How to add subshell support for ash

Alexander Kriegisch kriegaex at freetz.org
Sun Mar 4 14:19:52 UTC 2012


Okay guys, I guess I have a working integration for ash subshell support
(tested with BusyBox ash/sh on mipsel) now. I am offering it to you
developers for inspection and adaption, so it may soon become a part of
the mainstream MC code base. I am aware of a few shortcomings and have
mentioned them as TODO items in code comments.

The first file 040-ash_as_subshell.patch contains the functional part of
the patch, while 040-ash_as_subshell_additional.patch contains some
minor additions to documentation and test code which are not necessary
to run mc + ash. Feel free and encouraged to criticise and improve the
code - as I said, I am not a C programmer and rather got my results by
continuous testing with strace as a debugging tool because I do not know
how to handle gdb.

What I have so far:

  - Ash mode will be used if the login shell is /bin/sh (on my
    platform it is safe to assume this, for general use this needs to
    be adapted to really recognise if /bin/sh is an ash or dash. I know
    how to do this via shell script, but not cleanly via C, sorry.

  - Ash as a subshell currently displays a fixed PS1 prompt like
    "user at host:/my/path/$ " ("user at host:/my/path/# " for root). It
    should be easy enough to change this, it just served my purpose
    like this. It is just a detail.

  - Chdir via subshell "cd" and via MC panel works as expected.

  - Analogous to Bash, it is possible to use an init file
    ~/.local/share/mc/ashrc (with auto-fallback to ~/.profile). This is
    not even implemented upstream for Zsh and Tcsh at the moment.

  - Plese refer to code comments for how and why I implemented the
    precmd via PS1 with two-fold indirection. This was necessary to
    enable the start of a sub-subshell (user command "ash" from
    subshell) without the sub-shell freezing (kill -STOP) or throwing
    an error. This is the trickiest part and I am somewhat proud I got
    it resolved with my rudimentary knowledge because it was a pain in
    the a**. Maybe there is a much simpler way.

  - I added some minimal documentation for Ash subshell mode to the
    help file, but only in English (needs translation), also extending
    Bash mode by mentioning ~/.bashrc (upstream just mentions
    ~/.local/share/mc/ashrc).

Remark: In order to get ENV into the environment for the init file, I
had to uncomment "g_free (putenv_str)". Initially I had used g_free
because Bash mode also uses it for INPUTRC. I wonder if the g_free also
needs to be removed in that case. Some MC professional might want to
check this.

I hope you are interested in this feature even though until now nobody
has answered my earlier inquiries. I want to thank Harald (ralda) from
the BusyxBox list though for sharing his thoughts and insights with me.
e.g. he gave me the important hint with (not to use) g_free.

Kind regards
--
Alexander Kriegisch


Alexander Kriegisch, 03.03.2012 18:39:
> Never mind, I am one step further:
> 
>>     case ASH:
>>         /* ash does not support precmd, we need to read cwd from the prompt */
>>         g_snprintf (precmd, sizeof (precmd),
>>                     "PS1='$(pwd>&%d; kill -STOP $$)\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]);
>>         break;
> 
> This works for BusyBox ash (tested on mipsel platform). The command will
> be contained in the shell editing history, but for me this is acceptable.
> 
> The next thing I want to do is set ENV so as to enable loading my shell
> profile without having to use a login shell. This would be the
> equivalent to Bash's "-rcfile" parameter. I did this:
> 
>>     case ASH:
>>         /* Do we have a custom init file ~/.local/share/mc/ashrc? */
>>         init_file = mc_config_get_full_path ("ashrc");
>>
>>         /* Otherwise use ~/.profile */
>>         if (access (init_file, R_OK) == -1)
>>         {
>>             g_free (init_file);
>>             init_file = g_strdup (".profile");
>>         }
>>
>>         /* Put init file to ENV variable used by ash */
>>         char *putenv_str = g_strconcat ("ENV=", init_file, NULL);
>>         putenv (putenv_str);
>>         g_free (putenv_str);
>>
>>         break;
> 
> And later this:
> 
>>     /* TODO for upstream patch: Execute correct ash/dash/busybox shell (not necessary for Freetz) */
>>     case ASH:
>>         execl (shell, "sh", (char *) NULL);
>>         break;
> 
> The problem is that ENV seems to be unset in my subshell's environment,
> i.e. that ~ /.profile (whiche exists) is not evaluated. Do I need to
> somehow export the ENV variable to make it available to the subshell?
> BTW, I am compiling against uClibc 0.9.29, if this is relevant.
> 
> 
> Alexander Kriegisch, 03.03.2012 14:41:
>> I am on an embedded environment. Bash is available as a separate 
>> package, but huge in comparison with the built-in ash of BusyBox.
>>
>> Disclaimer before I continue: I am *not* a C programmer. I can read
>> a bit of C, but not develop anything meaningful other than copy,
>> paste and modify existing code. So bear with me anyway, if you
>> please.
>>
>> I looked into src/subshell.c and tried to figure out what happens
>> there. I have started to add ash support, but MC seems to depend on 
>> PROMPT_COMMAND/precmd/fish_prompt, i.e. on a function or alias which
>> is executed each time just before a prompt is printed. Ash does not
>> have anything like that, AFAIK. If I understand correctly, using
>> those pre-commands are MC's way of determining the cwd. I wonder why
>> you do not just use something like pwd or $PWD, but OTOH I do not
>> understand the difficulties of corresponding with the subshell.
>>
>> Anyway, in my case it would be absolutely fine to set a fixed value
>> of PS1='\w\$ ' for the subshell and read the cwd from the prompt. In
>> any case it would be better than not having the option of using ash
>> as a subshell at all.
>>
>> Could anyone maybe provide me with a code snippet or a patch which
>> shows me how to extract the cwd from the prompt assuming that PS1 has
>> the value '\w\$ '? (BTW, '\$' will be evaluated to '$' or '#' in
>> ash, depending on whether you are root or not.)
>>
>> Thank you so much. If I succeed in adding ash as a subshell, I will 
>> provide a (raw) patch for you to inspect and maybe refine and
>> include upstream.
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 040-ash_as_subshell.patch
URL: <http://lists.midnight-commander.org/pipermail/mc-devel/attachments/20120304/e7d6fef0/attachment.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: 040-ash_as_subshell_additional.patch
URL: <http://lists.midnight-commander.org/pipermail/mc-devel/attachments/20120304/e7d6fef0/attachment-0001.ksh>


More information about the mc-devel mailing list