From 1d797c29b01a918d151bebc3d5cfb7adc373afb8 Mon Sep 17 00:00:00 2001 From: Dirk Brenken Date: Wed, 25 Nov 2015 20:15:36 +0100 Subject: [PATCH] mc: add ash subshell support * backport a slightly modified subshell patch to stable 4.8.15 (see ticket: https://www.midnight-commander.org/ticket/2742) * enable subshell support by default Signed-off-by: Dirk Brenken --- utils/mc/Config.in | 4 +- utils/mc/Makefile | 2 +- utils/mc/patches/010-subshell.patch | 579 ++++++++++++++++++++++++++++ 3 files changed, 582 insertions(+), 3 deletions(-) create mode 100644 utils/mc/patches/010-subshell.patch diff --git a/utils/mc/Config.in b/utils/mc/Config.in index 29e617df6..b2c57941b 100644 --- a/utils/mc/Config.in +++ b/utils/mc/Config.in @@ -17,10 +17,10 @@ config MC_EDITOR config MC_SUBSHELL bool "Enable concurrent subshell" - default n + default y help This option enables concurrent subshell support. - Disabled by default. + Enabled by default. config MC_LARGEFILE bool "Enable largefile support" diff --git a/utils/mc/Makefile b/utils/mc/Makefile index b929d9e1a..7c0b3dbef 100644 --- a/utils/mc/Makefile +++ b/utils/mc/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=mc PKG_VERSION:=4.8.15 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_MAINTAINER:=Dirk Brenken PKG_LICENSE:=GPL-3.0+ diff --git a/utils/mc/patches/010-subshell.patch b/utils/mc/patches/010-subshell.patch new file mode 100644 index 000000000..12067f1c9 --- /dev/null +++ b/utils/mc/patches/010-subshell.patch @@ -0,0 +1,579 @@ +--- a/lib/global.c ++++ b/lib/global.c +@@ -97,6 +97,7 @@ mc_global_t mc_global = { + #endif /* !ENABLE_SUBSHELL */ + + .shell = NULL, ++ .shell_realpath = NULL, + + .xterm_flag = FALSE, + .disable_x11 = FALSE, +--- a/lib/global.h ++++ b/lib/global.h +@@ -255,6 +255,7 @@ typedef struct + + /* The user's shell */ + char *shell; ++ char *shell_realpath; + + /* This flag is set by xterm detection routine in function main() */ + /* It is used by function view_other_cmd() */ +--- a/lib/mcconfig/paths.c ++++ b/lib/mcconfig/paths.c +@@ -84,6 +84,7 @@ static const struct + /* 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}, +--- a/src/main.c ++++ b/src/main.c +@@ -87,6 +87,9 @@ + /*** file scope variables ************************************************************************/ + + /*** file scope functions ************************************************************************/ ++ ++static char rp_shell[PATH_MAX]; ++ + /* --------------------------------------------------------------------------------------------- */ + + static void +@@ -118,6 +121,44 @@ check_codeset (void) + } + + /* --------------------------------------------------------------------------------------------- */ ++/** ++ * Get a system shell. ++ * ++ * @return newly allocated string with shell name ++ */ ++ ++static char * ++mc_get_system_shell (void) ++{ ++ char *sh_str; ++ /* 3rd choice: look for existing shells supported as MC subshells. */ ++ if (access ("/bin/bash", X_OK) == 0) ++ sh_str = g_strdup ("/bin/bash"); ++ else if (access ("/bin/ash", X_OK) == 0) ++ sh_str = g_strdup ("/bin/ash"); ++ else if (access ("/bin/dash", X_OK) == 0) ++ sh_str = g_strdup ("/bin/dash"); ++ else if (access ("/bin/busybox", X_OK) == 0) ++ sh_str = g_strdup ("/bin/busybox"); ++ else if (access ("/bin/zsh", X_OK) == 0) ++ sh_str = g_strdup ("/bin/zsh"); ++ else if (access ("/bin/tcsh", X_OK) == 0) ++ sh_str = g_strdup ("/bin/tcsh"); ++ /* No fish as fallback because it is so much different from other shells and ++ * in a way exotic (even though user-friendly by name) that we should not ++ * present it as a subshell without the user's explicit intention. We rather ++ * will not use a subshell but just a command line. ++ * else if (access("/bin/fish", X_OK) == 0) ++ * mc_global.tty.shell = g_strdup ("/bin/fish"); ++ */ ++ else ++ /* Fallback and last resort: system default shell */ ++ sh_str = g_strdup ("/bin/sh"); ++ ++ return sh_str; ++} ++ ++/* --------------------------------------------------------------------------------------------- */ + + /** POSIX version. The only version we support. */ + static void +@@ -126,9 +167,11 @@ OS_Setup (void) + const char *shell_env; + const char *datadir_env; + ++ + shell_env = getenv ("SHELL"); + if ((shell_env == NULL) || (shell_env[0] == '\0')) + { ++ /* 2nd choice: user login shell */ + struct passwd *pwd; + + pwd = getpwuid (geteuid ()); +@@ -136,13 +179,15 @@ OS_Setup (void) + mc_global.tty.shell = g_strdup (pwd->pw_shell); + } + else ++ /* 1st choice: SHELL environment variable */ + mc_global.tty.shell = g_strdup (shell_env); + + if ((mc_global.tty.shell == NULL) || (mc_global.tty.shell[0] == '\0')) + { + g_free (mc_global.tty.shell); +- mc_global.tty.shell = g_strdup ("/bin/sh"); ++ mc_global.tty.shell = mc_get_system_shell (); + } ++ mc_global.tty.shell_realpath = mc_realpath (mc_global.tty.shell, rp_shell); + + /* This is the directory, where MC was installed, on Unix this is DATADIR */ + /* and can be overriden by the MC_DATADIR environment variable */ +--- a/src/subshell.c ++++ b/src/subshell.c +@@ -114,6 +114,8 @@ enum + static enum + { + BASH, ++ ASH_BUSYBOX, /* BusyBox default shell (ash) */ ++ DASH, /* Debian variant of ash */ + TCSH, + ZSH, + FISH +@@ -209,6 +211,7 @@ static void + init_subshell_child (const char *pty_name) + { + char *init_file = NULL; ++ char *putenv_str = NULL; + pid_t mc_sid; + + (void) pty_name; +@@ -257,32 +260,53 @@ init_subshell_child (const char *pty_nam + 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); + init_file = g_strdup (".bashrc"); + } + +- /* Make MC's special commands not show up in bash's history */ +- putenv ((char *) "HISTCONTROL=ignorespace"); ++ /* Make MC's special commands not show up in bash's history and also suppress ++ * consecutive identical commands*/ ++ putenv ((char *) "HISTCONTROL=ignoreboth"); + + /* Allow alternative readline settings for MC */ + { + 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); + } + g_free (input_file); + } + + break; + +- /* TODO: Find a way to pass initfile to TCSH and ZSH */ ++ case ASH_BUSYBOX: ++ case DASH: ++ /* 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, ZSH and FISH */ + case TCSH: + case ZSH: + case FISH: +@@ -320,10 +344,6 @@ init_subshell_child (const char *pty_nam + execl (mc_global.tty.shell, "bash", "-rcfile", init_file, (char *) NULL); + break; + +- case TCSH: +- execl (mc_global.tty.shell, "tcsh", (char *) NULL); +- break; +- + case ZSH: + /* Use -g to exclude cmds beginning with space from history + * and -Z to use the line editor on non-interactive term */ +@@ -331,8 +351,11 @@ init_subshell_child (const char *pty_nam + + break; + ++ case ASH_BUSYBOX: ++ case DASH: ++ case TCSH: + case FISH: +- execl (mc_global.tty.shell, "fish", (char *) NULL); ++ execl (mc_global.tty.shell, mc_global.tty.shell, (char *) NULL); + break; + + default: +@@ -341,6 +364,7 @@ init_subshell_child (const char *pty_nam + + /* If we get this far, everything failed miserably */ + g_free (init_file); ++ g_free (putenv_str); + my_exit (FORK_FAILURE); + } + +@@ -742,6 +766,171 @@ pty_open_slave (const char *pty_name) + } + #endif /* !HAVE_GRANTPT */ + ++ ++/* --------------------------------------------------------------------------------------------- */ ++/** ++ * Get a subshell type and store in subshell_type variable ++ * ++ * @return TRUE if subtype was gotten, FALSE otherwise ++ */ ++ ++static gboolean ++init_subshell_type (void) ++{ ++ gboolean result = TRUE; ++ ++ /* Find out what type of shell we have. Also consider real paths (resolved symlinks) ++ * because e.g. csh might point to tcsh, ash to dash or busybox, sh to anything. */ ++ ++ if (strstr (mc_global.tty.shell, "/zsh") || strstr (mc_global.tty.shell_realpath, "/zsh") ++ || getenv ("ZSH_VERSION")) ++ /* Also detects ksh symlinked to zsh */ ++ subshell_type = ZSH; ++ else if (strstr (mc_global.tty.shell, "/tcsh") ++ || strstr (mc_global.tty.shell_realpath, "/tcsh")) ++ /* Also detects csh symlinked to tcsh */ ++ subshell_type = TCSH; ++ else if (strstr (mc_global.tty.shell, "/fish") ++ || strstr (mc_global.tty.shell_realpath, "/fish")) ++ subshell_type = FISH; ++ else if (strstr (mc_global.tty.shell, "/dash") ++ || strstr (mc_global.tty.shell_realpath, "/dash")) ++ /* Debian ash (also found if symlinked to by ash/sh) */ ++ subshell_type = DASH; ++ else if (strstr (mc_global.tty.shell_realpath, "/busybox")) ++ { ++ /* If shell is symlinked to busybox, assume it is an ash, even though theoretically ++ * it could also be a hush (a mini shell for non-MMU systems deactivated by default). ++ * For simplicity's sake we assume that busybox always contains an ash, not a hush. ++ * On embedded platforms or on server systems, /bin/sh often points to busybox. ++ * Sometimes even bash is symlinked to busybox (CONFIG_FEATURE_BASH_IS_ASH option), ++ * so we need to check busybox symlinks *before* checking for the name "bash" ++ * in order to avoid that case. */ ++ subshell_type = ASH_BUSYBOX; ++ } ++ else if (strstr (mc_global.tty.shell, "/bash") || getenv ("BASH")) ++ /* If bash is not symlinked to busybox, it is safe to assume it is a real bash */ ++ subshell_type = BASH; ++ else ++ { ++ mc_global.tty.use_subshell = FALSE; ++ result = FALSE; ++ } ++ return result; ++} ++ ++/* --------------------------------------------------------------------------------------------- */ ++/** ++ * Set up `precmd' or equivalent for reading the subshell's CWD. ++ * ++ * Attention! Never forget that these are *one-liners* even though the concatenated ++ * substrings contain line breaks and indentation for better understanding of the ++ * shell code. It is vital that each one-liner ends with a line feed character ("\n" ). ++ * ++ * @return initialized pre-command string ++ */ ++ ++static void ++init_subshell_precmd (char *precmd, size_t buff_size) ++{ ++ ++ switch (subshell_type) ++ { ++ case BASH: ++ g_snprintf (precmd, buff_size, ++ " PROMPT_COMMAND='pwd>&%d; kill -STOP $$';\n", subshell_pipe[WRITE]); ++ break; ++ ++ case ASH_BUSYBOX: ++ /* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital ++ * that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway. ++ * ++ * 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. ++ * Attention: BusyBox must be built with FEATURE_EDITING_FANCY_PROMPT to ++ * permit \u, \w, \h, \$ escape sequences. Unfortunately this cannot be guaranteed, ++ * especially on embedded systems where people try to save space, so let's use ++ * the dash version below. It should work on virtually all systems. ++ * "precmd() { pwd>&%d; kill -STOP $$; }; " ++ * "PRECMD=precmd; " ++ * "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n", ++ */ ++ case DASH: ++ /* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash, ++ * but does not support escape sequences for user, host and cwd in prompt. ++ * Attention! Make sure that the buffer for precmd is big enough. ++ * ++ * We want to have a fancy dynamic prompt with user@host:cwd just like in the BusyBox ++ * examples above, but because replacing the home directory part of the path by "~" is ++ * complicated, it bloats the precmd to a size > BUF_SMALL (128). ++ * ++ * The following example is a little less fancy (home directory not replaced) ++ * and shows the basic workings of our prompt for easier understanding: ++ * ++ * "precmd() { " ++ * "echo \"$USER@$(hostname -s):$PWD\"; " ++ * "pwd>&%d; " ++ * "kill -STOP $$; " ++ * "}; " ++ * "PRECMD=precmd; " ++ * "PS1='$($PRECMD)$ '\n", ++ */ ++ g_snprintf (precmd, buff_size, ++ "precmd() { " ++ "if [ ! \"${PWD##$HOME}\" ]; then " ++ "MC_PWD=\"~\"; " ++ "else " ++ "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; " ++ "fi; " ++ "echo \"$USER@openwrt:$MC_PWD\"; " ++ "pwd>&%d; " ++ "kill -STOP $$; " ++ "}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]); ++ break; ++ ++ case ZSH: ++ g_snprintf (precmd, buff_size, ++ " precmd() { pwd>&%d; kill -STOP $$; }; " ++ "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]); ++ break; ++ ++ case TCSH: ++ g_snprintf (precmd, buff_size, ++ "set echo_style=both; " ++ "set prompt='%%n@%%m:%%~%%# '; " ++ "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo); ++ break; ++ ++ case FISH: ++ /* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also ++ * use colours, which is what we will do. But first here is a simpler, uncoloured version: ++ * "function fish_prompt; " ++ * "echo (whoami)@(hostname -s):(pwd)\\$\\ ; " ++ * "echo \"$PWD\">&%d; " ++ * "kill -STOP %%self; " ++ * "end\n", ++ * ++ * TODO: fish prompt is shown when panel is hidden (Ctrl-O), but not when it is visible. ++ * Find out how to fix this. ++ */ ++ g_snprintf (precmd, buff_size, ++ "function fish_prompt; " ++ "echo (whoami)@(hostname -s):(set_color $fish_color_cwd)(pwd)(set_color normal)\\$\\ ; " ++ "echo \"$PWD\">&%d; " "kill -STOP %%self; " "end\n", subshell_pipe[WRITE]); ++ break; ++ ++ default: ++ break; ++ } ++} ++ + /* --------------------------------------------------------------------------------------------- */ + /*** public functions ****************************************************************************/ + /* --------------------------------------------------------------------------------------------- */ +@@ -761,6 +950,7 @@ init_subshell (void) + { + /* This must be remembered across calls to init_subshell() */ + static char pty_name[BUF_SMALL]; ++ /* Must be considerably longer than BUF_SMALL (128) to support fancy shell prompts */ + char precmd[BUF_MEDIUM]; + + switch (check_sid ()) +@@ -782,23 +972,8 @@ init_subshell (void) + + if (mc_global.tty.subshell_pty == 0) + { /* First time through */ +- /* Find out what type of shell we have */ +- +- if (strstr (mc_global.tty.shell, "/zsh") || getenv ("ZSH_VERSION")) +- subshell_type = ZSH; +- else if (strstr (mc_global.tty.shell, "/tcsh")) +- subshell_type = TCSH; +- else if (strstr (mc_global.tty.shell, "/csh")) +- subshell_type = TCSH; +- else if (strstr (mc_global.tty.shell, "/bash") || getenv ("BASH")) +- subshell_type = BASH; +- else if (strstr (mc_global.tty.shell, "/fish")) +- subshell_type = FISH; +- else +- { +- mc_global.tty.use_subshell = FALSE; ++ if (!init_subshell_type ()) + return; +- } + + /* Open a pty for talking to the subshell */ + +@@ -844,7 +1019,7 @@ init_subshell (void) + return; + } + } +- else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe)) ++ else if (pipe (subshell_pipe)) /* subshell_type is BASH, ASH_BUSYBOX, DASH or ZSH */ + { + perror (__FILE__ ": couldn't create pipe"); + mc_global.tty.use_subshell = FALSE; +@@ -872,39 +1047,116 @@ init_subshell (void) + init_subshell_child (pty_name); + } + +- /* Set up 'precmd' or equivalent for reading the subshell's CWD */ ++ init_subshell_precmd (precmd, BUF_MEDIUM); ++ ++ /* Set up `precmd' or equivalent for reading the subshell's CWD ++ * ++ * Attention! Never forget that these are *one-liners* even though the concatenated ++ * substrings contain line breaks and indentation for better understanding of the ++ * shell code. It is vital that each one-liner ends with a line feed character ("\n" ). ++ */ + + switch (subshell_type) + { + case BASH: + g_snprintf (precmd, sizeof (precmd), +- " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n", +- subshell_pipe[WRITE]); ++ " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n" ++ "PS1='\\u@\\h:\\w\\$ '\n", subshell_pipe[WRITE]); ++ break; ++ ++ case ASH_BUSYBOX: ++ /* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital ++ * that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway. ++ * ++ * 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. ++ * Attention: BusyBox must be built with FEATURE_EDITING_FANCY_PROMPT to ++ * permit \u, \w, \h, \$ escape sequences. Unfortunately this cannot be guaranteed, ++ * especially on embedded systems where people try to save space, so let's use ++ * the dash version below. It should work on virtually all systems. ++ * "precmd() { pwd>&%d; kill -STOP $$; }; " ++ * "PRECMD=precmd; " ++ * "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n", ++ */ ++ case DASH: ++ /* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash, ++ * but does not support escape sequences for user, host and cwd in prompt. ++ * Attention! Make sure that the buffer for precmd is big enough. ++ * ++ * We want to have a fancy dynamic prompt with user@host:cwd just like in the BusyBox ++ * examples above, but because replacing the home directory part of the path by "~" is ++ * complicated, it bloats the precmd to a size > BUF_SMALL (128). ++ * ++ * The following example is a little less fancy (home directory not replaced) ++ * and shows the basic workings of our prompt for easier understanding: ++ * ++ * "precmd() { " ++ * "echo \"$USER@$(hostname -s):$PWD\"; " ++ * "pwd>&%d; " ++ * "kill -STOP $$; " ++ * "}; " ++ * "PRECMD=precmd; " ++ * "PS1='$($PRECMD)$ '\n", ++ */ ++ g_snprintf (precmd, sizeof (precmd), ++ "precmd() { " ++ "if [ ! \"${PWD##$HOME}\" ]; then " ++ "MC_PWD=\"~\"; " ++ "else " ++ "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; " ++ "fi; " ++ "echo \"$USER@openwrt:$MC_PWD\"; " ++ "pwd>&%d; " ++ "kill -STOP $$; " ++ "}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]); + break; + + case ZSH: + g_snprintf (precmd, sizeof (precmd), +- " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n", +- subshell_pipe[WRITE]); ++ " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n" ++ "PS1='%%n@%%m:%%~%%# '\n", subshell_pipe[WRITE]); + break; + + case TCSH: + g_snprintf (precmd, sizeof (precmd), +- "set echo_style=both;" +- "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n", tcsh_fifo); ++ "set echo_style=both; " ++ "set prompt='%%n@%%m:%%~%%# '; " ++ "alias precmd 'echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo); + break; ++ + case FISH: + /* Use fish_prompt_mc function for prompt, if not present then copy fish_prompt to it. */ ++ /* We also want a fancy user@host:cwd prompt here, but fish makes it very easy to also ++ * use colours, which is what we will do. But first here is a simpler, uncoloured version: ++ * "function fish_prompt; " ++ * "echo (whoami)@(hostname -s):(pwd)\\$\\ ; " ++ * "echo \"$PWD\">&%d; " ++ * "kill -STOP %%self; " ++ * "end\n", ++ * ++ * TODO: fish prompt is shown when panel is hidden (Ctrl-O), but not when it is visible. ++ * Find out how to fix this. ++ */ + g_snprintf (precmd, sizeof (precmd), + "if not functions -q fish_prompt_mc;" + "functions -c fish_prompt fish_prompt_mc; end;" +- "function fish_prompt; echo $PWD>&%d; fish_prompt_mc; kill -STOP %%self; end\n", ++ "function fish_prompt;" ++ "echo (whoami)@(hostname -s):(set_color $fish_color_cwd)(pwd)(set_color normal)\\$\\ ; " ++ "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n", + subshell_pipe[WRITE]); + break; + + default: + break; + } ++ + write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd)); + + /* Wait until the subshell has started up and processed the command */ +@@ -1108,6 +1360,13 @@ subshell_name_quote (const char *s) + 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_BUSYBOX) ++ { ++ quote_cmd_start = "\"`echo -en '"; ++ quote_cmd_end = "'`\""; ++ } */ + else + { + quote_cmd_start = "\"`printf \"%b\" '";