Re: How to add subshell support for ash



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]