Merge branch '4561_tar_segfault'
[midnight-commander.git] / src / subshell / common.c
blobdbc32afc2c415607ab16cbda772dff213ac83e21
1 /*
2 Concurrent shell support for the Midnight Commander
4 Copyright (C) 1994-2024
5 Free Software Foundation, Inc.
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>
35 This file is part of the Midnight Commander.
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.
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.
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/>.
51 /** \file subshell.c
52 * \brief Source: concurrent shell support
55 #include <config.h>
57 #ifndef _GNU_SOURCE
58 #define _GNU_SOURCE 1
59 #endif
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>
80 #ifdef HAVE_STROPTS_H
81 #include <stropts.h> /* For I_PUSH */
82 #endif /* HAVE_STROPTS_H */
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 */
98 #include "lib/global.h"
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"
110 #include "src/filemanager/layout.h" /* setup_cmdline() */
111 #include "src/filemanager/command.h" /* cmdline */
113 #include "subshell.h"
114 #include "internal.h"
116 /*** global variables ****************************************************************************/
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;
124 /* Holds the latest prompt captured from the subshell */
125 GString *subshell_prompt = NULL;
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;
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;
135 /*** file scope macro definitions ****************************************************************/
137 #ifndef WEXITSTATUS
138 #define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
139 #endif
141 #ifndef WIFEXITED
142 #define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
143 #endif
145 /* Initial length of the buffer for the subshell's prompt */
146 #define INITIAL_PROMPT_SIZE 10
148 /* Used by the child process to indicate failure to start the subshell */
149 #define FORK_FAILURE 69 /* Arbitrary */
151 /* Length of the buffer for all I/O with the subshell */
152 #define PTY_BUFFER_SIZE BUF_MEDIUM /* Arbitrary; but keep it >= 80 */
154 /*** file scope type declarations ****************************************************************/
156 /* For pipes */
157 enum
159 READ = 0,
160 WRITE = 1
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 "_"
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 "+"
171 /*** forward declarations (file scope functions) *************************************************/
173 /*** file scope variables ************************************************************************/
175 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
176 static char tcsh_fifo[128];
178 static int subshell_pty_slave = -1;
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 /* *INDENT-ON* */
185 /* For reading/writing on the subshell's pty */
186 static char pty_buffer[PTY_BUFFER_SIZE] = "\0";
188 /* To pass CWD info from the subshell to MC */
189 static int subshell_pipe[2];
191 /* To pass command buffer info from the subshell to MC */
192 static int command_buffer_pipe[2];
194 /* The subshell's process ID */
195 static pid_t subshell_pid = 1;
197 /* One extra char for final '\n' */
198 static char subshell_cwd[MC_MAXPATHLEN + 1];
200 /* Flag to indicate whether the subshell is ready for next command */
201 static int subshell_ready;
203 /* Flag to indicate if the subshell supports the persistent buffer feature. */
204 static gboolean use_persistent_buffer = FALSE;
206 /* This is the local variable where the subshell prompt is stored while we are working on it. */
207 static GString *subshell_prompt_temp_buffer = NULL;
209 /* The following two flags can be changed by the SIGCHLD handler. This is */
210 /* OK, because the 'int' type is updated atomically on all known machines */
211 static volatile int subshell_alive, subshell_stopped;
213 /* We store the terminal's initial mode here so that we can configure
214 the pty similarly, and also so we can restore the real terminal to
215 sanity if we have to exit abruptly */
216 static struct termios shell_mode;
218 /* This is a transparent mode for the terminal where MC is running on */
219 /* It is used when the shell is active, so that the control signals */
220 /* are delivered to the shell pty */
221 static struct termios raw_mode;
223 /* --------------------------------------------------------------------------------------------- */
224 /*** file scope functions ************************************************************************/
225 /* --------------------------------------------------------------------------------------------- */
227 * Write all data, even if the write() call is interrupted.
230 static ssize_t
231 write_all (int fd, const void *buf, size_t count)
233 ssize_t written = 0;
235 while (count > 0)
237 ssize_t ret;
239 ret = write (fd, (const unsigned char *) buf + written, count);
240 if (ret < 0)
242 if (errno == EINTR)
244 if (tty_got_winch ())
245 tty_change_screen_size ();
247 continue;
250 return written > 0 ? written : ret;
252 count -= ret;
253 written += ret;
255 return written;
258 /* --------------------------------------------------------------------------------------------- */
260 * Prepare child process to running the shell and run it.
262 * Modifies the global variables (in the child process only):
263 * shell_mode
265 * Returns: never.
268 static void
269 init_subshell_child (const char *pty_name)
271 char *init_file = NULL;
272 pid_t mc_sid;
274 (void) pty_name;
275 setsid (); /* Get a fresh terminal session */
277 /* Make sure that it has become our controlling terminal */
279 /* Redundant on Linux and probably most systems, but just in case: */
281 #ifdef TIOCSCTTY
282 ioctl (subshell_pty_slave, TIOCSCTTY, 0);
283 #endif
285 /* Configure its terminal modes and window size */
287 /* Set up the pty with the same termios flags as our own tty */
288 if (tcsetattr (subshell_pty_slave, TCSANOW, &shell_mode))
290 fprintf (stderr, "Cannot set pty terminal modes: %s\r\n", unix_error_string (errno));
291 my_exit (FORK_FAILURE);
294 /* Set the pty's size (80x25 by default on Linux) according to the */
295 /* size of the real terminal as calculated by ncurses, if possible */
296 tty_resize (subshell_pty_slave);
298 /* Set up the subshell's environment and init file name */
300 /* It simplifies things to change to our home directory here, */
301 /* and the user's startup file may do a 'cd' command anyway */
303 int ret;
305 ret = chdir (mc_config_get_home_dir ()); /* FIXME? What about when we re-run the subshell? */
306 (void) ret;
309 /* Set MC_SID to prevent running one mc from another */
310 mc_sid = getsid (0);
311 if (mc_sid != -1)
313 char sid_str[BUF_SMALL];
315 g_snprintf (sid_str, sizeof (sid_str), "MC_SID=%ld", (long) mc_sid);
316 putenv (g_strdup (sid_str));
319 switch (mc_global.shell->type)
321 case SHELL_BASH:
322 /* Do we have a custom init file ~/.local/share/mc/bashrc? */
323 init_file = mc_config_get_full_path (MC_BASHRC_FILE);
325 /* Otherwise use ~/.bashrc */
326 if (!exist_file (init_file))
328 g_free (init_file);
329 init_file = g_strdup (".bashrc");
332 /* Make MC's special commands not show up in bash's history and also suppress
333 * consecutive identical commands*/
334 putenv ((char *) "HISTCONTROL=ignoreboth");
336 /* Allow alternative readline settings for MC */
338 char *input_file;
340 input_file = mc_config_get_full_path (MC_INPUTRC_FILE);
341 if (exist_file (input_file))
342 g_setenv ("INPUTRC", input_file, TRUE);
343 g_free (input_file);
346 break;
348 case SHELL_ASH_BUSYBOX:
349 case SHELL_DASH:
350 /* Do we have a custom init file ~/.local/share/mc/ashrc? */
351 init_file = mc_config_get_full_path (MC_ASHRC_FILE);
353 /* Otherwise use ~/.profile */
354 if (!exist_file (init_file))
356 g_free (init_file);
357 init_file = g_strdup (".profile");
360 /* Put init file to ENV variable used by ash */
361 g_setenv ("ENV", init_file, TRUE);
363 break;
365 case SHELL_ZSH:
366 /* ZDOTDIR environment variable is the only way to point zsh
367 * to an other rc file than the default. */
369 /* Don't overwrite $ZDOTDIR */
370 if (g_getenv ("ZDOTDIR") != NULL)
372 /* Do we have a custom init file ~/.local/share/mc/.zshrc?
373 * Otherwise use standard ~/.zshrc */
374 init_file = mc_config_get_full_path (MC_ZSHRC_FILE);
375 if (exist_file (init_file))
377 /* Set ZDOTDIR to ~/.local/share/mc */
378 g_setenv ("ZDOTDIR", mc_config_get_data_path (), TRUE);
381 break;
383 /* TODO: Find a way to pass initfile to TCSH and FISH */
384 case SHELL_TCSH:
385 case SHELL_FISH:
386 break;
388 default:
389 fprintf (stderr, __FILE__ ": unimplemented subshell type %u\r\n", mc_global.shell->type);
390 my_exit (FORK_FAILURE);
393 /* Attach all our standard file descriptors to the pty */
395 /* This is done just before the exec, because stderr must still */
396 /* be connected to the real tty during the above error messages; */
397 /* otherwise the user will never see them. */
399 dup2 (subshell_pty_slave, STDIN_FILENO);
400 dup2 (subshell_pty_slave, STDOUT_FILENO);
401 dup2 (subshell_pty_slave, STDERR_FILENO);
403 close (subshell_pipe[READ]);
405 if (use_persistent_buffer)
406 close (command_buffer_pipe[READ]);
408 close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */
409 /* Close master side of pty. This is important; apart from */
410 /* freeing up the descriptor for use in the subshell, it also */
411 /* means that when MC exits, the subshell will get a SIGHUP and */
412 /* exit too, because there will be no more descriptors pointing */
413 /* at the master side of the pty and so it will disappear. */
414 close (mc_global.tty.subshell_pty);
416 /* Execute the subshell at last */
418 switch (mc_global.shell->type)
420 case SHELL_BASH:
421 execl (mc_global.shell->path, mc_global.shell->path, "-rcfile", init_file, (char *) NULL);
422 break;
424 case SHELL_ZSH:
425 /* Use -g to exclude cmds beginning with space from history
426 * and -Z to use the line editor on non-interactive term */
427 execl (mc_global.shell->path, mc_global.shell->path, "-Z", "-g", (char *) NULL);
428 break;
430 case SHELL_ASH_BUSYBOX:
431 case SHELL_DASH:
432 case SHELL_TCSH:
433 case SHELL_FISH:
434 execl (mc_global.shell->path, mc_global.shell->path, (char *) NULL);
435 break;
437 default:
438 break;
441 /* If we get this far, everything failed miserably */
442 g_free (init_file);
443 my_exit (FORK_FAILURE);
446 /* --------------------------------------------------------------------------------------------- */
448 static void
449 init_raw_mode (void)
451 static gboolean initialized = FALSE;
453 /* MC calls tty_reset_shell_mode() in pre_exec() to set the real tty to its */
454 /* original settings. However, here we need to make this tty very raw, */
455 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
456 /* pty. So, instead of changing the code for execute(), pre_exec(), */
457 /* etc, we just set up the modes we need here, before each command. */
459 if (!initialized) /* First time: initialise 'raw_mode' */
461 tcgetattr (STDOUT_FILENO, &raw_mode);
462 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
463 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
464 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
465 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
466 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
467 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
468 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
469 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
470 initialized = TRUE;
474 /* --------------------------------------------------------------------------------------------- */
476 * Wait until the subshell dies or stops. If it stops, make it resume.
477 * Possibly modifies the globals 'subshell_alive' and 'subshell_stopped'
480 static void
481 synchronize (void)
483 sigset_t sigchld_mask, old_mask;
485 sigemptyset (&sigchld_mask);
486 sigaddset (&sigchld_mask, SIGCHLD);
487 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
490 * SIGCHLD should not be blocked, but we unblock it just in case.
491 * This is known to be useful for cygwin 1.3.12 and older.
493 sigdelset (&old_mask, SIGCHLD);
495 /* Wait until the subshell has stopped */
496 while (subshell_alive && !subshell_stopped)
497 sigsuspend (&old_mask);
499 if (subshell_state != ACTIVE)
501 /* Discard all remaining data from stdin to the subshell */
502 tcflush (subshell_pty_slave, TCIFLUSH);
505 subshell_stopped = FALSE;
506 kill (subshell_pid, SIGCONT);
508 sigprocmask (SIG_SETMASK, &old_mask, NULL);
509 /* We can't do any better without modifying the shell(s) */
512 /* --------------------------------------------------------------------------------------------- */
513 /* Get the contents of the current subshell command line buffer, and */
514 /* transfer the contents to the panel command prompt. */
516 static gboolean
517 read_command_line_buffer (gboolean test_mode)
519 char subshell_command_buffer[BUF_LARGE];
520 char subshell_cursor_buffer[BUF_SMALL];
522 fd_set read_set;
523 int i;
524 ssize_t bytes;
525 struct timeval subshell_prompt_timer = { 0, 0 };
526 int command_buffer_length;
527 int command_buffer_char_length;
528 int bash_version;
529 int cursor_position;
530 int maxfdp;
531 int rc;
533 if (!use_persistent_buffer)
534 return TRUE;
536 FD_ZERO (&read_set);
537 FD_SET (command_buffer_pipe[READ], &read_set);
538 maxfdp = command_buffer_pipe[READ];
540 /* First, flush the command buffer pipe. This pipe shouldn't be written
541 * to under normal circumstances, but if it somehow does get written
542 * to, we need to make sure to discard whatever data is there before
543 * we try to use it. */
544 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 0)
546 if (rc == -1)
548 if (errno == EINTR)
549 continue;
551 return FALSE;
554 if (rc == 1)
556 bytes = read (command_buffer_pipe[READ], subshell_command_buffer,
557 sizeof (subshell_command_buffer));
558 (void) bytes;
562 /* get contents of command line buffer */
563 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_BUFFER_KEYBINDING,
564 sizeof (ESC_STR SHELL_CURSOR_KEYBINDING) - 1);
566 subshell_prompt_timer.tv_sec = 1;
567 FD_ZERO (&read_set);
568 FD_SET (command_buffer_pipe[READ], &read_set);
570 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1)
572 if (rc == -1)
574 if (errno == EINTR)
575 continue;
577 return FALSE;
580 if (rc == 0)
581 return FALSE;
584 bytes =
585 read (command_buffer_pipe[READ], subshell_command_buffer, sizeof (subshell_command_buffer));
586 if (bytes == 0 || bytes == sizeof (subshell_command_buffer))
587 return FALSE;
589 command_buffer_char_length = bytes - 1;
590 subshell_command_buffer[command_buffer_char_length] = '\0';
591 command_buffer_length = str_length (subshell_command_buffer);
593 /* get cursor position */
594 write_all (mc_global.tty.subshell_pty, ESC_STR SHELL_CURSOR_KEYBINDING,
595 sizeof (ESC_STR SHELL_CURSOR_KEYBINDING) - 1);
597 subshell_prompt_timer.tv_sec = 1;
598 subshell_prompt_timer.tv_usec = 0;
599 FD_ZERO (&read_set);
600 FD_SET (command_buffer_pipe[READ], &read_set);
602 while ((rc = select (maxfdp + 1, &read_set, NULL, NULL, &subshell_prompt_timer)) != 1)
604 if (rc == -1)
606 if (errno == EINTR)
607 continue;
609 return FALSE;
612 if (rc == 0)
613 return FALSE;
616 bytes =
617 read (command_buffer_pipe[READ], subshell_cursor_buffer, sizeof (subshell_cursor_buffer));
618 if (bytes == 0)
619 return FALSE;
621 subshell_cursor_buffer[bytes - 1] = '\0';
622 if (mc_global.shell->type == SHELL_BASH)
624 if (sscanf (subshell_cursor_buffer, "%d:%d", &bash_version, &cursor_position) != 2)
625 return FALSE;
627 else
629 if (sscanf (subshell_cursor_buffer, "%d", &cursor_position) != 1)
630 return FALSE;
631 bash_version = 1000;
634 if (test_mode)
635 return TRUE;
637 /* Substitute non-text characters in the command buffer, such as tab, or newline, as this
638 * could cause problems. */
639 for (i = 0; i < command_buffer_char_length; i++)
640 if ((unsigned char) subshell_command_buffer[i] < 32
641 || (unsigned char) subshell_command_buffer[i] == 127)
642 subshell_command_buffer[i] = ' ';
644 input_assign_text (cmdline, "");
645 input_insert (cmdline, subshell_command_buffer, FALSE);
647 if (bash_version < 5) /* implies SHELL_BASH */
649 /* We need to do this because bash < v5 gives the cursor position in a utf-8 string based
650 * on the location in bytes, not in unicode characters. */
651 char *curr, *stop;
653 curr = subshell_command_buffer;
654 stop = curr + cursor_position;
656 for (cursor_position = 0; curr < stop; cursor_position++)
657 str_next_char_safe (&curr);
659 if (cursor_position > command_buffer_length)
660 cursor_position = command_buffer_length;
661 cmdline->point = cursor_position;
662 /* We send any remaining data to STDOUT before we finish. */
663 flush_subshell (0, VISIBLY);
665 /* Now we erase the current contents of the command line buffer */
666 if (mc_global.shell->type != SHELL_ZSH)
668 /* In zsh, we can just press c-u to clear the line, without needing to go to the end of
669 * the line first first. In all other shells, we must go to the end of the line first. */
671 /* If we are not at the end of the line, we go to the end. */
672 if (cursor_position != command_buffer_length)
674 write_all (mc_global.tty.subshell_pty, "\005", 1);
675 if (flush_subshell (1, VISIBLY) != 1)
676 return FALSE;
680 if (command_buffer_length > 0)
682 /* Now we clear the line. */
683 write_all (mc_global.tty.subshell_pty, "\025", 1);
684 if (flush_subshell (1, VISIBLY) != 1)
685 return FALSE;
688 return TRUE;
691 /* --------------------------------------------------------------------------------------------- */
693 static void
694 clear_subshell_prompt_string (void)
696 if (subshell_prompt_temp_buffer != NULL)
697 g_string_set_size (subshell_prompt_temp_buffer, 0);
700 /* --------------------------------------------------------------------------------------------- */
702 static void
703 parse_subshell_prompt_string (const char *buffer, int bytes)
705 int i;
707 if (mc_global.mc_run_mode != MC_RUN_FULL)
708 return;
710 /* First time through */
711 if (subshell_prompt == NULL)
712 subshell_prompt = g_string_sized_new (INITIAL_PROMPT_SIZE);
713 if (subshell_prompt_temp_buffer == NULL)
714 subshell_prompt_temp_buffer = g_string_sized_new (INITIAL_PROMPT_SIZE);
716 /* Extract the prompt from the shell output */
717 for (i = 0; i < bytes; i++)
718 if (buffer[i] == '\n' || buffer[i] == '\r')
719 g_string_set_size (subshell_prompt_temp_buffer, 0);
720 else if (buffer[i] != '\0')
721 g_string_append_c (subshell_prompt_temp_buffer, buffer[i]);
724 /* --------------------------------------------------------------------------------------------- */
726 static void
727 set_prompt_string (void)
729 if (mc_global.mc_run_mode != MC_RUN_FULL)
730 return;
732 if (subshell_prompt_temp_buffer->len != 0)
733 mc_g_string_copy (subshell_prompt, subshell_prompt_temp_buffer);
735 setup_cmdline ();
738 /* --------------------------------------------------------------------------------------------- */
739 /** Feed the subshell our keyboard input until it says it's finished */
741 static gboolean
742 feed_subshell (int how, gboolean fail_on_error)
744 fd_set read_set; /* For 'select' */
745 int bytes; /* For the return value from 'read' */
746 int i; /* Loop counter */
748 struct timeval wtime; /* Maximum time we wait for the subshell */
749 struct timeval *wptr;
751 should_read_new_subshell_prompt = FALSE;
753 /* have more than enough time to run subshell:
754 wait up to 10 second if fail_on_error, forever otherwise */
755 wtime.tv_sec = 10;
756 wtime.tv_usec = 0;
757 wptr = fail_on_error ? &wtime : NULL;
759 while (TRUE)
761 int maxfdp;
763 if (!subshell_alive)
764 return FALSE;
766 /* Prepare the file-descriptor set and call 'select' */
768 FD_ZERO (&read_set);
769 FD_SET (mc_global.tty.subshell_pty, &read_set);
770 FD_SET (subshell_pipe[READ], &read_set);
771 maxfdp = MAX (mc_global.tty.subshell_pty, subshell_pipe[READ]);
772 if (how == VISIBLY)
774 FD_SET (STDIN_FILENO, &read_set);
775 maxfdp = MAX (maxfdp, STDIN_FILENO);
778 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1)
780 /* Despite using SA_RESTART, we still have to check for this */
781 if (errno == EINTR)
783 if (tty_got_winch ())
784 tty_change_screen_size ();
786 continue; /* try all over again */
788 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
789 fprintf (stderr, "select (FD_SETSIZE, &read_set...): %s\r\n",
790 unix_error_string (errno));
791 exit (EXIT_FAILURE);
794 if (FD_ISSET (mc_global.tty.subshell_pty, &read_set))
795 /* Read from the subshell, write to stdout */
797 /* This loop improves performance by reducing context switches
798 by a factor of 20 or so... unfortunately, it also hangs MC
799 randomly, because of an apparent Linux bug. Investigate. */
800 /* for (i=0; i<5; ++i) * FIXME -- experimental */
802 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
804 /* The subshell has died */
805 if (bytes == -1 && errno == EIO && !subshell_alive)
806 return FALSE;
808 if (bytes <= 0)
810 #ifdef PTY_ZEROREAD
811 /* On IBM i, read(1) can return 0 for a non-closed fd */
812 continue;
813 #else
814 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
815 fprintf (stderr, "read (subshell_pty...): %s\r\n", unix_error_string (errno));
816 exit (EXIT_FAILURE);
817 #endif
820 if (how == VISIBLY)
821 write_all (STDOUT_FILENO, pty_buffer, bytes);
823 if (should_read_new_subshell_prompt)
824 parse_subshell_prompt_string (pty_buffer, bytes);
827 else if (FD_ISSET (subshell_pipe[READ], &read_set))
828 /* Read the subshell's CWD and capture its prompt */
830 bytes = read (subshell_pipe[READ], subshell_cwd, sizeof (subshell_cwd));
831 if (bytes <= 0)
833 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
834 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n",
835 unix_error_string (errno));
836 exit (EXIT_FAILURE);
839 subshell_cwd[bytes - 1] = '\0'; /* Squash the final '\n' */
841 synchronize ();
843 clear_subshell_prompt_string ();
844 should_read_new_subshell_prompt = TRUE;
845 subshell_ready = TRUE;
846 if (subshell_state == RUNNING_COMMAND)
848 subshell_state = INACTIVE;
849 return TRUE;
853 else if (FD_ISSET (STDIN_FILENO, &read_set))
854 /* Read from stdin, write to the subshell */
856 should_read_new_subshell_prompt = FALSE;
857 bytes = read (STDIN_FILENO, pty_buffer, sizeof (pty_buffer));
858 if (bytes <= 0)
860 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
861 fprintf (stderr,
862 "read (STDIN_FILENO, pty_buffer...): %s\r\n", unix_error_string (errno));
863 exit (EXIT_FAILURE);
866 for (i = 0; i < bytes; ++i)
867 if (pty_buffer[i] == subshell_switch_key)
869 write_all (mc_global.tty.subshell_pty, pty_buffer, i);
871 if (subshell_ready)
873 subshell_state = INACTIVE;
874 set_prompt_string ();
875 if (subshell_ready && !read_command_line_buffer (FALSE))
877 /* If we got here, some unforeseen error must have occurred. */
878 if (mc_global.shell->type != SHELL_FISH)
880 write_all (mc_global.tty.subshell_pty, "\003", 1);
881 subshell_state = RUNNING_COMMAND;
882 if (feed_subshell (QUIETLY, TRUE))
883 if (read_command_line_buffer (FALSE))
884 return TRUE;
886 subshell_state = ACTIVE;
887 flush_subshell (0, VISIBLY);
888 input_assign_text (cmdline, "");
892 return TRUE;
895 write_all (mc_global.tty.subshell_pty, pty_buffer, bytes);
897 if (pty_buffer[bytes - 1] == '\n' || pty_buffer[bytes - 1] == '\r')
899 /* We should only clear the command line if we are using a shell that works
900 * with persistent command buffer, otherwise we get awkward results. */
901 if (use_persistent_buffer)
902 input_assign_text (cmdline, "");
903 subshell_ready = FALSE;
906 else
907 return FALSE;
911 /* --------------------------------------------------------------------------------------------- */
912 /* pty opening functions */
914 #ifndef HAVE_OPENPTY
916 #ifdef HAVE_GRANTPT
918 /* System V version of pty_open_master */
920 static int
921 pty_open_master (char *pty_name)
923 char *slave_name;
924 int pty_master;
926 #ifdef HAVE_POSIX_OPENPT
927 pty_master = posix_openpt (O_RDWR);
928 #elif defined HAVE_GETPT
929 /* getpt () is a GNU extension (glibc 2.1.x) */
930 pty_master = getpt ();
931 #elif defined IS_AIX
932 strcpy (pty_name, "/dev/ptc");
933 pty_master = open (pty_name, O_RDWR);
934 #else
935 strcpy (pty_name, "/dev/ptmx");
936 pty_master = open (pty_name, O_RDWR);
937 #endif
939 if (pty_master == -1)
940 return -1;
942 if (grantpt (pty_master) == -1 /* Grant access to slave */
943 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
944 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
946 close (pty_master);
947 return -1;
949 strcpy (pty_name, slave_name);
950 return pty_master;
953 /* --------------------------------------------------------------------------------------------- */
954 /** System V version of pty_open_slave */
956 static int
957 pty_open_slave (const char *pty_name)
959 int pty_slave;
961 pty_slave = open (pty_name, O_RDWR);
962 if (pty_slave == -1)
964 fprintf (stderr, "open (%s, O_RDWR): %s\r\n", pty_name, unix_error_string (errno));
965 return -1;
967 #if !defined(__osf__) && !defined(__linux__)
968 #if defined (I_FIND) && defined (I_PUSH)
969 if (ioctl (pty_slave, I_FIND, "ptem") == 0)
970 if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
972 fprintf (stderr, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
973 pty_slave, unix_error_string (errno));
974 close (pty_slave);
975 return -1;
978 if (ioctl (pty_slave, I_FIND, "ldterm") == 0)
979 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
981 fprintf (stderr,
982 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
983 pty_slave, unix_error_string (errno));
984 close (pty_slave);
985 return -1;
987 #if !defined(sgi) && !defined(__sgi)
988 if (ioctl (pty_slave, I_FIND, "ttcompat") == 0)
989 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
991 fprintf (stderr,
992 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
993 pty_slave, unix_error_string (errno));
994 close (pty_slave);
995 return -1;
997 #endif /* sgi || __sgi */
998 #endif /* I_FIND && I_PUSH */
999 #endif /* __osf__ || __linux__ */
1001 fcntl (pty_slave, F_SETFD, FD_CLOEXEC);
1002 return pty_slave;
1005 #else /* !HAVE_GRANTPT */
1007 /* --------------------------------------------------------------------------------------------- */
1008 /** BSD version of pty_open_master */
1009 static int
1010 pty_open_master (char *pty_name)
1012 int pty_master;
1013 const char *ptr1, *ptr2;
1015 strcpy (pty_name, "/dev/ptyXX");
1016 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1018 pty_name[8] = *ptr1;
1019 for (ptr2 = "0123456789abcdef"; *ptr2 != '\0'; ++ptr2)
1021 pty_name[9] = *ptr2;
1023 /* Try to open master */
1024 pty_master = open (pty_name, O_RDWR);
1025 if (pty_master == -1)
1027 if (errno == ENOENT) /* Different from EIO */
1028 return -1; /* Out of pty devices */
1029 continue; /* Try next pty device */
1031 pty_name[5] = 't'; /* Change "pty" to "tty" */
1032 if (access (pty_name, 6) != 0)
1034 close (pty_master);
1035 pty_name[5] = 'p';
1036 continue;
1038 return pty_master;
1041 return -1; /* Ran out of pty devices */
1044 /* --------------------------------------------------------------------------------------------- */
1045 /** BSD version of pty_open_slave */
1047 static int
1048 pty_open_slave (const char *pty_name)
1050 int pty_slave;
1051 struct group *group_info;
1053 group_info = getgrnam ("tty");
1054 if (group_info != NULL)
1056 /* The following two calls will only succeed if we are root */
1057 /* [Commented out while permissions problem is investigated] */
1058 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1059 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1061 pty_slave = open (pty_name, O_RDWR);
1062 if (pty_slave == -1)
1063 fprintf (stderr, "open (pty_name, O_RDWR): %s\r\n", pty_name);
1064 fcntl (pty_slave, F_SETFD, FD_CLOEXEC);
1065 return pty_slave;
1067 #endif /* !HAVE_GRANTPT */
1069 #endif /* !HAVE_OPENPTY */
1071 /* --------------------------------------------------------------------------------------------- */
1073 * Set up `precmd' or equivalent for reading the subshell's CWD.
1075 * Attention! Never forget that these are *one-liners* even though the concatenated
1076 * substrings contain line breaks and indentation for better understanding of the
1077 * shell code. It is vital that each one-liner ends with a line feed character ("\n" ).
1079 * @return initialized pre-command string
1082 static void
1083 init_subshell_precmd (char *precmd, size_t buff_size)
1085 switch (mc_global.shell->type)
1087 case SHELL_BASH:
1088 g_snprintf (precmd, buff_size,
1089 " mc_print_command_buffer () { printf \"%%s\\\\n\" \"$READLINE_LINE\" >&%d; }\n"
1090 " bind -x '\"\\e" SHELL_BUFFER_KEYBINDING "\":\"mc_print_command_buffer\"'\n"
1091 " bind -x '\"\\e" SHELL_CURSOR_KEYBINDING
1092 "\":\"echo $BASH_VERSINFO:$READLINE_POINT >&%d\"'\n"
1093 " PROMPT_COMMAND=${PROMPT_COMMAND:+$PROMPT_COMMAND\n}'pwd>&%d;kill -STOP $$'\n"
1094 "PS1='\\u@\\h:\\w\\$ '\n", command_buffer_pipe[WRITE],
1095 command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1096 break;
1098 case SHELL_ASH_BUSYBOX:
1099 /* BusyBox ash needs a somewhat complicated precmd emulation via PS1, and it is vital
1100 * that BB be built with active CONFIG_ASH_EXPAND_PRMT, but this is the default anyway.
1102 * A: This leads to a stopped subshell (=frozen mc) if user calls "ash" command
1103 * "PS1='$(pwd>&%d; kill -STOP $$)\\u@\\h:\\w\\$ '\n",
1105 * B: This leads to "sh: precmd: not found" in sub-subshell if user calls "ash" command
1106 * "precmd() { pwd>&%d; kill -STOP $$; }; "
1107 * "PS1='$(precmd)\\u@\\h:\\w\\$ '\n",
1109 * C: This works if user calls "ash" command because in sub-subshell
1110 * PRECMD is undefined, thus evaluated to empty string - no damage done.
1111 * Attention: BusyBox must be built with FEATURE_EDITING_FANCY_PROMPT to
1112 * permit \u, \w, \h, \$ escape sequences. Unfortunately this cannot be guaranteed,
1113 * especially on embedded systems where people try to save space, so let's use
1114 * the dash version below. It should work on virtually all systems.
1115 * "precmd() { pwd>&%d; kill -STOP $$; }; "
1116 * "PRECMD=precmd; "
1117 * "PS1='$(eval $PRECMD)\\u@\\h:\\w\\$ '\n",
1119 case SHELL_DASH:
1120 /* Debian ash needs a precmd emulation via PS1, similar to BusyBox ash,
1121 * but does not support escape sequences for user, host and cwd in prompt.
1122 * Attention! Make sure that the buffer for precmd is big enough.
1124 * We want to have a fancy dynamic prompt with user@host:cwd just like in the BusyBox
1125 * examples above, but because replacing the home directory part of the path by "~" is
1126 * complicated, it bloats the precmd to a size > BUF_SMALL (128).
1128 * The following example is a little less fancy (home directory not replaced)
1129 * and shows the basic workings of our prompt for easier understanding:
1131 * "precmd() { "
1132 * "echo \"$USER@$(hostname -s):$PWD\"; "
1133 * "pwd>&%d; "
1134 * "kill -STOP $$; "
1135 * "}; "
1136 * "PRECMD=precmd; "
1137 * "PS1='$($PRECMD)$ '\n",
1139 g_snprintf (precmd, buff_size,
1140 "precmd() { "
1141 "if [ ! \"${PWD##$HOME}\" ]; then "
1142 "MC_PWD=\"~\"; "
1143 "else "
1144 "[ \"${PWD##$HOME/}\" = \"$PWD\" ] && MC_PWD=\"$PWD\" || MC_PWD=\"~/${PWD##$HOME/}\"; "
1145 "fi; "
1146 "echo \"$USER@$(hostname -s):$MC_PWD\"; "
1147 "pwd>&%d; "
1148 "kill -STOP $$; "
1149 "}; " "PRECMD=precmd; " "PS1='$($PRECMD)$ '\n", subshell_pipe[WRITE]);
1150 break;
1152 case SHELL_ZSH:
1153 g_snprintf (precmd, buff_size,
1154 " mc_print_command_buffer () { printf \"%%s\\\\n\" \"$BUFFER\" >&%d; }\n"
1155 " zle -N mc_print_command_buffer\n"
1156 " bindkey '^[" SHELL_BUFFER_KEYBINDING "' mc_print_command_buffer\n"
1157 " mc_print_cursor_position () { echo $CURSOR >&%d}\n"
1158 " zle -N mc_print_cursor_position\n"
1159 " bindkey '^[" SHELL_CURSOR_KEYBINDING "' mc_print_cursor_position\n"
1160 " _mc_precmd(){ pwd>&%d;kill -STOP $$ }; precmd_functions+=(_mc_precmd)\n"
1161 "PS1='%%n@%%m:%%~%%# '\n",
1162 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1163 break;
1165 case SHELL_TCSH:
1166 g_snprintf (precmd, buff_size,
1167 "set echo_style=both; "
1168 "set prompt='%%n@%%m:%%~%%# '; "
1169 "alias precmd 'echo -n;echo $cwd:q >>%s; kill -STOP $$'\n", tcsh_fifo);
1170 break;
1171 case SHELL_FISH:
1172 g_snprintf (precmd, buff_size,
1173 " bind \\e" SHELL_BUFFER_KEYBINDING " 'commandline >&%d';"
1174 "bind \\e" SHELL_CURSOR_KEYBINDING " 'commandline -C >&%d';"
1175 "if not functions -q fish_prompt_mc;"
1176 "functions -e fish_right_prompt;"
1177 "functions -c fish_prompt fish_prompt_mc; end;"
1178 "function fish_prompt;"
1179 "echo \"$PWD\">&%d; fish_prompt_mc; kill -STOP %%self; end\n",
1180 command_buffer_pipe[WRITE], command_buffer_pipe[WRITE], subshell_pipe[WRITE]);
1181 break;
1183 default:
1184 break;
1188 /* --------------------------------------------------------------------------------------------- */
1190 * Carefully quote directory name to allow entering any directory safely,
1191 * no matter what weird characters it may contain in its name.
1192 * NOTE: Treat directory name an untrusted data, don't allow it to cause
1193 * executing any commands in the shell. Escape all control characters.
1194 * Use following technique:
1196 * printf(1) with format string containing a single conversion specifier,
1197 * "b", and an argument which contains a copy of the string passed to
1198 * subshell_name_quote() with all characters, except digits and letters,
1199 * replaced by the backslash-escape sequence \0nnn, where "nnn" is the
1200 * numeric value of the character converted to octal number.
1202 * cd "`printf '%b' 'ABC\0nnnDEF\0nnnXYZ'`"
1204 * N.B.: Use single quotes for conversion specifier to work around
1205 * tcsh 6.20+ parser breakage, see ticket #3852 for the details.
1208 static GString *
1209 subshell_name_quote (const char *s)
1211 GString *ret;
1212 const char *su, *n;
1213 const char *quote_cmd_start, *quote_cmd_end;
1215 if (mc_global.shell->type == SHELL_FISH)
1217 quote_cmd_start = "(printf '%b' '";
1218 quote_cmd_end = "')";
1220 /* TODO: When BusyBox printf is fixed, get rid of this "else if", see
1221 http://lists.busybox.net/pipermail/busybox/2012-March/077460.html */
1222 /* else if (subshell_type == ASH_BUSYBOX)
1224 quote_cmd_start = "\"`echo -en '";
1225 quote_cmd_end = "'`\"";
1226 } */
1227 else
1229 quote_cmd_start = "\"`printf '%b' '";
1230 quote_cmd_end = "'`\"";
1233 ret = g_string_sized_new (64);
1235 /* Prevent interpreting leading '-' as a switch for 'cd' */
1236 if (s[0] == '-')
1237 g_string_append (ret, "./");
1239 /* Copy the beginning of the command to the buffer */
1240 g_string_append (ret, quote_cmd_start);
1243 * Print every character except digits and letters as a backslash-escape
1244 * sequence of the form \0nnn, where "nnn" is the numeric value of the
1245 * character converted to octal number.
1247 for (su = s; su[0] != '\0'; su = n)
1249 n = str_cget_next_char_safe (su);
1251 if (str_isalnum (su))
1252 g_string_append_len (ret, su, n - su);
1253 else
1255 int c;
1257 for (c = 0; c < n - su; c++)
1258 g_string_append_printf (ret, "\\0%03o", (unsigned char) su[c]);
1262 g_string_append (ret, quote_cmd_end);
1264 return ret;
1267 /* --------------------------------------------------------------------------------------------- */
1269 * This function checks the pipe from which we receive data about the current working directory.
1270 * If there is any data waiting, we clear it.
1273 static void
1274 clear_cwd_pipe (void)
1276 fd_set read_set;
1277 struct timeval wtime = { 0, 0 };
1278 int maxfdp;
1280 FD_ZERO (&read_set);
1281 FD_SET (subshell_pipe[READ], &read_set);
1282 maxfdp = subshell_pipe[READ];
1284 if (select (maxfdp + 1, &read_set, NULL, NULL, &wtime) > 0
1285 && FD_ISSET (subshell_pipe[READ], &read_set))
1287 if (read (subshell_pipe[READ], subshell_cwd, sizeof (subshell_cwd)) <= 0)
1289 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1290 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n", unix_error_string (errno));
1291 exit (EXIT_FAILURE);
1294 synchronize ();
1298 /* --------------------------------------------------------------------------------------------- */
1299 /*** public functions ****************************************************************************/
1300 /* --------------------------------------------------------------------------------------------- */
1302 /* --------------------------------------------------------------------------------------------- */
1304 * Fork the subshell, and set up many, many things.
1306 * Possibly modifies the global variables:
1307 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
1308 * mc_global.tty.use_subshell - Is set to FALSE if we can't run the subshell
1309 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
1312 void
1313 init_subshell (void)
1315 /* This must be remembered across calls to init_subshell() */
1316 static char pty_name[BUF_SMALL];
1317 /* Must be considerably longer than BUF_SMALL (128) to support fancy shell prompts */
1318 char precmd[BUF_MEDIUM];
1320 /* Take the current (hopefully pristine) tty mode and make */
1321 /* a raw mode based on it now, before we do anything else with it */
1322 init_raw_mode ();
1324 if (mc_global.tty.subshell_pty == 0)
1325 { /* First time through */
1326 if (mc_global.shell->type == SHELL_NONE)
1327 return;
1329 /* Open a pty for talking to the subshell */
1331 /* FIXME: We may need to open a fresh pty each time on SVR4 */
1333 #ifdef HAVE_OPENPTY
1334 if (openpty (&mc_global.tty.subshell_pty, &subshell_pty_slave, NULL, NULL, NULL))
1336 fprintf (stderr, "Cannot open master and slave sides of pty: %s\n",
1337 unix_error_string (errno));
1338 mc_global.tty.use_subshell = FALSE;
1339 return;
1341 #else
1342 mc_global.tty.subshell_pty = pty_open_master (pty_name);
1343 if (mc_global.tty.subshell_pty == -1)
1345 fprintf (stderr, "Cannot open master side of pty: %s\r\n", unix_error_string (errno));
1346 mc_global.tty.use_subshell = FALSE;
1347 return;
1349 subshell_pty_slave = pty_open_slave (pty_name);
1350 if (subshell_pty_slave == -1)
1352 fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
1353 pty_name, unix_error_string (errno));
1354 mc_global.tty.use_subshell = FALSE;
1355 return;
1357 #endif /* HAVE_OPENPTY */
1359 /* Create a pipe for receiving the subshell's CWD */
1361 if (mc_global.shell->type == SHELL_TCSH)
1363 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
1364 mc_tmpdir (), (int) getpid ());
1365 if (mkfifo (tcsh_fifo, 0600) == -1)
1367 fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo, unix_error_string (errno));
1368 mc_global.tty.use_subshell = FALSE;
1369 return;
1372 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
1374 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
1375 || (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
1377 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
1378 perror (__FILE__ ": open");
1379 mc_global.tty.use_subshell = FALSE;
1380 return;
1383 else if (pipe (subshell_pipe) != 0) /* subshell_type is BASH, ASH_BUSYBOX, DASH or ZSH */
1385 perror (__FILE__ ": couldn't create pipe");
1386 mc_global.tty.use_subshell = FALSE;
1387 return;
1390 if (mc_global.mc_run_mode == MC_RUN_FULL &&
1391 (mc_global.shell->type == SHELL_BASH || mc_global.shell->type == SHELL_ZSH
1392 || mc_global.shell->type == SHELL_FISH))
1393 use_persistent_buffer = TRUE;
1394 if (use_persistent_buffer && pipe (command_buffer_pipe) != 0)
1396 perror (__FILE__ ": couldn't create pipe");
1397 mc_global.tty.use_subshell = FALSE;
1398 return;
1402 /* Fork the subshell */
1404 subshell_alive = TRUE;
1405 subshell_stopped = FALSE;
1406 subshell_pid = fork ();
1408 if (subshell_pid == -1)
1410 fprintf (stderr, "Cannot spawn the subshell process: %s\r\n", unix_error_string (errno));
1411 /* We exit here because, if the process table is full, the */
1412 /* other method of running user commands won't work either */
1413 exit (EXIT_FAILURE);
1416 if (subshell_pid == 0)
1418 /* We are in the child process */
1419 init_subshell_child (pty_name);
1422 init_subshell_precmd (precmd, BUF_MEDIUM);
1424 write_all (mc_global.tty.subshell_pty, precmd, strlen (precmd));
1426 /* Wait until the subshell has started up and processed the command */
1428 subshell_state = RUNNING_COMMAND;
1429 tty_enable_interrupt_key ();
1430 if (!feed_subshell (QUIETLY, TRUE))
1431 mc_global.tty.use_subshell = FALSE;
1432 tty_disable_interrupt_key ();
1433 if (!subshell_alive)
1434 mc_global.tty.use_subshell = FALSE; /* Subshell died instantly, so don't use it */
1436 /* Try out the persistent command buffer feature. If it doesn't work the first time, we
1437 * assume there must be something wrong with the shell, and we turn persistent buffer off
1438 * for good. This will save the user the trouble of having to wait for the persistent
1439 * buffer function to time out every time they try to close the subshell. */
1440 if (use_persistent_buffer && !read_command_line_buffer (TRUE))
1441 use_persistent_buffer = FALSE;
1444 /* --------------------------------------------------------------------------------------------- */
1447 invoke_subshell (const char *command, int how, vfs_path_t **new_dir_vpath)
1449 /* Make the MC terminal transparent */
1450 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
1452 /* Make the subshell change to MC's working directory */
1453 if (new_dir_vpath != NULL)
1454 do_subshell_chdir (subshell_get_cwd (), TRUE);
1456 if (command == NULL) /* The user has done "C-o" from MC */
1458 if (subshell_state == INACTIVE)
1460 subshell_state = ACTIVE;
1462 /* FIXME: possibly take out this hack; the user can re-play it by hitting C-hyphen a few times! */
1463 if (subshell_ready && mc_global.mc_run_mode == MC_RUN_FULL)
1464 write_all (mc_global.tty.subshell_pty, " \b", 2); /* Hack to make prompt reappear */
1466 if (use_persistent_buffer)
1468 const char *s;
1469 size_t i;
1470 int pos;
1472 s = input_get_ctext (cmdline);
1474 /* Check to make sure there are no non text characters in the command buffer,
1475 * such as tab, or newline, as this could cause problems. */
1476 for (i = 0; i < cmdline->buffer->len; i++)
1477 if ((unsigned char) s[i] < 32 || (unsigned char) s[i] == 127)
1478 g_string_overwrite_len (cmdline->buffer, i, " ", 1);
1480 /* Write the command buffer to the subshell. */
1481 write_all (mc_global.tty.subshell_pty, s, cmdline->buffer->len);
1483 /* Put the cursor in the correct place in the subshell. */
1484 pos = str_length (s) - cmdline->point;
1485 for (i = 0; i < (size_t) pos; i++)
1486 write_all (mc_global.tty.subshell_pty, ESC_STR "[D", 3);
1490 else /* MC has passed us a user command */
1492 /* Before we write to the command prompt, we need to clear whatever */
1493 /* data is there, but only if we are using one of the shells that */
1494 /* doesn't support keeping command buffer contents, OR if there was */
1495 /* some sort of error. */
1496 if (use_persistent_buffer)
1497 clear_cwd_pipe ();
1498 else
1500 /* We don't need to call feed_subshell here if we are using fish, because of a
1501 * quirk in the behavior of that particular shell. */
1502 if (mc_global.shell->type != SHELL_FISH)
1504 write_all (mc_global.tty.subshell_pty, "\003", 1);
1505 subshell_state = RUNNING_COMMAND;
1506 feed_subshell (QUIETLY, FALSE);
1510 if (how == QUIETLY)
1511 write_all (mc_global.tty.subshell_pty, " ", 1);
1512 /* FIXME: if command is long (>8KB ?) we go comma */
1513 write_all (mc_global.tty.subshell_pty, command, strlen (command));
1514 write_all (mc_global.tty.subshell_pty, "\n", 1);
1515 subshell_state = RUNNING_COMMAND;
1516 subshell_ready = FALSE;
1519 feed_subshell (how, FALSE);
1521 if (new_dir_vpath != NULL && subshell_alive)
1523 const char *pcwd;
1525 pcwd = vfs_translate_path (vfs_path_as_str (subshell_get_cwd ()));
1526 if (strcmp (subshell_cwd, pcwd) != 0)
1527 *new_dir_vpath = vfs_path_from_str (subshell_cwd); /* Make MC change to the subshell's CWD */
1530 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
1531 while (!subshell_alive && subshell_get_mainloop_quit () == 0 && mc_global.tty.use_subshell)
1532 init_subshell ();
1534 return subshell_get_mainloop_quit ();
1537 /* --------------------------------------------------------------------------------------------- */
1539 gboolean
1540 flush_subshell (int max_wait_length, int how)
1542 int rc = 0;
1543 ssize_t bytes = 0;
1544 struct timeval timeleft = { 0, 0 };
1545 gboolean return_value = FALSE;
1546 fd_set tmp;
1548 timeleft.tv_sec = max_wait_length;
1549 FD_ZERO (&tmp);
1550 FD_SET (mc_global.tty.subshell_pty, &tmp);
1552 while (subshell_alive
1553 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0)
1555 /* Check for 'select' errors */
1556 if (rc == -1)
1558 if (errno == EINTR)
1560 if (tty_got_winch ())
1561 tty_change_screen_size ();
1563 continue;
1566 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno));
1567 exit (EXIT_FAILURE);
1570 return_value = TRUE;
1571 timeleft.tv_sec = 0;
1572 timeleft.tv_usec = 0;
1574 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
1575 if (how == VISIBLY)
1576 write_all (STDOUT_FILENO, pty_buffer, bytes);
1579 return return_value;
1582 /* --------------------------------------------------------------------------------------------- */
1584 gboolean
1585 read_subshell_prompt (void)
1587 int rc = 0;
1588 ssize_t bytes = 0;
1589 struct timeval timeleft = { 0, 0 };
1590 gboolean got_new_prompt = FALSE;
1592 fd_set tmp;
1593 FD_ZERO (&tmp);
1594 FD_SET (mc_global.tty.subshell_pty, &tmp);
1596 while (subshell_alive
1597 && (rc = select (mc_global.tty.subshell_pty + 1, &tmp, NULL, NULL, &timeleft)) != 0)
1599 /* Check for 'select' errors */
1600 if (rc == -1)
1602 if (errno == EINTR)
1604 if (tty_got_winch ())
1605 tty_change_screen_size ();
1607 continue;
1610 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n", unix_error_string (errno));
1611 exit (EXIT_FAILURE);
1614 bytes = read (mc_global.tty.subshell_pty, pty_buffer, sizeof (pty_buffer));
1616 parse_subshell_prompt_string (pty_buffer, bytes);
1617 got_new_prompt = TRUE;
1620 if (got_new_prompt)
1621 set_prompt_string ();
1623 return (rc != 0 || bytes != 0);
1626 /* --------------------------------------------------------------------------------------------- */
1628 void
1629 do_update_prompt (void)
1631 if (update_subshell_prompt)
1633 if (subshell_prompt != NULL)
1635 printf ("\r\n%s", subshell_prompt->str);
1636 fflush (stdout);
1638 update_subshell_prompt = FALSE;
1642 /* --------------------------------------------------------------------------------------------- */
1644 gboolean
1645 exit_subshell (void)
1647 gboolean subshell_quit = TRUE;
1649 if (subshell_state != INACTIVE && subshell_alive)
1650 subshell_quit =
1651 query_dialog (_("Warning"),
1652 _("The shell is still active. Quit anyway?"),
1653 D_NORMAL, 2, _("&Yes"), _("&No")) == 0;
1655 if (subshell_quit)
1657 if (mc_global.shell->type == SHELL_TCSH)
1659 if (unlink (tcsh_fifo) == -1)
1660 fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
1661 tcsh_fifo, unix_error_string (errno));
1664 if (subshell_prompt != NULL)
1666 g_string_free (subshell_prompt, TRUE);
1667 subshell_prompt = NULL;
1670 if (subshell_prompt_temp_buffer != NULL)
1672 g_string_free (subshell_prompt_temp_buffer, TRUE);
1673 subshell_prompt_temp_buffer = NULL;
1676 pty_buffer[0] = '\0';
1679 return subshell_quit;
1682 /* --------------------------------------------------------------------------------------------- */
1684 /** If it actually changed the directory it returns true */
1685 void
1686 do_subshell_chdir (const vfs_path_t *vpath, gboolean update_prompt)
1688 char *pcwd;
1690 pcwd = vfs_path_to_str_flags (subshell_get_cwd (), 0, VPF_RECODE);
1692 if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, pcwd) != 0))
1694 /* We have to repaint the subshell prompt if we read it from
1695 * the main program. Please note that in the code after this
1696 * if, the cd command that is sent will make the subshell
1697 * repaint the prompt, so we don't have to paint it. */
1698 if (update_prompt)
1699 do_update_prompt ();
1700 g_free (pcwd);
1701 return;
1704 /* If we are using a shell that doesn't support persistent command buffer, we need to clear
1705 * the command prompt before we send the cd command. */
1706 if (!use_persistent_buffer)
1708 write_all (mc_global.tty.subshell_pty, "\003", 1);
1709 subshell_state = RUNNING_COMMAND;
1710 if (mc_global.shell->type != SHELL_FISH)
1711 if (!feed_subshell (QUIETLY, TRUE))
1713 subshell_state = ACTIVE;
1714 return;
1718 /* A quick and dirty fix for fish shell. For some reason, fish does not
1719 * execute all the commands sent to it from Midnight Commander :(
1720 * An example of such buggy behavior is presented in ticket #4521.
1721 * TODO: Find the real cause and fix it "the right way" */
1722 if (mc_global.shell->type == SHELL_FISH)
1724 write_all (mc_global.tty.subshell_pty, "\n", 1);
1725 subshell_state = RUNNING_COMMAND;
1726 feed_subshell (QUIETLY, TRUE);
1729 /* The initial space keeps this out of the command history (in bash
1730 because we set "HISTCONTROL=ignorespace") */
1731 write_all (mc_global.tty.subshell_pty, " cd ", 4);
1733 if (vpath == NULL)
1734 write_all (mc_global.tty.subshell_pty, "/", 1);
1735 else
1737 const char *translate;
1739 translate = vfs_translate_path (vfs_path_as_str (vpath));
1740 if (translate == NULL)
1741 write_all (mc_global.tty.subshell_pty, ".", 1);
1742 else
1744 GString *temp;
1746 temp = subshell_name_quote (translate);
1747 write_all (mc_global.tty.subshell_pty, temp->str, temp->len);
1748 g_string_free (temp, TRUE);
1752 write_all (mc_global.tty.subshell_pty, "\n", 1);
1754 subshell_state = RUNNING_COMMAND;
1755 if (!feed_subshell (QUIETLY, TRUE))
1757 subshell_state = ACTIVE;
1758 return;
1761 if (subshell_alive)
1763 gboolean bPathNotEq;
1765 bPathNotEq = strcmp (subshell_cwd, pcwd) != 0;
1767 if (bPathNotEq && mc_global.shell->type == SHELL_TCSH)
1769 char rp_subshell_cwd[PATH_MAX];
1770 char rp_current_panel_cwd[PATH_MAX];
1771 char *p_subshell_cwd, *p_current_panel_cwd;
1773 p_subshell_cwd = mc_realpath (subshell_cwd, rp_subshell_cwd);
1774 p_current_panel_cwd = mc_realpath (pcwd, rp_current_panel_cwd);
1776 if (p_subshell_cwd == NULL)
1777 p_subshell_cwd = subshell_cwd;
1778 if (p_current_panel_cwd == NULL)
1779 p_current_panel_cwd = pcwd;
1780 bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd) != 0;
1783 if (bPathNotEq && !DIR_IS_DOT (pcwd))
1785 char *cwd;
1787 cwd = vfs_path_to_str_flags (subshell_get_cwd (), 0, VPF_STRIP_PASSWORD);
1788 vfs_print_message (_("Warning: Cannot change to %s.\n"), cwd);
1789 g_free (cwd);
1793 /* Really escape Zsh/Fish history */
1794 if (mc_global.shell->type == SHELL_ZSH || mc_global.shell->type == SHELL_FISH)
1796 /* Per Zsh documentation last command prefixed with space lingers in the internal history
1797 * until the next command is entered before it vanishes. To make it vanish right away,
1798 * type a space and press return.
1800 * Fish shell now also provides the same behavior:
1801 * https://github.com/fish-shell/fish-shell/commit/9fdc4f903b8b421b18389a0f290d72cc88c128bb
1802 * */
1803 write_all (mc_global.tty.subshell_pty, " \n", 2);
1804 subshell_state = RUNNING_COMMAND;
1805 feed_subshell (QUIETLY, TRUE);
1808 update_subshell_prompt = FALSE;
1810 g_free (pcwd);
1811 /* Make sure that MC never stores the CWD in a silly format */
1812 /* like /usr////lib/../bin, or the strcmp() above will fail */
1815 /* --------------------------------------------------------------------------------------------- */
1817 void
1818 subshell_get_console_attributes (void)
1820 /* Get our current terminal modes */
1822 if (tcgetattr (STDOUT_FILENO, &shell_mode))
1824 fprintf (stderr, "Cannot get terminal settings: %s\r\n", unix_error_string (errno));
1825 mc_global.tty.use_subshell = FALSE;
1829 /* --------------------------------------------------------------------------------------------- */
1831 * Figure out whether the subshell has stopped, exited or been killed
1832 * Possibly modifies: 'subshell_alive', 'subshell_stopped' and 'quit' */
1834 void
1835 sigchld_handler (int sig)
1837 int status;
1838 pid_t pid;
1840 (void) sig;
1842 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
1844 if (pid == subshell_pid)
1846 /* Figure out what has happened to the subshell */
1848 if (WIFSTOPPED (status))
1850 if (WSTOPSIG (status) == SIGSTOP)
1852 /* The subshell has received a SIGSTOP signal */
1853 subshell_stopped = TRUE;
1855 else
1857 /* The user has suspended the subshell. Revive it */
1858 kill (subshell_pid, SIGCONT);
1861 else
1863 /* The subshell has either exited normally or been killed */
1864 subshell_alive = FALSE;
1865 delete_select_channel (mc_global.tty.subshell_pty);
1866 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
1868 int subshell_quit;
1869 subshell_quit = subshell_get_mainloop_quit () | SUBSHELL_EXIT; /* Exited normally */
1870 subshell_set_mainloop_quit (subshell_quit);
1874 subshell_handle_cons_saver ();
1876 /* If we got here, some other child exited; ignore it */
1879 /* --------------------------------------------------------------------------------------------- */