root/src/subshell/common.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. write_all
  2. init_subshell_child
  3. init_raw_mode
  4. synchronize
  5. read_command_line_buffer
  6. clear_subshell_prompt_string
  7. parse_subshell_prompt_string
  8. set_prompt_string
  9. feed_subshell
  10. pty_open_master
  11. pty_open_slave
  12. pty_open_master
  13. pty_open_slave
  14. init_subshell_precmd
  15. subshell_name_quote
  16. init_subshell
  17. invoke_subshell
  18. flush_subshell
  19. read_subshell_prompt
  20. do_update_prompt
  21. exit_subshell
  22. do_subshell_chdir
  23. subshell_get_console_attributes
  24. sigchld_handler

   1 /*
   2    Concurrent shell support for the Midnight Commander
   3 
   4    Copyright (C) 1994-2020
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Alexander Kriegisch <Alexander@Kriegisch.name>
   9    Aliaksey Kandratsenka <alk@tut.by>
  10    Andreas Mohr <and@gmx.li>
  11    Andrew Borodin <aborodin@vmail.ru>
  12    Andrew V. Samoilov <sav@bcs.zp.ua>
  13    Chris Owen <chris@candu.co.uk>
  14    Claes Nästén <me@pekdon.net>
  15    Egmont Koblinger <egmont@gmail.com>
  16    Enrico Weigelt, metux IT service <weigelt@metux.de>
  17    Eric Roberts <ericmrobertsdeveloper@gmail.com>
  18    Igor Urazov <z0rc3r@gmail.com>
  19    Ilia Maslakov <il.smind@gmail.com>
  20    Leonard den Ottolander <leonard@den.ottolander.nl>
  21    Miguel de Icaza <miguel@novell.com>
  22    Mikhail S. Pobolovets <styx.mp@gmail.com>
  23    Norbert Warmuth <nwarmuth@privat.circular.de>
  24    Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
  25    Patrick Winnertz <winnie@debian.org>
  26    Pavel Machek <pavel@suse.cz>
  27    Pavel Roskin <proski@gnu.org>
  28    Pavel Tsekov <ptsekov@gmx.net>
  29    Roland Illig <roland.illig@gmx.de>
  30    Sergei Trofimovich <slyfox@inbox.ru>
  31    Slava Zanko <slavazanko@gmail.com>
  32    Timur Bakeyev <mc@bat.ru>
  33    Vit Rosin <vit_r@list.ru>
  34 
  35    This file is part of the Midnight Commander.
  36 
  37    The Midnight Commander is free software: you can redistribute it
  38    and/or modify it under the terms of the GNU General Public License as
  39    published by the Free Software Foundation, either version 3 of the License,
  40    or (at your option) any later version.
  41 
  42    The Midnight Commander is distributed in the hope that it will be useful,
  43    but WITHOUT ANY WARRANTY; without even the implied warranty of
  44    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  45    GNU General Public License for more details.
  46 
  47    You should have received a copy of the GNU General Public License
  48    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  49  */
  50 
  51 /** \file subshell.c
  52  *  \brief Source: concurrent shell support
  53  */
  54 
  55 #include <config.h>
  56 
  57 #ifndef _GNU_SOURCE
  58 #define _GNU_SOURCE 1
  59 #endif
  60 
  61 #include <ctype.h>
  62 #include <stdio.h>
  63 #include <stdlib.h>
  64 #include <errno.h>
  65 #include <string.h>
  66 #include <signal.h>
  67 #ifdef HAVE_SYS_SELECT_H
  68 #include <sys/select.h>
  69 #else
  70 #include <sys/time.h>
  71 #include <unistd.h>
  72 #endif
  73 #include <sys/types.h>
  74 #include <sys/wait.h>
  75 #ifdef HAVE_SYS_IOCTL_H
  76 #include <sys/ioctl.h>
  77 #endif
  78 #include <termios.h>
  79 
  80 #ifdef HAVE_STROPTS_H
  81 #include <stropts.h>            /* For I_PUSH */
  82 #endif /* HAVE_STROPTS_H */
  83 
  84 #ifdef HAVE_OPENPTY
  85 /* includes for openpty() */
  86 #ifdef HAVE_PTY_H
  87 #include <pty.h>
  88 #endif
  89 #ifdef HAVE_UTIL_H
  90 #include <util.h>
  91 #endif
  92 /* <sys/types.h> is a prerequisite of <libutil.h> on FreeBSD 8.0.  */
  93 #ifdef HAVE_LIBUTIL_H
  94 #include <libutil.h>
  95 #endif
  96 #endif /* HAVE_OPENPTY */
  97 
  98 #include "lib/global.h"
  99 
 100 #include "lib/unixcompat.h"
 101 #include "lib/tty/tty.h"        /* LINES */
 102 #include "lib/tty/key.h"        /* XCTRL */
 103 #include "lib/vfs/vfs.h"
 104 #include "lib/strutil.h"
 105 #include "lib/mcconfig.h"
 106 #include "lib/util.h"
 107 #include "lib/widget.h"
 108 
 109 #include "src/filemanager/layout.h"     /* setup_cmdline() */
 110 #include "src/filemanager/command.h"    /* cmdline */
 111 
 112 #include "subshell.h"
 113 #include "internal.h"
 114 
 115 /*** global variables ****************************************************************************/
 116 
 117 /* State of the subshell:
 118  * INACTIVE: the default state; awaiting a command
 119  * ACTIVE: remain in the shell until the user hits 'subshell_switch_key'
 120  * RUNNING_COMMAND: return to MC when the current command finishes */
 121 enum subshell_state_enum subshell_state;
 122 
 123 /* Holds the latest prompt captured from the subshell */
 124 GString *subshell_prompt = NULL;
 125 
 126 /* Subshell: if set, then the prompt was not saved on CONSOLE_SAVE */
 127 /* We need to paint it after CONSOLE_RESTORE, see: load_prompt */
 128 gboolean update_subshell_prompt = FALSE;
 129 
 130 /* If set, then a command has just finished executing, and we need */
 131 /* to be on the lookout for a new prompt string from the subshell. */
 132 gboolean should_read_new_subshell_prompt;
 133 
 134 /*** file scope macro definitions ****************************************************************/
 135 
 136 #ifndef WEXITSTATUS
 137 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
 138 #endif
 139 
 140 #ifndef WIFEXITED
 141 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
 142 #endif
 143 
 144 /* Initial length of the buffer for the subshell's prompt */
 145 #define INITIAL_PROMPT_SIZE 10
 146 
 147 /* Used by the child process to indicate failure to start the subshell */
 148 #define FORK_FAILURE 69         /* Arbitrary */
 149 
 150 /* Length of the buffer for all I/O with the subshell */
 151 #define PTY_BUFFER_SIZE BUF_SMALL       /* Arbitrary; but keep it >= 80 */
 152 
 153 /*** file scope type declarations ****************************************************************/
 154 
 155 /* For pipes */
 156 enum
 157 {
 158     READ = 0,
 159     WRITE = 1
 160 };
 161 
 162 /* This is the keybinding that is sent to the shell, to make the shell send us the contents of
 163  * the current command buffer. */
 164 #define SHELL_BUFFER_KEYBINDING "_"
 165 
 166 /* This is the keybinding that is sent to the shell, to make the shell send us the location of
 167  * the cursor. */
 168 #define SHELL_CURSOR_KEYBINDING "+"
 169 
 170 /*** file scope variables ************************************************************************/
 171 
 172 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
 173 static char tcsh_fifo[128];
 174 
 175 static int subshell_pty_slave = -1;
 176 
 177 /* The key for switching back to MC from the subshell */
 178 /* *INDENT-OFF* */
 179 static const char subshell_switch_key = XCTRL ('o') & 255;
 180 /* *INDENT-ON* */
 181 
 182 /* For reading/writing on the subshell's pty */
 183 static char pty_buffer[PTY_BUFFER_SIZE] = "\0";
 184 
 185 /* To pass CWD info from the subshell to MC */
 186 static int subshell_pipe[2];
 187 
 188 /* To pass command buffer info from the subshell to MC */
 189 static int command_buffer_pipe[2];
 190 
 191 /* The subshell's process ID */
 192 static pid_t subshell_pid = 1;
 193 
 194 /* One extra char for final '\n' */
 195 static char subshell_cwd[MC_MAXPATHLEN + 1];
 196 
 197 /* Flag to indicate whether the subshell is ready for next command */
 198 static int subshell_ready;
 199 
 200 /* Flag to indicate if the subshell supports the persistent buffer feature. */
 201 static gboolean use_persistent_buffer = FALSE;
 202 
 203 /* Flag to indicate if the contents of the subshell command line need to be cleared before */
 204 /* executing a command. This should only end up set to true if there is some sort of error. */
 205 /* This allows us to recover gracefully from an error. */
 206 static gboolean subshell_should_clear_command_line = FALSE;
 207 
 208 /* This is the local variable where the subshell prompt is stored while we are working on it. */
 209 static GString *subshell_prompt_temp_buffer = NULL;
 210 
 211 /* The following two flags can be changed by the SIGCHLD handler. This is */
 212 /* OK, because the 'int' type is updated atomically on all known machines */
 213 static volatile int subshell_alive, subshell_stopped;
 214 
 215 /* We store the terminal's initial mode here so that we can configure
 216    the pty similarly, and also so we can restore the real terminal to
 217    sanity if we have to exit abruptly */
 218 static struct termios shell_mode;
 219 
 220 /* This is a transparent mode for the terminal where MC is running on */
 221 /* It is used when the shell is active, so that the control signals */
 222 /* are delivered to the shell pty */
 223 static struct termios raw_mode;
 224 
 225 /* --------------------------------------------------------------------------------------------- */
 226 /*** file scope functions ************************************************************************/
 227 /* --------------------------------------------------------------------------------------------- */
 228 /**
 229  *  Write all data, even if the write() call is interrupted.
 230  */
 231 
 232 static ssize_t
 233 write_all (int fd, const void *buf, size_t count)
     /* [previous][next][first][last][top][bottom][index][help]  */
 234 {
 235     ssize_t written = 0;
 236 
 237     while (count > 0)
 238     {
 239         ssize_t ret;
 240 
 241         ret = write (fd, (const unsigned char *) buf + written, count);
 242         if (ret < 0)
 243         {
 244             if (errno == EINTR)
 245             {
 246                 if (tty_got_winch ())
 247                     tty_change_screen_size ();
 248 
 249                 continue;
 250             }
 251 
 252             return written > 0 ? written : ret;
 253         }
 254         count -= ret;
 255         written += ret;
 256     }
 257     return written;
 258 }
 259 
 260 /* --------------------------------------------------------------------------------------------- */
 261 /**
 262  *  Prepare child process to running the shell and run it.
 263  *
 264  *  Modifies the global variables (in the child process only):
 265  *      shell_mode
 266  *
 267  *  Returns: never.
 268  */
 269 
 270 static void
 271 init_subshell_child (const char *pty_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 272 {
 273     char *init_file = NULL;
 274     char *putenv_str = NULL;
 275     pid_t mc_sid;
 276 
 277     (void) pty_name;
 278     setsid ();                  /* Get a fresh terminal session */
 279 
 280     /* Make sure that it has become our controlling terminal */
 281 
 282     /* Redundant on Linux and probably most systems, but just in case: */
 283 
 284 #ifdef TIOCSCTTY
 285     ioctl (subshell_pty_slave, TIOCSCTTY, 0);
 286 #endif
 287 
 288     /* Configure its terminal modes and window size */
 289 
 290     /* Set up the pty with the same termios flags as our own tty */
 291     if (tcsetattr (subshell_pty_slave, TCSANOW, &shell_mode))
 292     {
 293         fprintf (stderr, "Cannot set pty terminal modes: %s\r\n", unix_error_string (errno));
 294         my_exit (FORK_FAILURE);
 295     }
 296 
 297     /* Set the pty's size (80x25 by default on Linux) according to the */
 298     /* size of the real terminal as calculated by ncurses, if possible */
 299     tty_resize (subshell_pty_slave);
 300 
 301     /* Set up the subshell's environment and init file name */
 302 
 303     /* It simplifies things to change to our home directory here, */
 304     /* and the user's startup file may do a 'cd' command anyway   */
 305     {
 306         int ret;
 307 
 308         ret = chdir (mc_config_get_home_dir ());        /* FIXME? What about when we re-run the subshell? */
 309         (void) ret;
 310     }
 311 
 312     /* Set MC_SID to prevent running one mc from another */
 313     mc_sid = getsid (0);
 314     if (mc_sid != -1)
 315     {
 316         char sid_str[BUF_SMALL];
 317 
 318         g_snprintf (sid_str, sizeof (sid_str), "MC_SID=%ld", (long) mc_sid);
 319         putenv (g_strdup (sid_str));
 320     }
 321 
 322     switch (mc_global.shell->type)
 323     {
 324     case SHELL_BASH:
 325         /* Do we have a custom init file ~/.local/share/mc/bashrc? */
 326         init_file = mc_config_get_full_path ("bashrc");
 327 
 328         /* Otherwise use ~/.bashrc */
 329         if (!exist_file (init_file))
 330         {
 331             g_free (init_file);
 332             init_file = g_strdup (".bashrc");
 333         }
 334 
 335         /* Make MC's special commands not show up in bash's history and also suppress
 336          * consecutive identical commands*/
 337         putenv ((char *) "HISTCONTROL=ignoreboth");
 338 
 339         /* Allow alternative readline settings for MC */
 340         {
 341             char *input_file;
 342 
 343             input_file = mc_config_get_full_path ("inputrc");
 344             if (exist_file (input_file))
 345             {
 346                 putenv_str = g_strconcat ("INPUTRC=", input_file, (char *) NULL);
 347                 putenv (putenv_str);
 348             }
 349             g_free (input_file);
 350         }
 351 
 352         break;
 353 
 354     case SHELL_ASH_BUSYBOX:
 355     case SHELL_DASH:
 356         /* Do we have a custom init file ~/.local/share/mc/ashrc? */
 357         init_file = mc_config_get_full_path ("ashrc");
 358 
 359         /* Otherwise use ~/.profile */
 360         if (!exist_file (init_file))
 361         {
 362             g_free (init_file);
 363             init_file = g_strdup (".profile");
 364         }
 365 
 366         /* Put init file to ENV variable used by ash */
 367         putenv_str = g_strconcat ("ENV=", init_file, (char *) NULL);
 368         putenv (putenv_str);
 369         /* Do not use "g_free (putenv_str)" here, otherwise ENV will be undefined! */
 370 
 371         break;
 372 
 373         /* TODO: Find a way to pass initfile to TCSH, ZSH and FISH */
 374     case SHELL_TCSH:
 375     case SHELL_ZSH:
 376     case SHELL_FISH:
 377         break;
 378 
 379     default:
 380         fprintf (stderr, __FILE__ ": unimplemented subshell type %u\r\n", mc_global.shell->type);
 381         my_exit (FORK_FAILURE);
 382     }
 383 
 384     /* Attach all our standard file descriptors to the pty */
 385 
 386     /* This is done just before the exec, because stderr must still      */
 387     /* be connected to the real tty during the above error messages; */
 388     /* otherwise the user will never see them.                   */
 389 
 390     dup2 (subshell_pty_slave, STDIN_FILENO);
 391     dup2 (subshell_pty_slave, STDOUT_FILENO);
 392     dup2 (subshell_pty_slave, STDERR_FILENO);
 393 
 394     close (subshell_pipe[READ]);
 395 
 396     if (use_persistent_buffer)
 397         close (command_buffer_pipe[READ]);
 398 
 399     close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */
 400     /* Close master side of pty.  This is important; apart from */
 401     /* freeing up the descriptor for use in the subshell, it also       */
 402     /* means that when MC exits, the subshell will get a SIGHUP and     */
 403     /* exit too, because there will be no more descriptors pointing     */
 404     /* at the master side of the pty and so it will disappear.  */
 405     close (mc_global.tty.subshell_pty);
 406 
 407     /* Execute the subshell at last */
 408 
 409     switch (mc_global.shell->type)
 410     {
 411     case SHELL_BASH:
 412         execl (mc_global.shell->path, "bash", "-rcfile", init_file, (char *) NULL);
 413         break;
 414 
 415     case SHELL_ZSH:
 416         /* Use -g to exclude cmds beginning with space from history
 417          * and -Z to use the line editor on non-interactive term */
 418         execl (mc_global.shell->path, "zsh", "-Z", "-g", (char *) NULL);
 419 
 420         break;
 421 
 422     case SHELL_ASH_BUSYBOX:
 423     case SHELL_DASH:
 424     case SHELL_TCSH:
 425     case SHELL_FISH:
 426         execl (mc_global.shell->path, mc_global.shell->path, (char *) NULL);
 427         break;
 428 
 429     default:
 430         break;
 431     }
 432 
 433     /* If we get this far, everything failed miserably */
 434     g_free (init_file);
 435     g_free (putenv_str);
 436     my_exit (FORK_FAILURE);
 437 }
 438 
 439 /* --------------------------------------------------------------------------------------------- */
 440 
 441 static void
 442 init_raw_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 443 {
 444     static gboolean initialized = FALSE;
 445 
 446     /* MC calls tty_reset_shell_mode() in pre_exec() to set the real tty to its */
 447     /* original settings.  However, here we need to make this tty very raw,     */
 448     /* so that all keyboard signals, XON/XOFF, etc. will get through to the     */
 449     /* pty.  So, instead of changing the code for execute(), pre_exec(),        */
 450     /* etc, we just set up the modes we need here, before each command.         */
 451 
 452     if (!initialized)           /* First time: initialise 'raw_mode' */
 453     {
 454         tcgetattr (STDOUT_FILENO, &raw_mode);
 455         raw_mode.c_lflag &= ~ICANON;    /* Disable line-editing chars, etc.   */
 456         raw_mode.c_lflag &= ~ISIG;      /* Disable intr, quit & suspend chars */
 457         raw_mode.c_lflag &= ~ECHO;      /* Disable input echoing              */
 458         raw_mode.c_iflag &= ~IXON;      /* Pass ^S/^Q to subshell undisturbed */
 459         raw_mode.c_iflag &= ~ICRNL;     /* Don't translate CRs into LFs       */
 460         raw_mode.c_oflag &= ~OPOST;     /* Don't postprocess output           */
 461         raw_mode.c_cc[VTIME] = 0;       /* IE: wait forever, and return as    */
 462         raw_mode.c_cc[VMIN] = 1;        /* soon as a character is available   */
 463         initialized = TRUE;
 464     }
 465 }
 466 
 467 /* --------------------------------------------------------------------------------------------- */
 468 /**
 469  * Wait until the subshell dies or stops.  If it stops, make it resume.
 470  * Possibly modifies the globals 'subshell_alive' and 'subshell_stopped'
 471  */
 472 
 473 static void
 474 synchronize (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 475 {
 476     sigset_t sigchld_mask, old_mask;
 477 
 478     sigemptyset (&sigchld_mask);
 479     sigaddset (&sigchld_mask, SIGCHLD);
 480     sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
 481 
 482     /*
 483      * SIGCHLD should not be blocked, but we unblock it just in case.
 484      * This is known to be useful for cygwin 1.3.12 and older.
 485      */
 486     sigdelset (&old_mask, SIGCHLD);
 487 
 488     /* Wait until the subshell has stopped */
 489     while (subshell_alive && !subshell_stopped)
 490         sigsuspend (&old_mask);
 491 
 492     if (subshell_state != ACTIVE)
 493     {
 494         /* Discard all remaining data from stdin to the subshell */
 495         tcflush (subshell_pty_slave, TCIFLUSH);
 496     }
 497 
 498     subshell_stopped = FALSE;
 499     kill (subshell_pid, SIGCONT);
 500 
 501     sigprocmask (SIG_SETMASK, &old_mask, NULL);
 502     /* We can't do any better without modifying the shell(s) */
 503 }
 504 
 505 /* --------------------------------------------------------------------------------------------- */
 506 /* Get the contents of the current subshell command line buffer, and */
 507 /* transfer the contents to the panel command prompt. */
 508 
 509 static gboolean
 510 read_command_line_buffer (gboolean test_mode)
     /* [previous][next][first][last][top][bottom][index][help]  */
 511 {
 512     char subshell_command_buffer[BUF_LARGE];
 513     char subshell_cursor_buffer[BUF_SMALL];
 514 
 515     fd_set read_set;
 516     int i;
 517     ssize_t bytes;
 518     struct timeval subshell_prompt_timer = { 0, 0 };
 519     int command_buffer_length;
 520     int command_buffer_char_length;
 521     int bash_version;
 522     int cursor_position;
 523     int maxfdp;
 524     int rc;
 525 
 526     if (!use_persistent_buffer)
 527         return TRUE;
 528 
 529     FD_ZERO (&read_set);
 530     FD_SET (command_buffer_pipe[READ], &read_set);
 531     maxfdp = command_buffer_pipe[READ];
 532 
 533     /* First, flush the command buffer pipe. This pipe shouldn't be written
 534      * to under normal circumstances, but if it somehow does get written
 535      * to, we need to make sure to discard whatever data is there before
 536      * we try to use it. */
 537     while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 0)
 538     {
 539         if (rc == -1)
 540         {
 541             if (errno == EINTR)
 542                 continue;
 543 
 544             return FALSE;
 545         }
 546 
 547         if (rc == 1)
 548         {
 549             bytes = read (command_buffer_pipe[READ], subshell_command_buffer,
 550                           sizeof (subshell_command_buffer));
 551             (void) bytes;
 552         }
 553     }
 554 
 555     /* get contents of command line buffer */
 556     write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING,
 557                sizeof (ESC_STR SHELL_CURSOR_KEYBINDING) - 1);
 558 
 559     subshell_prompt_timer.tv_sec = 1;
 560     FD_ZERO (&read_set);
 561     FD_SET (command_buffer_pipe[READ], &read_set);
 562 
 563     while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1)
 564     {
 565         if (rc == -1)
 566         {
 567             if (errno == EINTR)
 568                 continue;
 569 
 570             return FALSE;
 571         }
 572 
 573         if (rc == 0)
 574             return FALSE;
 575     }
 576 
 577     bytes =
 578         read (command_buffer_pipe[READ], subshell_command_buffer, sizeof (subshell_command_buffer));
 579     if (bytes == 0 || bytes == sizeof (subshell_command_buffer))
 580         return FALSE;
 581 
 582     command_buffer_char_length = bytes - 1;
 583     subshell_command_buffer[command_buffer_char_length] = '\0';
 584     command_buffer_length = str_length (subshell_command_buffer);
 585 
 586     /* get cursor position */
 587     write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING,
 588                sizeof (ESC_STR SHELL_CURSOR_KEYBINDING) - 1);
 589 
 590     subshell_prompt_timer.tv_sec = 1;
 591     subshell_prompt_timer.tv_usec = 0;
 592     FD_ZERO (&read_set);
 593     FD_SET (command_buffer_pipe[READ], &read_set);
 594 
 595     while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1)
 596     {
 597         if (rc == -1)
 598         {
 599             if (errno == EINTR)
 600                 continue;
 601 
 602             return FALSE;
 603         }
 604 
 605         if (rc == 0)
 606             return FALSE;
 607     }
 608 
 609     bytes =
 610         read (command_buffer_pipe[READ], subshell_cursor_buffer, sizeof (subshell_cursor_buffer));
 611     if (bytes == 0)
 612         return FALSE;
 613 
 614     subshell_cursor_buffer[bytes - 1] = '\0';
 615     if (mc_global.shell->type == SHELL_BASH)
 616     {
 617         if (sscanf (subshell_cursor_buffer, "%d:%d", &bash_version, &cursor_position) != 2)
 618             return FALSE;
 619     }
 620     else
 621     {
 622         if (sscanf (subshell_cursor_buffer, "%d", &cursor_position) != 1)
 623             return FALSE;
 624         bash_version = 1000;
 625     }
 626 
 627     if (test_mode)
 628         return TRUE;
 629 
 630     /* Substitute non-text characters in the command buffer, such as tab, or newline, as this
 631      * could cause problems. */
 632     for (i = 0; i < command_buffer_char_length; i++)
 633         if ((unsigned char) subshell_command_buffer[i] < 32
 634             || (unsigned char) subshell_command_buffer[i] == 127)
 635             subshell_command_buffer[i] = ' ';
 636 
 637     input_assign_text (cmdline, "");
 638     input_insert (cmdline, subshell_command_buffer, FALSE);
 639 
 640     if (bash_version < 5)       /* implies SHELL_BASH */
 641     {
 642         /* We need to do this because bash < v5 gives the cursor position in a utf-8 string based
 643          * on the location in bytes, not in unicode characters. */
 644         char *curr, *stop;
 645 
 646         curr = subshell_command_buffer;
 647         stop = curr + cursor_position;
 648 
 649         for (cursor_position = 0; curr < stop; cursor_position++)
 650             str_next_char_safe (&curr);
 651     }
 652     if (cursor_position > command_buffer_length)
 653         cursor_position = command_buffer_length;
 654     cmdline->point = cursor_position;
 655     /* We send any remaining data to STDOUT before we finish. */
 656     flush_subshell (0, VISIBLY);
 657 
 658     /* Now we erase the current contents of the command line buffer */
 659     if (mc_global.shell->type != SHELL_ZSH)
 660     {
 661         /* In zsh, we can just press c-u to clear the line, without needing to go to the end of
 662          * the line first first. In all other shells, we must go to the end of the line first. */
 663 
 664         /* If we are not at the end of the line, we go to the end. */
 665         if (cursor_position != command_buffer_length)
 666         {
 667             write_all (mc_global.tty.subshell_pty, "\005", 1);
 668             if (flush_subshell (1, VISIBLY) != 1)
 669                 return FALSE;
 670         }
 671     }
 672 
 673     if (command_buffer_length > 0)
 674     {
 675         /* Now we clear the line. */
 676         write_all (mc_global.tty.subshell_pty, "\025", 1);
 677         if (flush_subshell (1, VISIBLY) != 1)
 678             return FALSE;
 679     }
 680 
 681     return TRUE;
 682 }
 683 
 684 /* --------------------------------------------------------------------------------------------- */
 685 
 686 static void
 687 clear_subshell_prompt_string (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 688 {
 689     if (subshell_prompt_temp_buffer != NULL)
 690         g_string_set_size (subshell_prompt_temp_buffer, 0);
 691 }
 692 
 693 /* --------------------------------------------------------------------------------------------- */
 694 
 695 static void
 696 parse_subshell_prompt_string (const char *buffer, int bytes)
     /* [previous][next][first][last][top][bottom][index][help]  */
 697 {
 698     int i;
 699 
 700     if (mc_global.mc_run_mode != MC_RUN_FULL)
 701         return;
 702 
 703     /* First time through */
 704     if (subshell_prompt == NULL)
 705         subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE);
 706     if (subshell_prompt_temp_buffer == NULL)
 707         subshell_prompt_temp_buffer = g_string_sized_new (INITIAL_PROMPT_SIZE);
 708 
 709     /* Extract the prompt from the shell output */
 710     for (i = 0; i < bytes; i++)
 711         if (buffer[i] == '\n' || buffer[i] == '\r')
 712             g_string_set_size (subshell_prompt_temp_buffer, 0);
 713         else if (buffer[i] != '\0')
 714             g_string_append_c (subshell_prompt_temp_buffer, buffer[i]);
 715 }
 716 
 717 /* --------------------------------------------------------------------------------------------- */
 718 
 719 static void
 720 set_prompt_string (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 721 {
 722     if (mc_global.mc_run_mode != MC_RUN_FULL)
 723         return;
 724 
 725     if (subshell_prompt_temp_buffer->len != 0)
 726         g_string_assign (subshell_prompt, subshell_prompt_temp_buffer->str);
 727 
 728     setup_cmdline ();
 729 }
 730 
 731 /* --------------------------------------------------------------------------------------------- */
 732 /** Feed the subshell our keyboard input until it says it's finished */
 733 
 734 static gboolean
 735 feed_subshell (int how, gboolean fail_on_error)
     /* [previous][next][first][last][top][bottom][index][help]  */
 736 {
 737     fd_set read_set;            /* For 'select' */
 738     int bytes;                  /* For the return value from 'read' */
 739     int i;                      /* Loop counter */
 740 
 741     struct timeval wtime;       /* Maximum time we wait for the subshell */
 742     struct timeval *wptr;
 743 
 744     should_read_new_subshell_prompt = FALSE;
 745     subshell_should_clear_command_line = FALSE;
 746 
 747     /* we wait up to 10 seconds if fail_on_error, forever otherwise */
 748     wtime.tv_sec = 10;
 749     wtime.tv_usec = 0;
 750     wptr = fail_on_error ? &wtime : NULL;
 751 
 752     while (TRUE)
 753     {
 754         int maxfdp;
 755 
 756         if (!subshell_alive)
 757             return FALSE;
 758 
 759         /* Prepare the file-descriptor set and call 'select' */
 760 
 761         FD_ZERO (&read_set);
 762         FD_SET (mc_global.tty.subshell_pty, &read_set);
 763         FD_SET (subshell_pipe[READ], &read_set);
 764         maxfdp = MAX (mc_global.tty.subshell_pty, subshell_pipe[READ]);
 765         if (how == VISIBLY)
 766         {
 767             FD_SET (STDIN_FILENO, &read_set);
 768             maxfdp = MAX (maxfdp, STDIN_FILENO);
 769         }
 770 
 771         if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1)
 772         {
 773             /* Despite using SA_RESTART, we still have to check for this */
 774             if (errno == EINTR)
 775             {
 776                 if (tty_got_winch ())
 777                     tty_change_screen_size ();
 778 
 779                 continue;       /* try all over again */
 780             }
 781             tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
 782             fprintf (stderr, "select (FD_SETSIZE, &read_set...): %s\r\n",
 783                      unix_error_string (errno));
 784             exit (EXIT_FAILURE);
 785         }
 786 
 787         if (FD_ISSET (mc_global.tty.subshell_pty, &read_set))
 788             /* Read from the subshell, write to stdout */
 789 
 790             /* This loop improves performance by reducing context switches
 791                by a factor of 20 or so... unfortunately, it also hangs MC
 792                randomly, because of an apparent Linux bug.  Investigate. */
 793             /* for (i=0; i<5; ++i)  * FIXME -- experimental */
 794         {
 795             bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
 796 
 797             /* The subshell has died */
 798             if (bytes == -1 && errno == EIO && !subshell_alive)
 799                 return FALSE;
 800 
 801             if (bytes <= 0)
 802             {
 803 #ifdef PTY_ZEROREAD
 804                 /* On IBM i, read(1) can return 0 for a non-closed fd */
 805                 continue;
 806 #else
 807                 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
 808                 fprintf (stderr, "read (subshell_pty...): %s\r\n", unix_error_string (errno));
 809                 exit (EXIT_FAILURE);
 810 #endif
 811             }
 812 
 813             if (how == VISIBLY)
 814                 write_all (STDOUT_FILENO, pty_buffer, bytes);
 815 
 816             if (should_read_new_subshell_prompt)
 817                 parse_subshell_prompt_string (pty_buffer, bytes);
 818         }
 819 
 820         else if (FD_ISSET (subshell_pipe[READ], &read_set))
 821             /* Read the subshell's CWD and capture its prompt */
 822         {
 823             bytes = read (subshell_pipe[READ], subshell_cwd, sizeof (subshell_cwd));
 824             if (bytes <= 0)
 825             {
 826                 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
 827                 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n",
 828                          unix_error_string (errno));
 829                 exit (EXIT_FAILURE);
 830             }
 831 
 832             subshell_cwd[bytes - 1] = '\0';     /* Squash the final '\n' */
 833 
 834             synchronize ();
 835 
 836             clear_subshell_prompt_string ();
 837             should_read_new_subshell_prompt = TRUE;
 838             subshell_ready = TRUE;
 839             if (subshell_state == RUNNING_COMMAND)
 840             {
 841                 subshell_state = INACTIVE;
 842                 return TRUE;
 843             }
 844         }
 845 
 846         else if (FD_ISSET (STDIN_FILENO, &read_set))
 847             /* Read from stdin, write to the subshell */
 848         {
 849             should_read_new_subshell_prompt = FALSE;
 850             bytes = read (STDIN_FILENO, pty_buffer, sizeof (pty_buffer));
 851             if (bytes <= 0)
 852             {
 853                 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
 854                 fprintf (stderr,
 855                          "read (STDIN_FILENO, pty_buffer...): %s\r\n", unix_error_string (errno));
 856                 exit (EXIT_FAILURE);
 857             }
 858 
 859             for (i = 0; i < bytes; ++i)
 860                 if (pty_buffer[i] == subshell_switch_key)
 861                 {
 862                     write_all (mc_global.tty.subshell_pty, pty_buffer, i);
 863 
 864                     if (subshell_ready)
 865                     {
 866                         subshell_state = INACTIVE;
 867                         set_prompt_string ();
 868                         if (subshell_ready && !read_command_line_buffer (FALSE))
 869                         {
 870                             /* If we got here, some unforseen error must have occurred. */
 871                             flush_subshell (0, VISIBLY);
 872                             input_assign_text (cmdline, "");
 873                             subshell_should_clear_command_line = TRUE;
 874                         }
 875                     }
 876 
 877                     return TRUE;
 878                 }
 879 
 880             write_all (mc_global.tty.subshell_pty, pty_buffer, bytes);
 881 
 882             if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r')
 883             {
 884                 /* We should only clear the command line if we are using a shell that works
 885                  * with persistent command buffer, otherwise we get awkward results. */
 886                 if (use_persistent_buffer)
 887                     input_assign_text (cmdline, "");
 888                 subshell_ready = FALSE;
 889             }
 890         }
 891         else
 892             return FALSE;
 893     }
 894 }
 895 
 896 /* --------------------------------------------------------------------------------------------- */
 897 /* pty opening functions */
 898 
 899 #ifndef HAVE_OPENPTY
 900 
 901 #ifdef HAVE_GRANTPT
 902 
 903 /* System V version of pty_open_master */
 904 
 905 static int
 906 pty_open_master (char *pty_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 907 {
 908     char *slave_name;
 909     int pty_master;
 910 
 911 #ifdef HAVE_POSIX_OPENPT
 912     pty_master = posix_openpt (O_RDWR);
 913 #elif defined HAVE_GETPT
 914     /* getpt () is a GNU extension (glibc 2.1.x) */
 915     pty_master = getpt ();
 916 #elif defined IS_AIX
 917     strcpy (pty_name, "/dev/ptc");
 918     pty_master = open (pty_name, O_RDWR);
 919 #else
 920     strcpy (pty_name, "/dev/ptmx");
 921     pty_master = open (pty_name, O_RDWR);
 922 #endif
 923 
 924     if (pty_master == -1)
 925         return -1;
 926 
 927     if (grantpt (pty_master) == -1      /* Grant access to slave */
 928         || unlockpt (pty_master) == -1  /* Clear slave's lock flag */
 929         || !(slave_name = ptsname (pty_master)))        /* Get slave's name */
 930     {
 931         close (pty_master);
 932         return -1;
 933     }
 934     strcpy (pty_name, slave_name);
 935     return pty_master;
 936 }
 937 
 938 /* --------------------------------------------------------------------------------------------- */
 939 /** System V version of pty_open_slave */
 940 
 941 static int
 942 pty_open_slave (const char *pty_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 943 {
 944     int pty_slave;
 945 
 946     pty_slave = open (pty_name, O_RDWR);
 947     if (pty_slave == -1)
 948     {
 949         fprintf (stderr, "open (%s, O_RDWR): %s\r\n", pty_name, unix_error_string (errno));
 950         return -1;
 951     }
 952 #if !defined(__osf__) && !defined(__linux__)
 953 #if defined (I_FIND) && defined (I_PUSH)
 954     if (ioctl (pty_slave, I_FIND, "ptem") == 0)
 955         if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
 956         {
 957             fprintf (stderr, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
 958                      pty_slave, unix_error_string (errno));
 959             close (pty_slave);
 960             return -1;
 961         }
 962 
 963     if (ioctl (pty_slave, I_FIND, "ldterm") == 0)
 964         if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
 965         {
 966             fprintf (stderr,
 967                      "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
 968                      pty_slave, unix_error_string (errno));
 969             close (pty_slave);
 970             return -1;
 971         }
 972 #if !defined(sgi) && !defined(__sgi)
 973     if (ioctl (pty_slave, I_FIND, "ttcompat") == 0)
 974         if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
 975         {
 976             fprintf (stderr,
 977                      "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
 978                      pty_slave, unix_error_string (errno));
 979             close (pty_slave);
 980             return -1;
 981         }
 982 #endif /* sgi || __sgi */
 983 #endif /* I_FIND && I_PUSH */
 984 #endif /* __osf__ || __linux__ */
 985 
 986     fcntl (pty_slave, F_SETFD, FD_CLOEXEC);
 987     return pty_slave;
 988 }
 989 
 990 #else /* !HAVE_GRANTPT */
 991 
 992 /* --------------------------------------------------------------------------------------------- */
 993 /** BSD version of pty_open_master */
 994 static int
 995 pty_open_master (char *pty_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 996 {
 997     int pty_master;
 998     const char *ptr1, *ptr2;
 999 
1000     strcpy (pty_name, "/dev/ptyXX");
1001     for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1002     {
1003         pty_name[8] = *ptr1;
1004         for (ptr2 = "0123456789abcdef"; *ptr2 != '\0'; ++ptr2)
1005         {
1006             pty_name[9] = *ptr2;
1007 
1008             /* Try to open master */
1009             pty_master = open (pty_name, O_RDWR);
1010             if (pty_master == -1)
1011             {
1012                 if (errno == ENOENT)    /* Different from EIO */
1013                     return -1;  /* Out of pty devices */
1014                 continue;       /* Try next pty device */
1015             }
1016             pty_name[5] = 't';  /* Change "pty" to "tty" */
1017             if (access (pty_name, 6) != 0)
1018             {
1019                 close (pty_master);
1020                 pty_name[5] = 'p';
1021                 continue;
1022             }
1023             return pty_master;
1024         }
1025     }
1026     return -1;                  /* Ran out of pty devices */
1027 }
1028 
1029 /* --------------------------------------------------------------------------------------------- */
1030 /** BSD version of pty_open_slave */
1031 
1032 static int
1033 pty_open_slave (const char *pty_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
1034 {
1035     int pty_slave;
1036     struct group *group_info;
1037 
1038     group_info = getgrnam ("tty");
1039     if (group_info != NULL)
1040     {
1041         /* The following two calls will only succeed if we are root */
1042         /* [Commented out while permissions problem is investigated] */
1043         /* chown (pty_name, getuid (), group_info->gr_gid);  FIXME */
1044         /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP);   FIXME */
1045     }
1046     pty_slave = open (pty_name, O_RDWR);
1047     if (pty_slave == -1)
1048         fprintf (stderr, "open (pty_name, O_RDWR): %s\r\n", pty_name);
1049     fcntl (pty_slave, F_SETFD, FD_CLOEXEC);
1050     return pty_slave;
1051 }
1052 #endif /* !HAVE_GRANTPT */
1053 
1054 #endif /* !HAVE_OPENPTY */
1055 
1056 /* --------------------------------------------------------------------------------------------- */
1057 /**
1058  * Set up `precmd' or equivalent for reading the subshell's CWD.
1059  *
1060  * Attention! Never forget that these are *one-liners* even though the concatenated
1061  * substrings contain line breaks and indentation for better understanding of the
1062  * shell code. It is vital that each one-liner ends with a line feed character ("\n" ).
1063  *
1064  * @return initialized pre-command string
1065  */
1066 
1067 static void
1068 init_subshell_precmd (char *precmd, size_t buff_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
1069 {
1070     switch (mc_global.shell->type)
1071     {
1072     case SHELL_BASH:
1073         g_snprintf (precmd, buff_size,
1074                     " mc_print_command_buffer () { printf \"%%s\\\\n\" \"$READLINE_LINE\" >&%d; }\n"
1075                     " bind -x '\"\\e" SHELL_BUFFER_KEYBINDING "\":\"mc_print_command_buffer\"'\n"
1076                     " bind -x '\"\\e" SHELL_CURSOR_KEYBINDING
1077                     "\":\"echo $BASH_VERSINFO:$READLINE_POINT >&%d\"'\n"
1078                     " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n"
1079                     "PS1='\\u@\\h:\\w\\$ '\n", command_buffer_pipe[WRITE],
1080                     command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1081         break;
1082 
1083     case SHELL_ASH_BUSYBOX:
1084         /* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
1085          * that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
1086          *
1087          * A: This leads to a stopped subshell (=frozen mc) if user calls "ash" command
1088          *    "PS1='$(pwd>&%d; kill -STOP $$)\\u@\\h:\\w\\$ '\n",
1089          *
1090          * B: This leads to "sh: precmd: not found" in sub-subshell if user calls "ash" command
1091          *    "precmd() { pwd>&%d; kill -STOP $$; }; "
1092          *    "PS1='$(precmd)\\u@\\h:\\w\\$ '\n",
1093          *
1094          * C: This works if user calls "ash" command because in sub-subshell
1095          *    PRECMD is undefined, thus evaluated to empty string - no damage done.
1096          *    Attention: BusyBox must be built with FEATURE_EDITING_FANCY_PROMPT to
1097          *    permit \u, \w, \h, \$ escape sequences. Unfortunately this cannot be guaranteed,
1098          *    especially on embedded systems where people try to save space, so let's use
1099          *    the dash version below. It should work on virtually all systems.
1100          *    "precmd() { pwd>&%d; kill -STOP $$; }; "
1101          *    "PRECMD=precmd; "
1102          *    "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
1103          */
1104     case SHELL_DASH:
1105         /* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
1106          * but does not support escape sequences for user, host and cwd in prompt.
1107          * Attention! Make sure that the buffer for precmd is big enough.
1108          *
1109          * We want to have a fancy dynamic prompt with user@host:cwd just like in the BusyBox
1110          * examples above, but because replacing the home directory part of the path by "~" is
1111          * complicated, it bloats the precmd to a size > BUF_SMALL (128).
1112          *
1113          * The following example is a little less fancy (home directory not replaced)
1114          * and shows the basic workings of our prompt for easier understanding:
1115          *
1116          * "precmd() { "
1117          *     "echo \"$USER@$(hostname -s):$PWD\"; "
1118          *     "pwd>&%d; "
1119          *     "kill -STOP $$; "
1120          * "}; "
1121          * "PRECMD=precmd; "
1122          * "PS1='$($PRECMD)$ '\n",
1123          */
1124         g_snprintf (precmd, buff_size,
1125                     "precmd() { "
1126                     "if [ ! \"${PWD##$HOME}\" ]; then "
1127                     "MC_PWD=\"~\"; "
1128                     "else "
1129                     "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; "
1130                     "fi; "
1131                     "echo \"$USER@$(hostname -s):$MC_PWD\"; "
1132                     "pwd>&%d; "
1133                     "kill -STOP $$; "
1134                     "}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
1135         break;
1136 
1137     case SHELL_ZSH:
1138         g_snprintf (precmd, buff_size,
1139                     " mc_print_command_buffer () { printf \"%%s\\\\n\" \"$BUFFER\" >&%d; }\n"
1140                     " zle -N mc_print_command_buffer\n"
1141                     " bindkey '^[" SHELL_BUFFER_KEYBINDING "' mc_print_command_buffer\n"
1142                     " mc_print_cursor_position () { echo $CURSOR >&%d}\n"
1143                     " zle -N mc_print_cursor_position\n"
1144                     " bindkey '^[" SHELL_CURSOR_KEYBINDING "' mc_print_cursor_position\n"
1145                     " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n"
1146                     "PS1='%%n@%%m:%%~%%# '\n",
1147                     command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1148         break;
1149 
1150     case SHELL_TCSH:
1151         g_snprintf (precmd, buff_size,
1152                     "set echo_style=both; "
1153                     "set prompt='%%n@%%m:%%~%%# '; "
1154                     "alias precmd 'echo -n;echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
1155         break;
1156     case SHELL_FISH:
1157         g_snprintf (precmd, buff_size,
1158                     " bind \\e" SHELL_BUFFER_KEYBINDING " 'commandline >&%d';"
1159                     "bind \\e" SHELL_CURSOR_KEYBINDING " 'commandline -C >&%d';"
1160                     "if not functions -q fish_prompt_mc;"
1161                     "functions -e fish_right_prompt;"
1162                     "functions -c fish_prompt fish_prompt_mc; end;"
1163                     "function fish_prompt;"
1164                     "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n",
1165                     command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1166         break;
1167 
1168     default:
1169         break;
1170     }
1171 }
1172 
1173 /* --------------------------------------------------------------------------------------------- */
1174 /**
1175  * Carefully quote directory name to allow entering any directory safely,
1176  * no matter what weird characters it may contain in its name.
1177  * NOTE: Treat directory name an untrusted data, don't allow it to cause
1178  * executing any commands in the shell.  Escape all control characters.
1179  * Use following technique:
1180  *
1181  * printf(1) with format string containing a single conversion specifier,
1182  * "b", and an argument which contains a copy of the string passed to 
1183  * subshell_name_quote() with all characters, except digits and letters,
1184  * replaced by the backslash-escape sequence \0nnn, where "nnn" is the
1185  * numeric value of the character converted to octal number.
1186  * 
1187  *   cd "`printf '%b' 'ABC\0nnnDEF\0nnnXYZ'`"
1188  *
1189  * N.B.: Use single quotes for conversion specifier to work around
1190  *       tcsh 6.20+ parser breakage, see ticket #3852 for the details.
1191  */
1192 
1193 static GString *
1194 subshell_name_quote (const char *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
1195 {
1196     GString *ret;
1197     const char *su, *n;
1198     const char *quote_cmd_start, *quote_cmd_end;
1199 
1200     if (mc_global.shell->type == SHELL_FISH)
1201     {
1202         quote_cmd_start = "(printf '%b' '";
1203         quote_cmd_end = "')";
1204     }
1205     /* TODO: When BusyBox printf is fixed, get rid of this "else if", see
1206        http://lists.busybox.net/pipermail/busybox/2012-March/077460.html */
1207     /* else if (subshell_type == ASH_BUSYBOX)
1208        {
1209        quote_cmd_start = "\"`echo -en '";
1210        quote_cmd_end = "'`\"";
1211        } */
1212     else
1213     {
1214         quote_cmd_start = "\"`printf '%b' '";
1215         quote_cmd_end = "'`\"";
1216     }
1217 
1218     ret = g_string_sized_new (64);
1219 
1220     /* Prevent interpreting leading '-' as a switch for 'cd' */
1221     if (s[0] == '-')
1222         g_string_append (ret, "./");
1223 
1224     /* Copy the beginning of the command to the buffer */
1225     g_string_append (ret, quote_cmd_start);
1226 
1227     /*
1228      * Print every character except digits and letters as a backslash-escape
1229      * sequence of the form \0nnn, where "nnn" is the numeric value of the
1230      * character converted to octal number.
1231      */
1232     for (su = s; su[0] != '\0'; su = n)
1233     {
1234         n = str_cget_next_char_safe (su);
1235 
1236         if (str_isalnum (su))
1237             g_string_append_len (ret, su, n - su);
1238         else
1239         {
1240             int c;
1241 
1242             for (c = 0; c < n - su; c++)
1243                 g_string_append_printf (ret, "\\0%03o", (unsigned char) su[c]);
1244         }
1245     }
1246 
1247     g_string_append (ret, quote_cmd_end);
1248 
1249     return ret;
1250 }
1251 
1252 /* --------------------------------------------------------------------------------------------- */
1253 /*** public functions ****************************************************************************/
1254 /* --------------------------------------------------------------------------------------------- */
1255 
1256 /* --------------------------------------------------------------------------------------------- */
1257 /**
1258  *  Fork the subshell, and set up many, many things.
1259  *
1260  *  Possibly modifies the global variables:
1261  *      subshell_type, subshell_alive, subshell_stopped, subshell_pid
1262  *      mc_global.tty.use_subshell - Is set to FALSE if we can't run the subshell
1263  *      quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
1264  */
1265 
1266 void
1267 init_subshell (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1268 {
1269     /* This must be remembered across calls to init_subshell() */
1270     static char pty_name[BUF_SMALL];
1271     /* Must be considerably longer than BUF_SMALL (128) to support fancy shell prompts */
1272     char precmd[BUF_MEDIUM];
1273 
1274     /* Take the current (hopefully pristine) tty mode and make */
1275     /* a raw mode based on it now, before we do anything else with it */
1276     init_raw_mode ();
1277 
1278     if (mc_global.tty.subshell_pty == 0)
1279     {                           /* First time through */
1280         if (mc_global.shell->type == SHELL_NONE)
1281             return;
1282 
1283         /* Open a pty for talking to the subshell */
1284 
1285         /* FIXME: We may need to open a fresh pty each time on SVR4 */
1286 
1287 #ifdef HAVE_OPENPTY
1288         if (openpty (&mc_global.tty.subshell_pty, &subshell_pty_slave, NULL, NULL, NULL))
1289         {
1290             fprintf (stderr, "Cannot open master and slave sides of pty: %s\n",
1291                      unix_error_string (errno));
1292             mc_global.tty.use_subshell = FALSE;
1293             return;
1294         }
1295 #else
1296         mc_global.tty.subshell_pty = pty_open_master (pty_name);
1297         if (mc_global.tty.subshell_pty == -1)
1298         {
1299             fprintf (stderr, "Cannot open master side of pty: %s\r\n", unix_error_string (errno));
1300             mc_global.tty.use_subshell = FALSE;
1301             return;
1302         }
1303         subshell_pty_slave = pty_open_slave (pty_name);
1304         if (subshell_pty_slave == -1)
1305         {
1306             fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
1307                      pty_name, unix_error_string (errno));
1308             mc_global.tty.use_subshell = FALSE;
1309             return;
1310         }
1311 #endif /* HAVE_OPENPTY */
1312 
1313         /* Create a pipe for receiving the subshell's CWD */
1314 
1315         if (mc_global.shell->type == SHELL_TCSH)
1316         {
1317             g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
1318                         mc_tmpdir (), (int) getpid ());
1319             if (mkfifo (tcsh_fifo, 0600) == -1)
1320             {
1321                 fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo, unix_error_string (errno));
1322                 mc_global.tty.use_subshell = FALSE;
1323                 return;
1324             }
1325 
1326             /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
1327 
1328             if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
1329                 || (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
1330             {
1331                 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
1332                 perror (__FILE__ ": open");
1333                 mc_global.tty.use_subshell = FALSE;
1334                 return;
1335             }
1336         }
1337         else if (pipe (subshell_pipe) != 0)     /* subshell_type is BASH, ASH_BUSYBOX, DASH or ZSH */
1338         {
1339             perror (__FILE__ ": couldn't create pipe");
1340             mc_global.tty.use_subshell = FALSE;
1341             return;
1342         }
1343 
1344         if (mc_global.mc_run_mode == MC_RUN_FULL &&
1345             (mc_global.shell->type == SHELL_BASH || mc_global.shell->type == SHELL_ZSH
1346              || mc_global.shell->type == SHELL_FISH))
1347             use_persistent_buffer = TRUE;
1348         if (use_persistent_buffer && pipe (command_buffer_pipe) != 0)
1349         {
1350             perror (__FILE__ ": couldn't create pipe");
1351             mc_global.tty.use_subshell = FALSE;
1352             return;
1353         }
1354     }
1355 
1356     /* Fork the subshell */
1357 
1358     subshell_alive = TRUE;
1359     subshell_stopped = FALSE;
1360     subshell_pid = fork ();
1361 
1362     if (subshell_pid == -1)
1363     {
1364         fprintf (stderr, "Cannot spawn the subshell process: %s\r\n", unix_error_string (errno));
1365         /* We exit here because, if the process table is full, the */
1366         /* other method of running user commands won't work either */
1367         exit (EXIT_FAILURE);
1368     }
1369 
1370     if (subshell_pid == 0)
1371     {
1372         /* We are in the child process */
1373         init_subshell_child (pty_name);
1374     }
1375 
1376     init_subshell_precmd (precmd, BUF_MEDIUM);
1377 
1378     write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd));
1379 
1380     /* Wait until the subshell has started up and processed the command */
1381 
1382     subshell_state = RUNNING_COMMAND;
1383     tty_enable_interrupt_key ();
1384     if (!feed_subshell (QUIETLY, TRUE))
1385         mc_global.tty.use_subshell = FALSE;
1386     tty_disable_interrupt_key ();
1387     if (!subshell_alive)
1388         mc_global.tty.use_subshell = FALSE;     /* Subshell died instantly, so don't use it */
1389 
1390     /* Try out the persistent command buffer feature. If it doesn't work the first time, we
1391      * assume there must be something wrong with the shell, and we turn persistent buffer off
1392      * for good. This will save the user the trouble of having to wait for the persistent
1393      * buffer function to time out every time they try to close the subshell. */
1394     if (use_persistent_buffer && !read_command_line_buffer (TRUE))
1395         use_persistent_buffer = FALSE;
1396 }
1397 
1398 /* --------------------------------------------------------------------------------------------- */
1399 
1400 int
1401 invoke_subshell (const char *command, int how, vfs_path_t ** new_dir_vpath)
     /* [previous][next][first][last][top][bottom][index][help]  */
1402 {
1403     /* Make the MC terminal transparent */
1404     tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
1405 
1406     /* Make the subshell change to MC's working directory */
1407     if (new_dir_vpath != NULL)
1408         do_subshell_chdir (subshell_get_cwd (), TRUE);
1409 
1410     if (command == NULL)        /* The user has done "C-o" from MC */
1411     {
1412         if (subshell_state == INACTIVE)
1413         {
1414             subshell_state = ACTIVE;
1415 
1416             /* FIXME: possibly take out this hack; the user can re-play it by hitting C-hyphen a few times! */
1417             if (subshell_ready && mc_global.mc_run_mode == MC_RUN_FULL)
1418                 write_all (mc_global.tty.subshell_pty, " \b", 2);       /* Hack to make prompt reappear */
1419 
1420             if (use_persistent_buffer)
1421             {
1422                 size_t i;
1423                 int pos;
1424 
1425                 /* Check to make sure there are no non text characters in the command buffer,
1426                  * such as tab, or newline, as this could cause problems. */
1427                 for (i = 0; cmdline->buffer[i] != '\0'; i++)
1428                     if ((unsigned char) cmdline->buffer[i] < 32
1429                         || (unsigned char) cmdline->buffer[i] == 127)
1430                         cmdline->buffer[i] = ' ';
1431 
1432                 /* Write the command buffer to the subshell. */
1433                 write_all (mc_global.tty.subshell_pty, cmdline->buffer, strlen (cmdline->buffer));
1434 
1435                 /* Put the cursor in the correct place in the subshell. */
1436                 pos = str_length (cmdline->buffer) - cmdline->point;
1437                 for (i = 0; i < (size_t) pos; i++)
1438                     write_all (mc_global.tty.subshell_pty, ESC_STR "[D", 3);
1439             }
1440         }
1441     }
1442     else                        /* MC has passed us a user command */
1443     {
1444         /* Before we write to the command prompt, we need to clear whatever */
1445         /* data is there, but only if we are using one of the shells that */
1446         /* doesn't support keeping command buffer contents, OR if there was */
1447         /* some sort of error. */
1448         if (!use_persistent_buffer || subshell_should_clear_command_line)
1449         {
1450             write_all (mc_global.tty.subshell_pty, "\003", 1);
1451             subshell_state = RUNNING_COMMAND;
1452             /* We need to call feed_subshell here if we are using fish, because of a quirk
1453              * in the behavioral of that particular shell. */
1454             if (mc_global.shell->type != SHELL_FISH)
1455                 feed_subshell (QUIETLY, FALSE);
1456         }
1457 
1458         if (how == QUIETLY)
1459             write_all (mc_global.tty.subshell_pty, " ", 1);
1460         /* FIXME: if command is long (>8KB ?) we go comma */
1461         write_all (mc_global.tty.subshell_pty, command, strlen (command));
1462         write_all (mc_global.tty.subshell_pty, "\n", 1);
1463         subshell_state = RUNNING_COMMAND;
1464         subshell_ready = FALSE;
1465     }
1466 
1467     feed_subshell (how, FALSE);
1468 
1469     if (new_dir_vpath != NULL && subshell_alive)
1470     {
1471         const char *pcwd;
1472 
1473         pcwd = vfs_translate_path (vfs_path_as_str (subshell_get_cwd ()));
1474         if (strcmp (subshell_cwd, pcwd) != 0)
1475             *new_dir_vpath = vfs_path_from_str (subshell_cwd);  /* Make MC change to the subshell's CWD */
1476     }
1477 
1478     /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
1479     while (!subshell_alive && subshell_get_mainloop_quit () == 0 && mc_global.tty.use_subshell)
1480         init_subshell ();
1481 
1482     return subshell_get_mainloop_quit ();
1483 }
1484 
1485 /* --------------------------------------------------------------------------------------------- */
1486 
1487 gboolean
1488 flush_subshell (int max_wait_length, int how)
     /* [previous][next][first][last][top][bottom][index][help]  */
1489 {
1490     int rc = 0;
1491     ssize_t bytes = 0;
1492     struct timeval timeleft = { 0, 0 };
1493     gboolean return_value = FALSE;
1494     fd_set tmp;
1495 
1496     timeleft.tv_sec = max_wait_length;
1497     FD_ZERO (&tmp);
1498     FD_SET (mc_global.tty.subshell_pty, &tmp);
1499 
1500     while (subshell_alive
1501            && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0)
1502     {
1503         /* Check for 'select' errors */
1504         if (rc == -1)
1505         {
1506             if (errno == EINTR)
1507             {
1508                 if (tty_got_winch ())
1509                     tty_change_screen_size ();
1510 
1511                 continue;
1512             }
1513 
1514             fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno));
1515             exit (EXIT_FAILURE);
1516         }
1517 
1518         return_value = TRUE;
1519         timeleft.tv_sec = 0;
1520         timeleft.tv_usec = 0;
1521 
1522         bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
1523         if (how == VISIBLY)
1524             write_all (STDOUT_FILENO, pty_buffer, bytes);
1525     }
1526 
1527     return return_value;
1528 }
1529 
1530 /* --------------------------------------------------------------------------------------------- */
1531 
1532 gboolean
1533 read_subshell_prompt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1534 {
1535     int rc = 0;
1536     ssize_t bytes = 0;
1537     struct timeval timeleft = { 0, 0 };
1538     gboolean should_reset_prompt = TRUE;
1539     gboolean got_new_prompt = FALSE;
1540 
1541     fd_set tmp;
1542     FD_ZERO (&tmp);
1543     FD_SET (mc_global.tty.subshell_pty, &tmp);
1544 
1545     while (subshell_alive
1546            && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0)
1547     {
1548         /* Check for 'select' errors */
1549         if (rc == -1)
1550         {
1551             if (errno == EINTR)
1552             {
1553                 if (tty_got_winch ())
1554                     tty_change_screen_size ();
1555 
1556                 continue;
1557             }
1558 
1559             fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno));
1560             exit (EXIT_FAILURE);
1561         }
1562 
1563         bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
1564         if (should_reset_prompt)
1565         {
1566             should_reset_prompt = FALSE;
1567             clear_subshell_prompt_string ();
1568         }
1569 
1570         parse_subshell_prompt_string (pty_buffer, bytes);
1571         got_new_prompt = TRUE;
1572     }
1573 
1574     if (got_new_prompt)
1575         set_prompt_string ();
1576 
1577     return (rc != 0 || bytes != 0);
1578 }
1579 
1580 /* --------------------------------------------------------------------------------------------- */
1581 
1582 void
1583 do_update_prompt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1584 {
1585     if (update_subshell_prompt)
1586     {
1587         printf ("\r\n%s", subshell_prompt->str);
1588         fflush (stdout);
1589         update_subshell_prompt = FALSE;
1590     }
1591 }
1592 
1593 /* --------------------------------------------------------------------------------------------- */
1594 
1595 gboolean
1596 exit_subshell (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1597 {
1598     gboolean subshell_quit = TRUE;
1599 
1600     if (subshell_state != INACTIVE && subshell_alive)
1601         subshell_quit =
1602             query_dialog (_("Warning"),
1603                           _("The shell is still active. Quit anyway?"),
1604                           D_NORMAL, 2, _("&Yes"), _("&No")) == 0;
1605 
1606     if (subshell_quit)
1607     {
1608         if (mc_global.shell->type == SHELL_TCSH)
1609         {
1610             if (unlink (tcsh_fifo) == -1)
1611                 fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
1612                          tcsh_fifo, unix_error_string (errno));
1613         }
1614 
1615         if (subshell_prompt != NULL)
1616         {
1617             g_string_free (subshell_prompt, TRUE);
1618             subshell_prompt = NULL;
1619         }
1620 
1621         if (subshell_prompt_temp_buffer != NULL)
1622         {
1623             g_string_free (subshell_prompt_temp_buffer, TRUE);
1624             subshell_prompt_temp_buffer = NULL;
1625         }
1626 
1627         pty_buffer[0] = '\0';
1628     }
1629 
1630     return subshell_quit;
1631 }
1632 
1633 /* --------------------------------------------------------------------------------------------- */
1634 
1635 /** If it actually changed the directory it returns true */
1636 void
1637 do_subshell_chdir (const vfs_path_t * vpath, gboolean update_prompt)
     /* [previous][next][first][last][top][bottom][index][help]  */
1638 {
1639     char *pcwd;
1640 
1641     pcwd = vfs_path_to_str_flags (subshell_get_cwd (), 0, VPF_RECODE);
1642 
1643     if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, pcwd) != 0))
1644     {
1645         /* We have to repaint the subshell prompt if we read it from
1646          * the main program.  Please note that in the code after this
1647          * if, the cd command that is sent will make the subshell
1648          * repaint the prompt, so we don't have to paint it. */
1649         if (update_prompt)
1650             do_update_prompt ();
1651         g_free (pcwd);
1652         return;
1653     }
1654 
1655     /* If we are using a shell that doesn't support persistent command buffer, we need to clear
1656      * the command prompt before we send the cd command. */
1657     if (!use_persistent_buffer || subshell_should_clear_command_line)
1658     {
1659         write_all (mc_global.tty.subshell_pty, "\003", 1);
1660         subshell_state = RUNNING_COMMAND;
1661         if (mc_global.shell->type != SHELL_FISH)
1662             feed_subshell (QUIETLY, FALSE);
1663     }
1664     /* The initial space keeps this out of the command history (in bash
1665        because we set "HISTCONTROL=ignorespace") */
1666     write_all (mc_global.tty.subshell_pty, " cd ", 4);
1667 
1668     if (vpath != NULL)
1669     {
1670         const char *translate;
1671 
1672         translate = vfs_translate_path (vfs_path_as_str (vpath));
1673         if (translate != NULL)
1674         {
1675             GString *temp;
1676 
1677             temp = subshell_name_quote (translate);
1678             write_all (mc_global.tty.subshell_pty, temp->str, temp->len);
1679             g_string_free (temp, TRUE);
1680         }
1681         else
1682         {
1683             write_all (mc_global.tty.subshell_pty, ".", 1);
1684         }
1685     }
1686     else
1687     {
1688         write_all (mc_global.tty.subshell_pty, "/", 1);
1689     }
1690     write_all (mc_global.tty.subshell_pty, "\n", 1);
1691 
1692     subshell_state = RUNNING_COMMAND;
1693     feed_subshell (QUIETLY, FALSE);
1694 
1695     if (subshell_alive)
1696     {
1697         gboolean bPathNotEq;
1698 
1699         bPathNotEq = strcmp (subshell_cwd, pcwd) != 0;
1700 
1701         if (bPathNotEq && mc_global.shell->type == SHELL_TCSH)
1702         {
1703             char rp_subshell_cwd[PATH_MAX];
1704             char rp_current_panel_cwd[PATH_MAX];
1705             char *p_subshell_cwd, *p_current_panel_cwd;
1706 
1707             p_subshell_cwd = mc_realpath (subshell_cwd, rp_subshell_cwd);
1708             p_current_panel_cwd = mc_realpath (pcwd, rp_current_panel_cwd);
1709 
1710             if (p_subshell_cwd == NULL)
1711                 p_subshell_cwd = subshell_cwd;
1712             if (p_current_panel_cwd == NULL)
1713                 p_current_panel_cwd = pcwd;
1714             bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd) != 0;
1715         }
1716 
1717         if (bPathNotEq && !DIR_IS_DOT (pcwd))
1718         {
1719             char *cwd;
1720 
1721             cwd = vfs_path_to_str_flags (subshell_get_cwd (), 0, VPF_STRIP_PASSWORD);
1722             vfs_print_message (_("Warning: Cannot change to %s.\n"), cwd);
1723             g_free (cwd);
1724         }
1725     }
1726 
1727     /* Really escape Zsh history */
1728     if (mc_global.shell->type == SHELL_ZSH)
1729     {
1730         /* Per Zsh documentation last command prefixed with space lingers in the internal history
1731          * until the next command is entered before it vanishes. To make it vanish right away,
1732          * type a space and press return. */
1733         write_all (mc_global.tty.subshell_pty, " \n", 2);
1734         subshell_state = RUNNING_COMMAND;
1735         feed_subshell (QUIETLY, FALSE);
1736     }
1737 
1738     update_subshell_prompt = FALSE;
1739 
1740     g_free (pcwd);
1741     /* Make sure that MC never stores the CWD in a silly format */
1742     /* like /usr////lib/../bin, or the strcmp() above will fail */
1743 }
1744 
1745 /* --------------------------------------------------------------------------------------------- */
1746 
1747 void
1748 subshell_get_console_attributes (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1749 {
1750     /* Get our current terminal modes */
1751 
1752     if (tcgetattr (STDOUT_FILENO, &shell_mode))
1753     {
1754         fprintf (stderr, "Cannot get terminal settings: %s\r\n", unix_error_string (errno));
1755         mc_global.tty.use_subshell = FALSE;
1756     }
1757 }
1758 
1759 /* --------------------------------------------------------------------------------------------- */
1760 /**
1761  * Figure out whether the subshell has stopped, exited or been killed
1762  * Possibly modifies: 'subshell_alive', 'subshell_stopped' and 'quit' */
1763 
1764 void
1765 sigchld_handler (int sig)
     /* [previous][next][first][last][top][bottom][index][help]  */
1766 {
1767     int status;
1768     pid_t pid;
1769 
1770     (void) sig;
1771 
1772     pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
1773 
1774     if (pid == subshell_pid)
1775     {
1776         /* Figure out what has happened to the subshell */
1777 
1778         if (WIFSTOPPED (status))
1779         {
1780             if (WSTOPSIG (status) == SIGSTOP)
1781             {
1782                 /* The subshell has received a SIGSTOP signal */
1783                 subshell_stopped = TRUE;
1784             }
1785             else
1786             {
1787                 /* The user has suspended the subshell.  Revive it */
1788                 kill (subshell_pid, SIGCONT);
1789             }
1790         }
1791         else
1792         {
1793             /* The subshell has either exited normally or been killed */
1794             subshell_alive = FALSE;
1795             delete_select_channel (mc_global.tty.subshell_pty);
1796             if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
1797             {
1798                 int subshell_quit;
1799                 subshell_quit = subshell_get_mainloop_quit () | SUBSHELL_EXIT;  /* Exited normally */
1800                 subshell_set_mainloop_quit (subshell_quit);
1801             }
1802         }
1803     }
1804     subshell_handle_cons_saver ();
1805 
1806     /* If we got here, some other child exited; ignore it */
1807 }
1808 
1809 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */