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. clear_cwd_pipe
  17. init_subshell
  18. invoke_subshell
  19. flush_subshell
  20. read_subshell_prompt
  21. do_update_prompt
  22. exit_subshell
  23. do_subshell_chdir
  24. subshell_get_console_attributes
  25. sigchld_handler

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

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