Re: How to add subshell support for ash
- From: Alexander Kriegisch <kriegaex freetz org>
- To: mc-devel gnome org
- Subject: Re: How to add subshell support for ash
- Date: Mon, 05 Mar 2012 14:27:51 +0100
Update: I have factored out the INPUTRC fix (including two source code
comments for the bash case) into a separate 030-bash_inputrc.patch so as
to separate it from the ash patches and enable you to easily fix the
upstream code issue separately.
Alexander Kriegisch, 05.03.2012 14:25:
> Oswald Buddenhagen, 05.03.2012 09:27:
>> On Sun, Mar 04, 2012 at 03:19:52PM +0100, Alexander Kriegisch wrote:
>>> I know how to do this via shell script, but not cleanly via C, sorry.
>>>
>> you could start by posting the sh code as text or a comment ...
>
> I do not really know what the point would be to produce something which
> would never be used, but I am thinking about it and might post an update
> later.
>
>>> - Plese refer to code comments for how and why I implemented the
>>> precmd via PS1 with two-fold indirection.
>>>
>> as ash is as close to pure posix as it gets, this pretty much qualifies
>> as a generic solution. one could even remove the paths for the other
>> bourne-compatible shells (except that they are less hacky) ...
>
> I am providing my code as-is, so as I said, every core MC developer or
> maintainer is welcome to optimise and streamline my patch as well as the
> upstream code base. So if my PS1 precmd trick works for other shells,
> too, feel free to use it there, too. Maybe if I have time available I
> can test that, but my main concern still is ash.
>
>>> Remark: In order to get ENV into the environment for the init file, I
>>> had to uncomment "g_free (putenv_str)".
>>>
>> that sounds like adding a memory leak. you need to move, not remove the
>> free. but then, i don't know that code, maybe there is already a second
>> cleanup path.
>
> I took the chance to just test the INPUTRC case and found out that as I
> suspected, it actually does *not* work because the variable is g_free'd
> before the subshell is called. The effect is that even though I created
> a test file ~/.local/share/mc/inputrc, it was not used by bash and
> INPUTRC was undefined in the subshell.
>
> So I updated my patch: putenv_str is now created before the first switch
> statement and g_free(putenv_str) is called at the same place as
> g_free(init_file). No matter whether my ash subshell patch is accepted
> into the code base or not, the INPUTRC case needs to be fixed upstream.
> Probably it never worked unless the g_free'd memory area was not
> overwritten yet by the time it was used by the bash subshell. After my
> fix, INPUTRC is available and used by the bash subshell. I have tested
> it on my mipsel target platform.
>
>>> + // A: This leads to a stopped subshell (=frozen mc) if user calls "sh" command
>>>
>> please fix the indentation and avoid c99/c++ comments.
>
> I must say, I am rather happy that indentation and commenting style is
> your major concern about my code and not anything functional. My updated
> patch does not use c99 style comments anymore. The second patch file
> remains unchanged because I did not add any comments there. As for
> indentation, I did not find anything wrong there. I am using four spaces
> instead of tabs just like you MC developers, even though I find that
> rather strange. The indentation level is in line with the rest of the
> switch-case statement, even though I personally do not indent that way,
> but indentation is largely a matter of taste anyway and I am merely
> trying to adapt to the style I found in your code base.
>
>
>
>
> _______________________________________________
> mc-devel mailing list
> http://mail.gnome.org/mailman/listinfo/mc-devel
--- src/subshell.c 2012-03-02 13:55:52.018954847 +0100
+++ src/subshell.c 2012-03-05 13:59:36.697459979 +0100
@@ -266,11 +266,14 @@
putenv (g_strdup (sid_str));
}
+ char *putenv_str = NULL;
switch (subshell_type)
{
case BASH:
+ /* Do we have a custom init file ~/.local/share/mc/bashrc? */
init_file = mc_config_get_full_path ("bashrc");
+ /* Otherwise use ~/.bashrc */
if (access (init_file, R_OK) == -1)
{
g_free (init_file);
@@ -285,9 +288,9 @@
char *input_file = mc_config_get_full_path ("inputrc");
if (access (input_file, R_OK) == 0)
{
- char *putenv_str = g_strconcat ("INPUTRC=", input_file, NULL);
+ putenv_str = g_strconcat ("INPUTRC=", input_file, NULL);
putenv (putenv_str);
- g_free (putenv_str);
+ /* Do not use "g_free (putenv_str)" here, otherwise INPUTRC will be undefined! */
}
g_free (input_file);
}
@@ -350,6 +353,7 @@
/* If we get this far, everything failed miserably */
g_free (init_file);
+ g_free (putenv_str);
_exit (FORK_FAILURE);
}
--- src/subshell.c 2012-03-05 13:59:36.697459979 +0100
+++ src/subshell.c 2012-03-05 13:53:10.765462536 +0100
@@ -126,6 +126,7 @@
static enum
{
BASH,
+ ASH,
TCSH,
ZSH,
FISH
@@ -297,6 +298,24 @@
break;
+ 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 */
+ putenv_str = g_strconcat ("ENV=", init_file, NULL);
+ putenv (putenv_str);
+ /* Do not use "g_free (putenv_str)" here, otherwise ENV will be undefined! */
+
+ break;
+
/* TODO: Find a way to pass initfile to TCSH and ZSH */
case TCSH:
case ZSH:
@@ -335,6 +354,11 @@
execl (shell, "bash", "-rcfile", init_file, (char *) NULL);
break;
+ /* TODO for upstream patch: Execute correct ash/dash/busybox shell (not necessary for Freetz) */
+ case ASH:
+ execl (shell, "ash", (char *) NULL);
+ break;
+
case TCSH:
execl (shell, "tcsh", (char *) NULL);
break;
@@ -800,6 +824,9 @@
subshell_type = BASH;
else if (strstr (shell, "/fish"))
subshell_type = FISH;
+ /* TODO for upstream patch: Check if "sh" really points to ash/dash/busybox (not necessary for Freetz) */
+ else if (strstr (shell, "/ash") || strstr (shell, "/dash") || strstr (shell, "/sh"))
+ subshell_type = ASH;
else
{
mc_global.tty.use_subshell = FALSE;
@@ -850,7 +877,7 @@
return;
}
}
- else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe))
+ else /* subshell_type is BASH, ASH or ZSH */ if (pipe (subshell_pipe))
{
perror (__FILE__ ": couldn't create pipe");
mc_global.tty.use_subshell = FALSE;
@@ -887,6 +914,25 @@
" PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n", subshell_pipe[WRITE]);
break;
+ case ASH:
+ /* Ash needs a somewhat complicated precmd emulation via PS1.
+ BUF_SMALL (defined in lib/global.h) is the length limit for precmd. */
+ g_snprintf (precmd, sizeof (precmd),
+
+ /* A: This leads to a stopped subshell (=frozen mc) if user calls "ash" command
+ * "PS1='$(pwd>&%d; kill -STOP $$)\\\\u@\\\\h:\\\\w\\\\$ '\n",
+ *
+ * B: This leads to "sh: precmd: not found" in sub-subshell if user calls "ash" command
+ * "precmd(){ pwd>&%d;kill -STOP $$; }; PS1='$(precmd)\\\\u@\\\\h:\\\\w\\\\$ '\n",
+ *
+ * C: This works if user calls "ash" command because in sub-subshell
+ * PRECMD is unfedined, thus evaluated to empty string - no damage done
+ */
+ "precmd(){ pwd>&%d;kill -STOP $$; }; PRECMD=precmd; PS1='$(eval $PRECMD)\\\\u@\\\\h:\\\\w\\\\$ '\n",
+
+ subshell_pipe[WRITE]);
+ break;
+
case ZSH:
g_snprintf (precmd, sizeof (precmd),
" precmd(){ pwd>&%d;kill -STOP $$ }\n", subshell_pipe[WRITE]);
@@ -1107,6 +1153,13 @@
quote_cmd_start = "(printf \"%b\" '";
quote_cmd_end = "')";
}
+ /* TODO: When BusyBox printf is fixed, get rid of this "else if", see
+ http://lists.busybox.net/pipermail/busybox/2012-March/077460.html */
+ else if (subshell_type == ASH)
+ {
+ quote_cmd_start = "\"`echo -en '";
+ quote_cmd_end = "'`\"";
+ }
else
{
quote_cmd_start = "\"`printf \"%b\" '";
--- lib/mcconfig/paths.c 2012-03-04 04:28:07.000000000 +0100
+++ lib/mcconfig/paths.c 2012-03-04 04:28:43.000000000 +0100
@@ -82,6 +82,7 @@
/* data */
{ "skins", &mc_data_str, MC_SKINS_SUBDIR},
{ "fish", &mc_data_str, FISH_PREFIX},
+ { "ashrc", &mc_data_str, "ashrc"},
{ "bashrc", &mc_data_str, "bashrc"},
{ "inputrc", &mc_data_str, "inputrc"},
{ "extfs.d", &mc_data_str, MC_EXTFS_DIR},
--- tests/lib/mcconfig/user_configs_path.c 2012-03-04 04:27:47.000000000 +0100
+++ tests/lib/mcconfig/user_configs_path.c 2012-03-04 05:33:48.418447747 +0100
@@ -96,6 +96,7 @@
path_fail_unless (CONF_DATA, MC_SKINS_SUBDIR);
path_fail_unless (CONF_DATA, FISH_PREFIX);
+ path_fail_unless (CONF_DATA, "ashrc");
path_fail_unless (CONF_DATA, "bashrc");
path_fail_unless (CONF_DATA, "inputrc");
path_fail_unless (CONF_DATA, MC_EXTFS_DIR);
--- doc/man/mc.1.in 2012-03-04 05:18:35.970419532 +0100
+++ doc/man/mc.1.in 2012-03-04 05:35:58.262451703 +0100
@@ -2408,7 +2408,7 @@
.\"NODE " The subshell support"
.SH " The subshell support"
The subshell support is a compile time option, that works with the
-shells: bash, tcsh and zsh.
+shells: bash, ash, tcsh and zsh.
.PP
When the subshell code is activated the Midnight Commander will
spawn a concurrent copy of your shell (the one defined in the
@@ -2423,8 +2423,10 @@
If you are using
.B bash
you can specify startup
-commands for the subshell in your ~/.local/share/mc/bashrc file and
+commands for the subshell in your ~/.local/share/mc/bashrc file (fallback ~/.bashrc) and
special keyboard maps in the ~/.local/share/mc/inputrc file.
+.B ash
+users may specify startup commands in ~/.local/share/mc/ashrc (fallback ~/.profile).
.B tcsh
users may specify startup commands in the ~/.local/share/mc/tcshrc file.
.PP
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]