Reorganization of sources. Part 2
[midnight-commander.git] / src / subshell.c
blob22c1c6f4510917fa023fdd889afbf560efa2ac4b
1 /* Concurrent shell support for the Midnight Commander
2 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of Version 2 of the GNU General Public
7 License, as published by the Free Software Foundation.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 /** \file subshell.c
20 * \brief Source: concurrent shell support
23 #include <config.h>
25 #ifdef HAVE_SUBSHELL_SUPPORT
27 #ifndef _GNU_SOURCE
28 # define _GNU_SOURCE 1
29 #endif
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <string.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #include <sys/types.h>
39 #include <sys/wait.h>
40 #ifdef HAVE_SYS_IOCTL_H
41 # include <sys/ioctl.h>
42 #endif
43 #include <termios.h>
44 #include <unistd.h>
46 #ifdef HAVE_STROPTS_H
47 # include <stropts.h> /* For I_PUSH */
48 #endif /* HAVE_STROPTS_H */
50 #include "lib/global.h"
51 #include "lib/tty/tty.h" /* LINES */
52 #include "panel.h" /* current_panel */
53 #include "wtools.h" /* query_dialog() */
54 #include "main.h" /* do_update_prompt() */
55 #include "cons.saver.h" /* handle_console() */
56 #include "lib/tty/key.h" /* XCTRL */
57 #include "subshell.h"
58 #include "strutil.h"
60 #include "lib/vfs/mc-vfs/vfs.h"
62 #ifndef WEXITSTATUS
63 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
64 #endif
66 #ifndef WIFEXITED
67 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
68 #endif
70 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
71 static char tcsh_fifo[128];
73 /* Local functions */
74 static void init_raw_mode (void);
75 static int feed_subshell (int how, int fail_on_error);
76 static void synchronize (void);
77 static int pty_open_master (char *pty_name);
78 static int pty_open_slave (const char *pty_name);
79 static int resize_tty (int fd);
81 #ifndef STDIN_FILENO
82 # define STDIN_FILENO 0
83 #endif
85 #ifndef STDOUT_FILENO
86 # define STDOUT_FILENO 1
87 #endif
89 #ifndef STDERR_FILENO
90 # define STDERR_FILENO 2
91 #endif
93 /* If using a subshell for evaluating commands this is true */
94 int use_subshell =
95 #ifdef SUBSHELL_OPTIONAL
96 FALSE;
97 #else
98 TRUE;
99 #endif
101 /* File descriptors of the pseudoterminal used by the subshell */
102 int subshell_pty = 0;
103 static int subshell_pty_slave = -1;
105 /* The key for switching back to MC from the subshell */
106 static const char subshell_switch_key = XCTRL('o') & 255;
108 /* State of the subshell:
109 * INACTIVE: the default state; awaiting a command
110 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
111 * RUNNING_COMMAND: return to MC when the current command finishes */
112 enum subshell_state_enum subshell_state;
114 /* Holds the latest prompt captured from the subshell */
115 char *subshell_prompt = NULL;
117 /* Initial length of the buffer for the subshell's prompt */
118 #define INITIAL_PROMPT_SIZE 10
120 /* Used by the child process to indicate failure to start the subshell */
121 #define FORK_FAILURE 69 /* Arbitrary */
123 /* Initial length of the buffer for all I/O with the subshell */
124 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
126 /* For pipes */
127 enum {READ=0, WRITE=1};
129 static char *pty_buffer; /* For reading/writing on the subshell's pty */
130 static int pty_buffer_size; /* The buffer grows as needed */
131 static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
132 static pid_t subshell_pid = 1; /* The subshell's process ID */
133 static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
135 /* Subshell type (gleaned from the SHELL environment variable, if available) */
136 static enum {
137 BASH,
138 TCSH,
139 ZSH,
140 FISH
141 } subshell_type;
143 /* Flag to indicate whether the subshell is ready for next command */
144 static int subshell_ready;
146 /* The following two flags can be changed by the SIGCHLD handler. This is */
147 /* OK, because the `int' type is updated atomically on all known machines */
148 static volatile int subshell_alive, subshell_stopped;
150 /* We store the terminal's initial mode here so that we can configure
151 the pty similarly, and also so we can restore the real terminal to
152 sanity if we have to exit abruptly */
153 static struct termios shell_mode;
155 /* This is a transparent mode for the terminal where MC is running on */
156 /* It is used when the shell is active, so that the control signals */
157 /* are delivered to the shell pty */
158 static struct termios raw_mode;
160 /* This counter indicates how many characters of prompt we have read */
161 /* FIXME: try to figure out why this had to become global */
162 static int prompt_pos;
166 * Write all data, even if the write() call is interrupted.
168 static ssize_t
169 write_all (int fd, const void *buf, size_t count)
171 ssize_t ret;
172 ssize_t written = 0;
173 while (count > 0) {
174 ret = write (fd, (const unsigned char *) buf + written, count);
175 if (ret < 0) {
176 if (errno == EINTR) {
177 continue;
178 } else {
179 return written > 0 ? written : ret;
182 count -= ret;
183 written += ret;
185 return written;
189 * Prepare child process to running the shell and run it.
191 * Modifies the global variables (in the child process only):
192 * shell_mode
194 * Returns: never.
196 static void
197 init_subshell_child (const char *pty_name)
199 const char *init_file = NULL;
200 pid_t mc_sid;
202 (void) pty_name;
203 setsid (); /* Get a fresh terminal session */
205 /* Make sure that it has become our controlling terminal */
207 /* Redundant on Linux and probably most systems, but just in case: */
209 #ifdef TIOCSCTTY
210 ioctl (subshell_pty_slave, TIOCSCTTY, 0);
211 #endif
213 /* Configure its terminal modes and window size */
215 /* Set up the pty with the same termios flags as our own tty */
216 if (tcsetattr (subshell_pty_slave, TCSANOW, &shell_mode)) {
217 fprintf (stderr, "Cannot set pty terminal modes: %s\r\n",
218 unix_error_string (errno));
219 _exit (FORK_FAILURE);
222 /* Set the pty's size (80x25 by default on Linux) according to the */
223 /* size of the real terminal as calculated by ncurses, if possible */
224 resize_tty (subshell_pty_slave);
226 /* Set up the subshell's environment and init file name */
228 /* It simplifies things to change to our home directory here, */
229 /* and the user's startup file may do a `cd' command anyway */
230 chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
232 /* Set MC_SID to prevent running one mc from another */
233 mc_sid = getsid (0);
234 if (mc_sid != -1) {
235 char sid_str[BUF_SMALL];
236 g_snprintf (sid_str, sizeof (sid_str), "MC_SID=%ld",
237 (long) mc_sid);
238 putenv (g_strdup (sid_str));
241 switch (subshell_type) {
242 case BASH:
243 init_file = MC_USERCONF_DIR PATH_SEP_STR "bashrc";
244 if (access (init_file, R_OK) == -1)
245 init_file = ".bashrc";
247 /* Make MC's special commands not show up in bash's history */
248 putenv ((char*)"HISTCONTROL=ignorespace");
250 /* Allow alternative readline settings for MC */
251 if (access (MC_USERCONF_DIR PATH_SEP_STR "inputrc", R_OK) == 0)
252 putenv ((char*)"INPUTRC=" MC_USERCONF_DIR PATH_SEP_STR "/inputrc");
254 break;
256 /* TODO: Find a way to pass initfile to TCSH and ZSH */
257 case TCSH:
258 case ZSH:
259 case FISH:
260 break;
262 default:
263 fprintf (stderr, __FILE__ ": unimplemented subshell type %d\r\n",
264 subshell_type);
265 _exit (FORK_FAILURE);
268 /* Attach all our standard file descriptors to the pty */
270 /* This is done just before the fork, because stderr must still */
271 /* be connected to the real tty during the above error messages; */
272 /* otherwise the user will never see them. */
274 dup2 (subshell_pty_slave, STDIN_FILENO);
275 dup2 (subshell_pty_slave, STDOUT_FILENO);
276 dup2 (subshell_pty_slave, STDERR_FILENO);
278 close (subshell_pipe[READ]);
279 close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */
280 /* Close master side of pty. This is important; apart from */
281 /* freeing up the descriptor for use in the subshell, it also */
282 /* means that when MC exits, the subshell will get a SIGHUP and */
283 /* exit too, because there will be no more descriptors pointing */
284 /* at the master side of the pty and so it will disappear. */
285 close (subshell_pty);
287 /* Execute the subshell at last */
289 switch (subshell_type) {
290 case BASH:
291 execl (shell, "bash", "-rcfile", init_file, (char *) NULL);
292 break;
294 case TCSH:
295 execl (shell, "tcsh", (char *) NULL);
296 break;
298 case ZSH:
299 /* Use -g to exclude cmds beginning with space from history
300 * and -Z to use the line editor on non-interactive term */
301 execl (shell, "zsh", "-Z", "-g", (char *) NULL);
303 break;
305 case FISH:
306 execl (shell, "fish", (char *) NULL);
307 break;
310 /* If we get this far, everything failed miserably */
311 _exit (FORK_FAILURE);
316 * Check MC_SID to prevent running one mc from another.
317 * Return:
318 * 0 if no parent mc in our session was found,
319 * 1 if parent mc was found and the user wants to continue,
320 * 2 if parent mc was found and the user wants to quit mc.
322 static int
323 check_sid (void)
325 pid_t my_sid, old_sid;
326 const char *sid_str;
327 int r;
329 sid_str = getenv ("MC_SID");
330 if (!sid_str)
331 return 0;
333 old_sid = (pid_t) strtol (sid_str, NULL, 0);
334 if (!old_sid)
335 return 0;
337 my_sid = getsid (0);
338 if (my_sid == -1)
339 return 0;
341 /* The parent mc is in a different session, it's OK */
342 if (old_sid != my_sid)
343 return 0;
345 r = query_dialog (_("Warning"),
346 _("GNU Midnight Commander is already\n"
347 "running on this terminal.\n"
348 "Subshell support will be disabled."), D_ERROR, 2,
349 _("&OK"), _("&Quit"));
350 if (r != 0) {
351 return 2;
354 return 1;
359 * Fork the subshell, and set up many, many things.
361 * Possibly modifies the global variables:
362 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
363 * use_subshell - Is set to FALSE if we can't run the subshell
364 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
367 void
368 init_subshell (void)
370 /* This must be remembered across calls to init_subshell() */
371 static char pty_name[BUF_SMALL];
372 char precmd[BUF_SMALL];
374 switch (check_sid ()) {
375 case 1:
376 use_subshell = FALSE;
377 return;
378 case 2:
379 use_subshell = FALSE;
380 midnight_shutdown = 1;
381 return;
384 /* Take the current (hopefully pristine) tty mode and make */
385 /* a raw mode based on it now, before we do anything else with it */
386 init_raw_mode ();
388 if (subshell_pty == 0) { /* First time through */
389 /* Find out what type of shell we have */
391 if (strstr (shell, "/zsh") || getenv ("ZSH_VERSION"))
392 subshell_type = ZSH;
393 else if (strstr (shell, "/tcsh"))
394 subshell_type = TCSH;
395 else if (strstr (shell, "/csh"))
396 subshell_type = TCSH;
397 else if (strstr (shell, "/bash") || getenv ("BASH"))
398 subshell_type = BASH;
399 else if (strstr (shell, "/fish"))
400 subshell_type = FISH;
401 else {
402 use_subshell = FALSE;
403 return;
406 /* Open a pty for talking to the subshell */
408 /* FIXME: We may need to open a fresh pty each time on SVR4 */
410 subshell_pty = pty_open_master (pty_name);
411 if (subshell_pty == -1) {
412 fprintf (stderr, "Cannot open master side of pty: %s\r\n",
413 unix_error_string (errno));
414 use_subshell = FALSE;
415 return;
417 subshell_pty_slave = pty_open_slave (pty_name);
418 if (subshell_pty_slave == -1) {
419 fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
420 pty_name, unix_error_string (errno));
421 use_subshell = FALSE;
422 return;
425 /* Initialise the pty's I/O buffer */
427 pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
428 pty_buffer = g_malloc (pty_buffer_size);
430 /* Create a pipe for receiving the subshell's CWD */
432 if (subshell_type == TCSH) {
433 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
434 mc_tmpdir (), (int) getpid ());
435 if (mkfifo (tcsh_fifo, 0600) == -1) {
436 fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo,
437 unix_error_string (errno));
438 use_subshell = FALSE;
439 return;
442 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
444 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
445 || (subshell_pipe[WRITE] =
446 open (tcsh_fifo, O_RDWR)) == -1) {
447 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
448 perror (__FILE__": open");
449 use_subshell = FALSE;
450 return;
452 } else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe)) {
453 perror (__FILE__": couldn't create pipe");
454 use_subshell = FALSE;
455 return;
459 /* Fork the subshell */
461 subshell_alive = TRUE;
462 subshell_stopped = FALSE;
463 subshell_pid = fork ();
465 if (subshell_pid == -1) {
466 fprintf (stderr, "Cannot spawn the subshell process: %s\r\n",
467 unix_error_string (errno));
468 /* We exit here because, if the process table is full, the */
469 /* other method of running user commands won't work either */
470 exit (1);
473 if (subshell_pid == 0) { /* We are in the child process */
474 init_subshell_child (pty_name);
477 /* Set up `precmd' or equivalent for reading the subshell's CWD */
479 switch (subshell_type) {
480 case BASH:
481 g_snprintf (precmd, sizeof (precmd),
482 " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
483 subshell_pipe[WRITE]);
484 break;
486 case ZSH:
487 g_snprintf (precmd, sizeof (precmd),
488 " precmd(){ pwd>&%d;kill -STOP $$ }\n",
489 subshell_pipe[WRITE]);
490 break;
492 case TCSH:
493 g_snprintf (precmd, sizeof (precmd),
494 "set echo_style=both;"
495 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
496 tcsh_fifo);
497 break;
498 case FISH:
499 g_snprintf (precmd, sizeof (precmd),
500 "function fish_prompt ; pwd>&%d;kill -STOP %%self; end\n",
501 subshell_pipe[WRITE]);
502 break;
505 write_all (subshell_pty, precmd, strlen (precmd));
507 /* Wait until the subshell has started up and processed the command */
509 subshell_state = RUNNING_COMMAND;
510 tty_enable_interrupt_key ();
511 if (!feed_subshell (QUIETLY, TRUE)) {
512 use_subshell = FALSE;
514 tty_disable_interrupt_key ();
515 if (!subshell_alive)
516 use_subshell = FALSE; /* Subshell died instantly, so don't use it */
520 static void init_raw_mode ()
522 static int initialized = 0;
524 /* MC calls tty_reset_shell_mode() in pre_exec() to set the real tty to its */
525 /* original settings. However, here we need to make this tty very raw, */
526 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
527 /* pty. So, instead of changing the code for execute(), pre_exec(), */
528 /* etc, we just set up the modes we need here, before each command. */
530 if (initialized == 0) /* First time: initialise `raw_mode' */
532 tcgetattr (STDOUT_FILENO, &raw_mode);
533 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
534 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
535 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
536 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
537 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
538 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
539 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
540 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
541 initialized = 1;
546 int invoke_subshell (const char *command, int how, char **new_dir)
548 char *pcwd;
550 /* Make the MC terminal transparent */
551 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
553 /* Make the subshell change to MC's working directory */
554 if (new_dir)
555 do_subshell_chdir (current_panel->cwd, TRUE, 1);
557 if (command == NULL) /* The user has done "C-o" from MC */
559 if (subshell_state == INACTIVE)
561 subshell_state = ACTIVE;
562 /* FIXME: possibly take out this hack; the user can
563 re-play it by hitting C-hyphen a few times! */
564 if (subshell_ready)
565 write_all (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
568 else /* MC has passed us a user command */
570 if (how == QUIETLY)
571 write_all (subshell_pty, " ", 1);
572 /* FIXME: if command is long (>8KB ?) we go comma */
573 write_all (subshell_pty, command, strlen (command));
574 write_all (subshell_pty, "\n", 1);
575 subshell_state = RUNNING_COMMAND;
576 subshell_ready = FALSE;
579 feed_subshell (how, FALSE);
581 pcwd = vfs_translate_path_n (current_panel->cwd);
582 if (new_dir && subshell_alive && strcmp (subshell_cwd, pcwd))
583 *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
584 g_free (pcwd);
586 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
587 while (!subshell_alive && !quit && use_subshell)
588 init_subshell ();
590 prompt_pos = 0;
592 return quit;
597 read_subshell_prompt (void)
599 static int prompt_size = INITIAL_PROMPT_SIZE;
600 int bytes = 0, i, rc = 0;
601 struct timeval timeleft = { 0, 0 };
603 fd_set tmp;
604 FD_ZERO (&tmp);
605 FD_SET (subshell_pty, &tmp);
607 if (subshell_prompt == NULL) { /* First time through */
608 subshell_prompt = g_malloc (prompt_size);
609 *subshell_prompt = '\0';
610 prompt_pos = 0;
613 while (subshell_alive
614 && (rc =
615 select (subshell_pty + 1, &tmp, NULL, NULL, &timeleft))) {
616 /* Check for `select' errors */
617 if (rc == -1) {
618 if (errno == EINTR)
619 continue;
620 else {
621 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n",
622 unix_error_string (errno));
623 exit (1);
627 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
629 /* Extract the prompt from the shell output */
631 for (i = 0; i < bytes; ++i)
632 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r') {
633 prompt_pos = 0;
634 } else {
635 if (!pty_buffer[i])
636 continue;
638 subshell_prompt[prompt_pos++] = pty_buffer[i];
639 if (prompt_pos == prompt_size)
640 subshell_prompt =
641 g_realloc (subshell_prompt, prompt_size *= 2);
644 subshell_prompt[prompt_pos] = '\0';
646 if (rc == 0 && bytes == 0)
647 return FALSE;
648 return TRUE;
651 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
652 static int resize_tty (int fd)
654 #if defined TIOCSWINSZ
655 struct winsize tty_size;
657 tty_size.ws_row = LINES;
658 tty_size.ws_col = COLS;
659 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
661 return ioctl (fd, TIOCSWINSZ, &tty_size);
662 #else
663 return 0;
664 #endif
667 /* Resize subshell_pty */
668 void resize_subshell (void)
670 if (use_subshell == 0)
671 return;
673 resize_tty (subshell_pty);
677 exit_subshell (void)
679 int subshell_quit = TRUE;
681 if (subshell_state != INACTIVE && subshell_alive)
682 subshell_quit =
683 !query_dialog (_("Warning"),
684 _(" The shell is still active. Quit anyway? "),
685 D_NORMAL, 2, _("&Yes"), _("&No"));
687 if (subshell_quit) {
688 if (subshell_type == TCSH) {
689 if (unlink (tcsh_fifo) == -1)
690 fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
691 tcsh_fifo, unix_error_string (errno));
694 g_free (subshell_prompt);
695 g_free (pty_buffer);
696 subshell_prompt = NULL;
697 pty_buffer = NULL;
700 return subshell_quit;
705 * Carefully quote directory name to allow entering any directory safely,
706 * no matter what weird characters it may contain in its name.
707 * NOTE: Treat directory name an untrusted data, don't allow it to cause
708 * executing any commands in the shell. Escape all control characters.
709 * Use following technique:
711 * printf(1) with format string containing a single conversion specifier,
712 * "b", and an argument which contains a copy of the string passed to
713 * subshell_name_quote() with all characters, except digits and letters,
714 * replaced by the backslash-escape sequence \0nnn, where "nnn" is the
715 * numeric value of the character converted to octal number.
717 * cd "`printf "%b" 'ABC\0nnnDEF\0nnnXYZ'`"
720 static char *
721 subshell_name_quote (const char *s)
723 char *ret, *d;
724 const char *su, *n;
725 const char *quote_cmd_start, *quote_cmd_end;
726 int c;
728 if (subshell_type == FISH) {
729 quote_cmd_start = "(printf \"%b\" '";
730 quote_cmd_end = "')";
731 } else {
732 quote_cmd_start = "\"`printf \"%b\" '";
733 quote_cmd_end = "'`\"";
736 /* Factor 5 because we need \, 0 and 3 other digits per character. */
737 d = ret = g_try_malloc (1 + (5 * strlen (s)) + (strlen(quote_cmd_start))
738 + (strlen(quote_cmd_end)));
739 if (d == NULL)
740 return NULL;
742 /* Prevent interpreting leading `-' as a switch for `cd' */
743 if (*s == '-') {
744 *d++ = '.';
745 *d++ = '/';
748 /* Copy the beginning of the command to the buffer */
749 strcpy (d, quote_cmd_start);
750 d += strlen(quote_cmd_start);
753 * Print every character except digits and letters as a backslash-escape
754 * sequence of the form \0nnn, where "nnn" is the numeric value of the
755 * character converted to octal number.
757 su = s;
758 for (; su[0] != '\0'; ) {
759 n = str_cget_next_char_safe (su);
760 if (str_isalnum (su)) {
761 memcpy (d, su, n - su);
762 d+= n - su;
763 } else {
764 for (c = 0; c < n - su; c++) {
765 sprintf (d, "\\0%03o", (unsigned char) su[c]);
766 d += 5;
769 su = n;
772 strcpy (d, quote_cmd_end);
774 return ret;
778 /* If it actually changed the directory it returns true */
779 void
780 do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
782 char *pcwd;
783 char *temp;
784 char *translate;
786 pcwd = vfs_translate_path_n (current_panel->cwd);
788 if (!
789 (subshell_state == INACTIVE
790 && strcmp (subshell_cwd, pcwd))) {
791 /* We have to repaint the subshell prompt if we read it from
792 * the main program. Please note that in the code after this
793 * if, the cd command that is sent will make the subshell
794 * repaint the prompt, so we don't have to paint it. */
795 if (do_update)
796 do_update_prompt ();
797 g_free (pcwd);
798 return;
801 /* The initial space keeps this out of the command history (in bash
802 because we set "HISTCONTROL=ignorespace") */
803 write_all (subshell_pty, " cd ", 4);
804 if (*directory) {
805 translate = vfs_translate_path_n (directory);
806 if (translate) {
807 temp = subshell_name_quote (translate);
808 if (temp) {
809 write_all (subshell_pty, temp, strlen (temp));
810 g_free (temp);
811 } else {
812 /* Should not happen unless the directory name is so long
813 that we don't have memory to quote it. */
814 write_all (subshell_pty, ".", 1);
816 g_free (translate);
817 } else {
818 write_all (subshell_pty, ".", 1);
820 } else {
821 write_all (subshell_pty, "/", 1);
823 write_all (subshell_pty, "\n", 1);
825 subshell_state = RUNNING_COMMAND;
826 feed_subshell (QUIETLY, FALSE);
828 if (subshell_alive) {
829 int bPathNotEq = strcmp (subshell_cwd, pcwd);
831 if (bPathNotEq && subshell_type == TCSH) {
832 char rp_subshell_cwd[PATH_MAX];
833 char rp_current_panel_cwd[PATH_MAX];
835 char *p_subshell_cwd =
836 mc_realpath (subshell_cwd, rp_subshell_cwd);
837 char *p_current_panel_cwd =
838 mc_realpath (pcwd, rp_current_panel_cwd);
840 if (p_subshell_cwd == NULL)
841 p_subshell_cwd = subshell_cwd;
842 if (p_current_panel_cwd == NULL)
843 p_current_panel_cwd = pcwd;
844 bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd);
847 if (bPathNotEq && strcmp (pcwd, ".")) {
848 char *cwd = strip_password (g_strdup (pcwd), 1);
849 fprintf (stderr, _("Warning: Cannot change to %s.\n"), cwd);
850 g_free (cwd);
854 if (reset_prompt)
855 prompt_pos = 0;
856 update_prompt = FALSE;
858 g_free (pcwd);
859 /* Make sure that MC never stores the CWD in a silly format */
860 /* like /usr////lib/../bin, or the strcmp() above will fail */
864 void
865 subshell_get_console_attributes (void)
867 /* Get our current terminal modes */
869 if (tcgetattr (STDOUT_FILENO, &shell_mode)) {
870 fprintf (stderr, "Cannot get terminal settings: %s\r\n",
871 unix_error_string (errno));
872 use_subshell = FALSE;
873 return;
878 /* Figure out whether the subshell has stopped, exited or been killed */
879 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
880 void
881 sigchld_handler (int sig)
883 int status;
884 pid_t pid;
886 (void) sig;
888 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
890 if (pid == subshell_pid) {
891 /* Figure out what has happened to the subshell */
893 if (WIFSTOPPED (status)) {
894 if (WSTOPSIG (status) == SIGSTOP) {
895 /* The subshell has received a SIGSTOP signal */
896 subshell_stopped = TRUE;
897 } else {
898 /* The user has suspended the subshell. Revive it */
899 kill (subshell_pid, SIGCONT);
901 } else {
902 /* The subshell has either exited normally or been killed */
903 subshell_alive = FALSE;
904 delete_select_channel (subshell_pty);
905 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
906 quit |= SUBSHELL_EXIT; /* Exited normally */
909 #ifdef __linux__
910 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
912 if (pid == cons_saver_pid) {
914 if (WIFSTOPPED (status))
915 /* Someone has stopped cons.saver - restart it */
916 kill (pid, SIGCONT);
917 else {
918 /* cons.saver has died - disable confole saving */
919 handle_console (CONSOLE_DONE);
920 console_flag = 0;
924 #endif /* __linux__ */
926 /* If we got here, some other child exited; ignore it */
930 /* Feed the subshell our keyboard input until it says it's finished */
931 static int
932 feed_subshell (int how, int fail_on_error)
934 fd_set read_set; /* For `select' */
935 int maxfdp;
936 int bytes; /* For the return value from `read' */
937 int i; /* Loop counter */
939 struct timeval wtime; /* Maximum time we wait for the subshell */
940 struct timeval *wptr;
942 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
943 wtime.tv_sec = 10;
944 wtime.tv_usec = 0;
945 wptr = fail_on_error ? &wtime : NULL;
947 while (1) {
948 if (!subshell_alive)
949 return FALSE;
951 /* Prepare the file-descriptor set and call `select' */
953 FD_ZERO (&read_set);
954 FD_SET (subshell_pty, &read_set);
955 FD_SET (subshell_pipe[READ], &read_set);
956 maxfdp = max (subshell_pty, subshell_pipe[READ]);
957 if (how == VISIBLY) {
958 FD_SET (STDIN_FILENO, &read_set);
959 maxfdp = max (maxfdp, STDIN_FILENO);
962 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1) {
964 /* Despite using SA_RESTART, we still have to check for this */
965 if (errno == EINTR)
966 continue; /* try all over again */
967 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
968 fprintf (stderr, "select (FD_SETSIZE, &read_set...): %s\r\n",
969 unix_error_string (errno));
970 exit (1);
973 if (FD_ISSET (subshell_pty, &read_set))
974 /* Read from the subshell, write to stdout */
976 /* This loop improves performance by reducing context switches
977 by a factor of 20 or so... unfortunately, it also hangs MC
978 randomly, because of an apparent Linux bug. Investigate. */
979 /* for (i=0; i<5; ++i) * FIXME -- experimental */
981 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
983 /* The subshell has died */
984 if (bytes == -1 && errno == EIO && !subshell_alive)
985 return FALSE;
987 if (bytes <= 0) {
988 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
989 fprintf (stderr, "read (subshell_pty...): %s\r\n",
990 unix_error_string (errno));
991 exit (1);
994 if (how == VISIBLY)
995 write_all (STDOUT_FILENO, pty_buffer, bytes);
998 else if (FD_ISSET (subshell_pipe[READ], &read_set))
999 /* Read the subshell's CWD and capture its prompt */
1002 bytes =
1003 read (subshell_pipe[READ], subshell_cwd,
1004 MC_MAXPATHLEN + 1);
1005 if (bytes <= 0) {
1006 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1007 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n",
1008 unix_error_string (errno));
1009 exit (1);
1012 subshell_cwd[bytes - 1] = 0; /* Squash the final '\n' */
1014 synchronize ();
1016 subshell_ready = TRUE;
1017 if (subshell_state == RUNNING_COMMAND) {
1018 subshell_state = INACTIVE;
1019 return 1;
1023 else if (FD_ISSET (STDIN_FILENO, &read_set))
1024 /* Read from stdin, write to the subshell */
1026 bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
1027 if (bytes <= 0) {
1028 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1029 fprintf (stderr,
1030 "read (STDIN_FILENO, pty_buffer...): %s\r\n",
1031 unix_error_string (errno));
1032 exit (1);
1035 for (i = 0; i < bytes; ++i)
1036 if (pty_buffer[i] == subshell_switch_key) {
1037 write_all (subshell_pty, pty_buffer, i);
1038 if (subshell_ready)
1039 subshell_state = INACTIVE;
1040 return TRUE;
1043 write_all (subshell_pty, pty_buffer, bytes);
1045 if (pty_buffer[bytes-1] == '\n' || pty_buffer[bytes-1] == '\r')
1046 subshell_ready = FALSE;
1047 } else {
1048 return FALSE;
1054 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1055 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1056 static void synchronize (void)
1058 sigset_t sigchld_mask, old_mask;
1060 sigemptyset (&sigchld_mask);
1061 sigaddset (&sigchld_mask, SIGCHLD);
1062 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
1065 * SIGCHLD should not be blocked, but we unblock it just in case.
1066 * This is known to be useful for cygwin 1.3.12 and older.
1068 sigdelset (&old_mask, SIGCHLD);
1070 /* Wait until the subshell has stopped */
1071 while (subshell_alive && !subshell_stopped)
1072 sigsuspend (&old_mask);
1074 if (subshell_state != ACTIVE) {
1075 /* Discard all remaining data from stdin to the subshell */
1076 tcflush (subshell_pty_slave, TCIFLUSH);
1079 subshell_stopped = FALSE;
1080 kill (subshell_pid, SIGCONT);
1082 sigprocmask (SIG_SETMASK, &old_mask, NULL);
1083 /* We can't do any better without modifying the shell(s) */
1086 /* pty opening functions */
1088 #ifdef HAVE_GRANTPT
1090 /* System V version of pty_open_master */
1092 static int pty_open_master (char *pty_name)
1094 char *slave_name;
1095 int pty_master;
1097 #ifdef HAVE_POSIX_OPENPT
1098 pty_master = posix_openpt(O_RDWR);
1099 #elif HAVE_GETPT
1100 /* getpt () is a GNU extension (glibc 2.1.x) */
1101 pty_master = getpt ();
1102 #elif IS_AIX
1103 strcpy (pty_name, "/dev/ptc");
1104 pty_master = open (pty_name, O_RDWR);
1105 #else
1106 strcpy (pty_name, "/dev/ptmx");
1107 pty_master = open (pty_name, O_RDWR);
1108 #endif
1110 if (pty_master == -1)
1111 return -1;
1113 if (grantpt (pty_master) == -1 /* Grant access to slave */
1114 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
1115 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
1117 close (pty_master);
1118 return -1;
1120 strcpy (pty_name, slave_name);
1121 return pty_master;
1124 /* System V version of pty_open_slave */
1125 static int
1126 pty_open_slave (const char *pty_name)
1128 int pty_slave = open (pty_name, O_RDWR);
1130 if (pty_slave == -1) {
1131 fprintf (stderr, "open (%s, O_RDWR): %s\r\n", pty_name,
1132 unix_error_string (errno));
1133 return -1;
1135 #if !defined(__osf__) && !defined(__linux__)
1136 #if defined (I_FIND) && defined (I_PUSH)
1137 if (!ioctl (pty_slave, I_FIND, "ptem"))
1138 if (ioctl (pty_slave, I_PUSH, "ptem") == -1) {
1139 fprintf (stderr, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
1140 pty_slave, unix_error_string (errno));
1141 close (pty_slave);
1142 return -1;
1145 if (!ioctl (pty_slave, I_FIND, "ldterm"))
1146 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1) {
1147 fprintf (stderr,
1148 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
1149 pty_slave, unix_error_string (errno));
1150 close (pty_slave);
1151 return -1;
1153 #if !defined(sgi) && !defined(__sgi)
1154 if (!ioctl (pty_slave, I_FIND, "ttcompat"))
1155 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1) {
1156 fprintf (stderr,
1157 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
1158 pty_slave, unix_error_string (errno));
1159 close (pty_slave);
1160 return -1;
1162 #endif /* sgi || __sgi */
1163 #endif /* I_FIND && I_PUSH */
1164 #endif /* __osf__ || __linux__ */
1166 fcntl(pty_slave, F_SETFD, FD_CLOEXEC);
1167 return pty_slave;
1170 #else /* !HAVE_GRANTPT */
1172 /* BSD version of pty_open_master */
1173 static int pty_open_master (char *pty_name)
1175 int pty_master;
1176 const char *ptr1, *ptr2;
1178 strcpy (pty_name, "/dev/ptyXX");
1179 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1181 pty_name [8] = *ptr1;
1182 for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
1184 pty_name [9] = *ptr2;
1186 /* Try to open master */
1187 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1188 if (errno == ENOENT) /* Different from EIO */
1189 return -1; /* Out of pty devices */
1190 else
1191 continue; /* Try next pty device */
1193 pty_name [5] = 't'; /* Change "pty" to "tty" */
1194 if (access (pty_name, 6)){
1195 close (pty_master);
1196 pty_name [5] = 'p';
1197 continue;
1199 return pty_master;
1202 return -1; /* Ran out of pty devices */
1205 /* BSD version of pty_open_slave */
1206 static int
1207 pty_open_slave (const char *pty_name)
1209 int pty_slave;
1210 struct group *group_info = getgrnam ("tty");
1212 if (group_info != NULL) {
1213 /* The following two calls will only succeed if we are root */
1214 /* [Commented out while permissions problem is investigated] */
1215 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1216 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1218 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1219 fprintf (stderr, "open (pty_name, O_RDWR): %s\r\n", pty_name);
1220 fcntl(pty_slave, F_SETFD, FD_CLOEXEC);
1221 return pty_slave;
1224 #endif /* !HAVE_GRANTPT */
1225 #endif /* HAVE_SUBSHELL_SUPPORT */