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

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

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