fixed several missing #include's
[free-mc.git] / src / subshell.c
blob7253415c9c8ee0bd1a4575c879e697e4a392d4c9
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 #ifdef HAVE_SYS_IOCTL_H
40 # include <sys/ioctl.h>
41 #endif
42 #ifdef HAVE_TERMIOS_H
43 #include <termios.h>
44 #endif
45 #include <unistd.h>
47 #ifdef HAVE_STROPTS_H
48 # include <stropts.h> /* For I_PUSH */
49 #endif /* HAVE_STROPTS_H */
51 #include "global.h"
52 #include "tty.h" /* LINES */
53 #include "panel.h" /* current_panel */
54 #include "wtools.h" /* query_dialog() */
55 #include "main.h" /* do_update_prompt() */
56 #include "cons.saver.h" /* handle_console() */
57 #include "key.h" /* XCTRL */
58 #include "subshell.h"
59 #include "strutil.h"
61 #ifndef WEXITSTATUS
62 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
63 #endif
65 #ifndef WIFEXITED
66 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
67 #endif
69 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
70 static char tcsh_fifo[128];
72 /* Local functions */
73 static void init_raw_mode (void);
74 static int feed_subshell (int how, int fail_on_error);
75 static void synchronize (void);
76 static int pty_open_master (char *pty_name);
77 static int pty_open_slave (const char *pty_name);
78 static int resize_tty (int fd);
80 #ifndef STDIN_FILENO
81 # define STDIN_FILENO 0
82 #endif
84 #ifndef STDOUT_FILENO
85 # define STDOUT_FILENO 1
86 #endif
88 #ifndef STDERR_FILENO
89 # define STDERR_FILENO 2
90 #endif
92 /* If using a subshell for evaluating commands this is true */
93 int use_subshell =
94 #ifdef SUBSHELL_OPTIONAL
95 FALSE;
96 #else
97 TRUE;
98 #endif
100 /* File descriptors of the pseudoterminal used by the subshell */
101 int subshell_pty = 0;
102 static int subshell_pty_slave = -1;
104 /* The key for switching back to MC from the subshell */
105 static const char subshell_switch_key = XCTRL('o') & 255;
107 /* State of the subshell:
108 * INACTIVE: the default state; awaiting a command
109 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
110 * RUNNING_COMMAND: return to MC when the current command finishes */
111 enum subshell_state_enum subshell_state;
113 /* Holds the latest prompt captured from the subshell */
114 char *subshell_prompt = NULL;
116 /* Initial length of the buffer for the subshell's prompt */
117 #define INITIAL_PROMPT_SIZE 10
119 /* Used by the child process to indicate failure to start the subshell */
120 #define FORK_FAILURE 69 /* Arbitrary */
122 /* Initial length of the buffer for all I/O with the subshell */
123 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
125 /* For pipes */
126 enum {READ=0, WRITE=1};
128 static char *pty_buffer; /* For reading/writing on the subshell's pty */
129 static int pty_buffer_size; /* The buffer grows as needed */
130 static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
131 static pid_t subshell_pid = 1; /* The subshell's process ID */
132 static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
134 /* Subshell type (gleaned from the SHELL environment variable, if available) */
135 static enum {BASH, TCSH, ZSH} subshell_type;
137 /* Flag to indicate whether the subshell is ready for next command */
138 static int subshell_ready;
140 /* The following two flags can be changed by the SIGCHLD handler. This is */
141 /* OK, because the `int' type is updated atomically on all known machines */
142 static volatile int subshell_alive, subshell_stopped;
144 /* We store the terminal's initial mode here so that we can configure
145 the pty similarly, and also so we can restore the real terminal to
146 sanity if we have to exit abruptly */
147 static struct termios shell_mode;
149 /* This is a transparent mode for the terminal where MC is running on */
150 /* It is used when the shell is active, so that the control signals */
151 /* are delivered to the shell pty */
152 static struct termios raw_mode;
154 /* This counter indicates how many characters of prompt we have read */
155 /* FIXME: try to figure out why this had to become global */
156 static int prompt_pos;
160 * Write all data, even if the write() call is interrupted.
162 static ssize_t
163 write_all (int fd, const void *buf, size_t count)
165 ssize_t ret;
166 ssize_t written = 0;
167 while (count > 0) {
168 ret = write (fd, (const unsigned char *) buf + written, count);
169 if (ret < 0) {
170 if (errno == EINTR) {
171 continue;
172 } else {
173 return written > 0 ? written : ret;
176 count -= ret;
177 written += ret;
179 return written;
183 * Prepare child process to running the shell and run it.
185 * Modifies the global variables (in the child process only):
186 * shell_mode
188 * Returns: never.
190 static void
191 init_subshell_child (const char *pty_name)
193 const char *init_file = NULL;
194 #ifdef HAVE_GETSID
195 pid_t mc_sid;
196 #endif /* HAVE_GETSID */
198 (void) pty_name;
199 setsid (); /* Get a fresh terminal session */
201 /* Make sure that it has become our controlling terminal */
203 /* Redundant on Linux and probably most systems, but just in case: */
205 #ifdef TIOCSCTTY
206 ioctl (subshell_pty_slave, TIOCSCTTY, 0);
207 #endif
209 /* Configure its terminal modes and window size */
211 /* Set up the pty with the same termios flags as our own tty, plus */
212 /* TOSTOP, which keeps background processes from writing to the pty */
214 shell_mode.c_lflag |= TOSTOP; /* So background writers get SIGTTOU */
215 if (tcsetattr (subshell_pty_slave, TCSANOW, &shell_mode)) {
216 fprintf (stderr, "Cannot set pty terminal modes: %s\r\n",
217 unix_error_string (errno));
218 _exit (FORK_FAILURE);
221 /* Set the pty's size (80x25 by default on Linux) according to the */
222 /* size of the real terminal as calculated by ncurses, if possible */
223 resize_tty (subshell_pty_slave);
225 /* Set up the subshell's environment and init file name */
227 /* It simplifies things to change to our home directory here, */
228 /* and the user's startup file may do a `cd' command anyway */
229 chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
231 #ifdef HAVE_GETSID
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));
240 #endif /* HAVE_GETSID */
242 switch (subshell_type) {
243 case BASH:
244 init_file = ".mc/bashrc";
245 if (access (init_file, R_OK) == -1)
246 init_file = ".bashrc";
248 /* Make MC's special commands not show up in bash's history */
249 putenv ("HISTCONTROL=ignorespace");
251 /* Allow alternative readline settings for MC */
252 if (access (".mc/inputrc", R_OK) == 0)
253 putenv ("INPUTRC=.mc/inputrc");
255 break;
257 /* TODO: Find a way to pass initfile to TCSH and ZSH */
258 case TCSH:
259 case ZSH:
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;
306 /* If we get this far, everything failed miserably */
307 _exit (FORK_FAILURE);
311 #ifdef HAVE_GETSID
313 * Check MC_SID to prevent running one mc from another.
314 * Return:
315 * 0 if no parent mc in our session was found,
316 * 1 if parent mc was found and the user wants to continue,
317 * 2 if parent mc was found and the user wants to quit mc.
319 static int
320 check_sid (void)
322 pid_t my_sid, old_sid;
323 const char *sid_str;
324 int r;
326 sid_str = getenv ("MC_SID");
327 if (!sid_str)
328 return 0;
330 old_sid = (pid_t) strtol (sid_str, NULL, 0);
331 if (!old_sid)
332 return 0;
334 my_sid = getsid (0);
335 if (my_sid == -1)
336 return 0;
338 /* The parent mc is in a different session, it's OK */
339 if (old_sid != my_sid)
340 return 0;
342 r = query_dialog (_("Warning"),
343 _("GNU Midnight Commander is already\n"
344 "running on this terminal.\n"
345 "Subshell support will be disabled."), D_ERROR, 2,
346 _("&OK"), _("&Quit"));
347 if (r != 0) {
348 return 2;
351 return 1;
353 #endif /* HAVE_GETSID */
357 * Fork the subshell, and set up many, many things.
359 * Possibly modifies the global variables:
360 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
361 * use_subshell - Is set to FALSE if we can't run the subshell
362 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
365 void
366 init_subshell (void)
368 /* This must be remembered across calls to init_subshell() */
369 static char pty_name[BUF_SMALL];
370 char precmd[BUF_SMALL];
372 #ifdef HAVE_GETSID
373 switch (check_sid ()) {
374 case 1:
375 use_subshell = FALSE;
376 return;
377 case 2:
378 use_subshell = FALSE;
379 midnight_shutdown = 1;
380 return;
382 #endif /* HAVE_GETSID */
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, "/bash") || getenv ("BASH"))
396 subshell_type = BASH;
397 else {
398 use_subshell = FALSE;
399 return;
402 /* Open a pty for talking to the subshell */
404 /* FIXME: We may need to open a fresh pty each time on SVR4 */
406 subshell_pty = pty_open_master (pty_name);
407 if (subshell_pty == -1) {
408 fprintf (stderr, "Cannot open master side of pty: %s\r\n",
409 unix_error_string (errno));
410 use_subshell = FALSE;
411 return;
413 subshell_pty_slave = pty_open_slave (pty_name);
414 if (subshell_pty_slave == -1) {
415 fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
416 pty_name, unix_error_string (errno));
417 use_subshell = FALSE;
418 return;
421 /* Initialise the pty's I/O buffer */
423 pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
424 pty_buffer = g_malloc (pty_buffer_size);
426 /* Create a pipe for receiving the subshell's CWD */
428 if (subshell_type == TCSH) {
429 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
430 mc_tmpdir (), (int) getpid ());
431 if (mkfifo (tcsh_fifo, 0600) == -1) {
432 fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo,
433 unix_error_string (errno));
434 use_subshell = FALSE;
435 return;
438 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
440 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
441 || (subshell_pipe[WRITE] =
442 open (tcsh_fifo, O_RDWR)) == -1) {
443 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
444 perror (__FILE__": open");
445 use_subshell = FALSE;
446 return;
448 } else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe)) {
449 perror (__FILE__": couldn't create pipe");
450 use_subshell = FALSE;
451 return;
455 /* Fork the subshell */
457 subshell_alive = TRUE;
458 subshell_stopped = FALSE;
459 subshell_pid = fork ();
461 if (subshell_pid == -1) {
462 fprintf (stderr, "Cannot spawn the subshell process: %s\r\n",
463 unix_error_string (errno));
464 /* We exit here because, if the process table is full, the */
465 /* other method of running user commands won't work either */
466 exit (1);
469 if (subshell_pid == 0) { /* We are in the child process */
470 init_subshell_child (pty_name);
473 /* Set up `precmd' or equivalent for reading the subshell's CWD */
475 switch (subshell_type) {
476 case BASH:
477 g_snprintf (precmd, sizeof (precmd),
478 " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
479 subshell_pipe[WRITE]);
480 break;
482 case ZSH:
483 g_snprintf (precmd, sizeof (precmd),
484 " precmd(){ pwd>&%d;kill -STOP $$ }\n",
485 subshell_pipe[WRITE]);
486 break;
488 case TCSH:
489 g_snprintf (precmd, sizeof (precmd),
490 "set echo_style=both;"
491 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
492 tcsh_fifo);
493 break;
495 write_all (subshell_pty, precmd, strlen (precmd));
497 /* Wait until the subshell has started up and processed the command */
499 subshell_state = RUNNING_COMMAND;
500 enable_interrupt_key ();
501 if (!feed_subshell (QUIETLY, TRUE)) {
502 use_subshell = FALSE;
504 disable_interrupt_key ();
505 if (!subshell_alive)
506 use_subshell = FALSE; /* Subshell died instantly, so don't use it */
510 static void init_raw_mode ()
512 static int initialized = 0;
514 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
515 /* original settings. However, here we need to make this tty very raw, */
516 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
517 /* pty. So, instead of changing the code for execute(), pre_exec(), */
518 /* etc, we just set up the modes we need here, before each command. */
520 if (initialized == 0) /* First time: initialise `raw_mode' */
522 tcgetattr (STDOUT_FILENO, &raw_mode);
523 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
524 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
525 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
526 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
527 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
528 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
529 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
530 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
531 initialized = 1;
536 int invoke_subshell (const char *command, int how, char **new_dir)
538 char *pcwd;
540 /* Make the MC terminal transparent */
541 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
543 /* Make the subshell change to MC's working directory */
544 if (new_dir)
545 do_subshell_chdir (current_panel->cwd, TRUE, 1);
547 if (command == NULL) /* The user has done "C-o" from MC */
549 if (subshell_state == INACTIVE)
551 subshell_state = ACTIVE;
552 /* FIXME: possibly take out this hack; the user can
553 re-play it by hitting C-hyphen a few times! */
554 write_all (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
557 else /* MC has passed us a user command */
559 if (how == QUIETLY)
560 write_all (subshell_pty, " ", 1);
561 /* FIXME: if command is long (>8KB ?) we go comma */
562 write_all (subshell_pty, command, strlen (command));
563 write_all (subshell_pty, "\n", 1);
564 subshell_state = RUNNING_COMMAND;
565 subshell_ready = FALSE;
568 feed_subshell (how, FALSE);
570 pcwd = vfs_translate_path_n (current_panel->cwd);
571 if (new_dir && subshell_alive && strcmp (subshell_cwd, pcwd))
572 *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
573 g_free (pcwd);
575 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
576 while (!subshell_alive && !quit && use_subshell)
577 init_subshell ();
579 prompt_pos = 0;
581 return quit;
586 read_subshell_prompt (void)
588 static int prompt_size = INITIAL_PROMPT_SIZE;
589 int bytes = 0, i, rc = 0;
590 struct timeval timeleft = { 0, 0 };
592 fd_set tmp;
593 FD_ZERO (&tmp);
594 FD_SET (subshell_pty, &tmp);
596 if (subshell_prompt == NULL) { /* First time through */
597 subshell_prompt = g_malloc (prompt_size);
598 *subshell_prompt = '\0';
599 prompt_pos = 0;
602 while (subshell_alive
603 && (rc =
604 select (subshell_pty + 1, &tmp, NULL, NULL, &timeleft))) {
605 /* Check for `select' errors */
606 if (rc == -1) {
607 if (errno == EINTR)
608 continue;
609 else {
610 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n",
611 unix_error_string (errno));
612 exit (1);
616 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
618 /* Extract the prompt from the shell output */
620 for (i = 0; i < bytes; ++i)
621 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r') {
622 prompt_pos = 0;
623 } else {
624 if (!pty_buffer[i])
625 continue;
627 subshell_prompt[prompt_pos++] = pty_buffer[i];
628 if (prompt_pos == prompt_size)
629 subshell_prompt =
630 g_realloc (subshell_prompt, prompt_size *= 2);
633 subshell_prompt[prompt_pos] = '\0';
635 if (rc == 0 && bytes == 0)
636 return FALSE;
637 return TRUE;
640 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
641 static int resize_tty (int fd)
643 #if defined TIOCSWINSZ
644 struct winsize tty_size;
646 tty_size.ws_row = LINES;
647 tty_size.ws_col = COLS;
648 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
650 return ioctl (fd, TIOCSWINSZ, &tty_size);
651 #else
652 return 0;
653 #endif
656 /* Resize subshell_pty */
657 void resize_subshell (void)
659 if (use_subshell == 0)
660 return;
662 resize_tty (subshell_pty);
666 exit_subshell (void)
668 int subshell_quit = TRUE;
670 if (subshell_state != INACTIVE && subshell_alive)
671 subshell_quit =
672 !query_dialog (_("Warning"),
673 _(" The shell is still active. Quit anyway? "),
674 D_NORMAL, 2, _("&Yes"), _("&No"));
676 if (subshell_quit) {
677 if (subshell_type == TCSH) {
678 if (unlink (tcsh_fifo) == -1)
679 fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
680 tcsh_fifo, unix_error_string (errno));
683 g_free (subshell_prompt);
684 g_free (pty_buffer);
685 subshell_prompt = NULL;
686 pty_buffer = NULL;
689 return subshell_quit;
694 * Carefully quote directory name to allow entering any directory safely,
695 * no matter what weird characters it may contain in its name.
696 * NOTE: Treat directory name an untrusted data, don't allow it to cause
697 * executing any commands in the shell. Escape all control characters.
698 * Use following technique:
700 * printf(1) with format string containing a single conversion specifier,
701 * "b", and an argument which contains a copy of the string passed to
702 * subshell_name_quote() with all characters, except digits and letters,
703 * replaced by the backslash-escape sequence \0nnn, where "nnn" is the
704 * numeric value of the character converted to octal number.
706 * cd "`printf "%b" 'ABC\0nnnDEF\0nnnXYZ'`"
709 static char *
710 subshell_name_quote (const char *s)
712 char *ret, *d;
713 const char *su, *n;
714 const char quote_cmd_start[] = "\"`printf \"%b\" '";
715 const char quote_cmd_end[] = "'`\"";
716 int c;
718 /* Factor 5 because we need \, 0 and 3 other digits per character. */
719 d = ret = g_malloc (1 + (5 * strlen (s)) + (sizeof(quote_cmd_start) - 1)
720 + (sizeof(quote_cmd_end) - 1));
721 if (!d)
722 return NULL;
724 /* Prevent interpreting leading `-' as a switch for `cd' */
725 if (*s == '-') {
726 *d++ = '.';
727 *d++ = '/';
730 /* Copy the beginning of the command to the buffer */
731 strcpy (d, quote_cmd_start);
732 d += sizeof(quote_cmd_start) - 1;
735 * Print every character except digits and letters as a backslash-escape
736 * sequence of the form \0nnn, where "nnn" is the numeric value of the
737 * character converted to octal number.
739 su = s;
740 for (; su[0] != '\0'; ) {
741 n = str_cget_next_char_safe (su);
742 if (str_isalnum (su)) {
743 memcpy (d, su, n - su);
744 d+= n - su;
745 } else {
746 for (c = 0; c < n - su; c++) {
747 sprintf (d, "\\0%03o", (unsigned char) su[c]);
748 d += 5;
751 su = n;
754 strcpy (d, quote_cmd_end);
756 return ret;
760 /* If it actually changed the directory it returns true */
761 void
762 do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
764 char *pcwd;
765 char *temp;
766 char *translate;
768 pcwd = vfs_translate_path_n (current_panel->cwd);
770 if (!
771 (subshell_state == INACTIVE
772 && strcmp (subshell_cwd, pcwd))) {
773 /* We have to repaint the subshell prompt if we read it from
774 * the main program. Please note that in the code after this
775 * if, the cd command that is sent will make the subshell
776 * repaint the prompt, so we don't have to paint it. */
777 if (do_update)
778 do_update_prompt ();
779 g_free (pcwd);
780 return;
783 /* The initial space keeps this out of the command history (in bash
784 because we set "HISTCONTROL=ignorespace") */
785 write_all (subshell_pty, " cd ", 4);
786 if (*directory) {
787 translate = vfs_translate_path_n (directory);
788 if (translate) {
789 temp = subshell_name_quote (translate);
790 if (temp) {
791 write_all (subshell_pty, temp, strlen (temp));
792 g_free (temp);
793 } else {
794 /* Should not happen unless the directory name is so long
795 that we don't have memory to quote it. */
796 write_all (subshell_pty, ".", 1);
798 g_free (translate);
799 } else {
800 write_all (subshell_pty, ".", 1);
802 } else {
803 write_all (subshell_pty, "/", 1);
805 write_all (subshell_pty, "\n", 1);
807 subshell_state = RUNNING_COMMAND;
808 feed_subshell (QUIETLY, FALSE);
810 if (subshell_alive) {
811 int bPathNotEq = strcmp (subshell_cwd, pcwd);
813 if (bPathNotEq && subshell_type == TCSH) {
814 char rp_subshell_cwd[PATH_MAX];
815 char rp_current_panel_cwd[PATH_MAX];
817 char *p_subshell_cwd =
818 mc_realpath (subshell_cwd, rp_subshell_cwd);
819 char *p_current_panel_cwd =
820 mc_realpath (pcwd, rp_current_panel_cwd);
822 if (p_subshell_cwd == NULL)
823 p_subshell_cwd = subshell_cwd;
824 if (p_current_panel_cwd == NULL)
825 p_current_panel_cwd = pcwd;
826 bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd);
829 if (bPathNotEq && strcmp (pcwd, ".")) {
830 char *cwd = strip_password (g_strdup (pcwd), 1);
831 fprintf (stderr, _("Warning: Cannot change to %s.\n"), cwd);
832 g_free (cwd);
836 if (reset_prompt)
837 prompt_pos = 0;
838 update_prompt = FALSE;
840 g_free (pcwd);
841 /* Make sure that MC never stores the CWD in a silly format */
842 /* like /usr////lib/../bin, or the strcmp() above will fail */
846 void
847 subshell_get_console_attributes (void)
849 /* Get our current terminal modes */
851 if (tcgetattr (STDOUT_FILENO, &shell_mode)) {
852 fprintf (stderr, "Cannot get terminal settings: %s\r\n",
853 unix_error_string (errno));
854 use_subshell = FALSE;
855 return;
860 /* Figure out whether the subshell has stopped, exited or been killed */
861 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
862 void
863 sigchld_handler (int sig)
865 int status;
866 pid_t pid;
868 (void) sig;
870 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
872 if (pid == subshell_pid) {
873 /* Figure out what has happened to the subshell */
875 if (WIFSTOPPED (status)) {
876 if (WSTOPSIG (status) == SIGSTOP) {
877 /* The subshell has received a SIGSTOP signal */
878 subshell_stopped = TRUE;
879 } else {
880 /* The user has suspended the subshell. Revive it */
881 kill (subshell_pid, SIGCONT);
883 } else {
884 /* The subshell has either exited normally or been killed */
885 subshell_alive = FALSE;
886 delete_select_channel (subshell_pty);
887 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
888 quit |= SUBSHELL_EXIT; /* Exited normally */
891 #ifdef __linux__
892 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
894 if (pid == cons_saver_pid) {
896 if (WIFSTOPPED (status))
897 /* Someone has stopped cons.saver - restart it */
898 kill (pid, SIGCONT);
899 else {
900 /* cons.saver has died - disable confole saving */
901 handle_console (CONSOLE_DONE);
902 console_flag = 0;
906 #endif /* __linux__ */
908 /* If we got here, some other child exited; ignore it */
912 /* Feed the subshell our keyboard input until it says it's finished */
913 static int
914 feed_subshell (int how, int fail_on_error)
916 fd_set read_set; /* For `select' */
917 int maxfdp;
918 int bytes; /* For the return value from `read' */
919 int i; /* Loop counter */
921 struct timeval wtime; /* Maximum time we wait for the subshell */
922 struct timeval *wptr;
924 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
925 wtime.tv_sec = 10;
926 wtime.tv_usec = 0;
927 wptr = fail_on_error ? &wtime : NULL;
929 while (1) {
930 if (!subshell_alive)
931 return FALSE;
933 /* Prepare the file-descriptor set and call `select' */
935 FD_ZERO (&read_set);
936 FD_SET (subshell_pty, &read_set);
937 FD_SET (subshell_pipe[READ], &read_set);
938 maxfdp = max (subshell_pty, subshell_pipe[READ]);
939 if (how == VISIBLY) {
940 FD_SET (STDIN_FILENO, &read_set);
941 maxfdp = max (maxfdp, STDIN_FILENO);
944 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1) {
946 /* Despite using SA_RESTART, we still have to check for this */
947 if (errno == EINTR)
948 continue; /* try all over again */
949 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
950 fprintf (stderr, "select (FD_SETSIZE, &read_set...): %s\r\n",
951 unix_error_string (errno));
952 exit (1);
955 if (FD_ISSET (subshell_pty, &read_set))
956 /* Read from the subshell, write to stdout */
958 /* This loop improves performance by reducing context switches
959 by a factor of 20 or so... unfortunately, it also hangs MC
960 randomly, because of an apparent Linux bug. Investigate. */
961 /* for (i=0; i<5; ++i) * FIXME -- experimental */
963 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
965 /* The subshell has died */
966 if (bytes == -1 && errno == EIO && !subshell_alive)
967 return FALSE;
969 if (bytes <= 0) {
970 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
971 fprintf (stderr, "read (subshell_pty...): %s\r\n",
972 unix_error_string (errno));
973 exit (1);
976 if (how == VISIBLY)
977 write_all (STDOUT_FILENO, pty_buffer, bytes);
980 else if (FD_ISSET (subshell_pipe[READ], &read_set))
981 /* Read the subshell's CWD and capture its prompt */
984 bytes =
985 read (subshell_pipe[READ], subshell_cwd,
986 MC_MAXPATHLEN + 1);
987 if (bytes <= 0) {
988 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
989 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n",
990 unix_error_string (errno));
991 exit (1);
994 subshell_cwd[bytes - 1] = 0; /* Squash the final '\n' */
996 synchronize ();
998 subshell_ready = TRUE;
999 if (subshell_state == RUNNING_COMMAND) {
1000 subshell_state = INACTIVE;
1001 return 1;
1005 else if (FD_ISSET (STDIN_FILENO, &read_set))
1006 /* Read from stdin, write to the subshell */
1008 bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
1009 if (bytes <= 0) {
1010 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1011 fprintf (stderr,
1012 "read (STDIN_FILENO, pty_buffer...): %s\r\n",
1013 unix_error_string (errno));
1014 exit (1);
1017 for (i = 0; i < bytes; ++i)
1018 if (pty_buffer[i] == subshell_switch_key) {
1019 write_all (subshell_pty, pty_buffer, i);
1020 if (subshell_ready)
1021 subshell_state = INACTIVE;
1022 return TRUE;
1025 write_all (subshell_pty, pty_buffer, bytes);
1026 subshell_ready = FALSE;
1027 } else {
1028 return FALSE;
1034 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1035 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1036 static void synchronize (void)
1038 sigset_t sigchld_mask, old_mask;
1040 sigemptyset (&sigchld_mask);
1041 sigaddset (&sigchld_mask, SIGCHLD);
1042 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
1045 * SIGCHLD should not be blocked, but we unblock it just in case.
1046 * This is known to be useful for cygwin 1.3.12 and older.
1048 sigdelset (&old_mask, SIGCHLD);
1050 /* Wait until the subshell has stopped */
1051 while (subshell_alive && !subshell_stopped)
1052 sigsuspend (&old_mask);
1054 if (subshell_state != ACTIVE) {
1055 /* Discard all remaining data from stdin to the subshell */
1056 tcflush (subshell_pty_slave, TCIFLUSH);
1059 subshell_stopped = FALSE;
1060 kill (subshell_pid, SIGCONT);
1062 sigprocmask (SIG_SETMASK, &old_mask, NULL);
1063 /* We can't do any better without modifying the shell(s) */
1066 /* pty opening functions */
1068 #ifdef HAVE_GRANTPT
1070 /* System V version of pty_open_master */
1072 static int pty_open_master (char *pty_name)
1074 char *slave_name;
1075 int pty_master;
1077 #ifdef HAVE_POSIX_OPENPT
1078 pty_master = posix_openpt(O_RDWR);
1079 #elif HAVE_GETPT
1080 /* getpt () is a GNU extension (glibc 2.1.x) */
1081 pty_master = getpt ();
1082 #elif IS_AIX
1083 strcpy (pty_name, "/dev/ptc");
1084 pty_master = open (pty_name, O_RDWR);
1085 #else
1086 strcpy (pty_name, "/dev/ptmx");
1087 pty_master = open (pty_name, O_RDWR);
1088 #endif
1090 if (pty_master == -1)
1091 return -1;
1093 if (grantpt (pty_master) == -1 /* Grant access to slave */
1094 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
1095 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
1097 close (pty_master);
1098 return -1;
1100 strcpy (pty_name, slave_name);
1101 return pty_master;
1104 /* System V version of pty_open_slave */
1105 static int
1106 pty_open_slave (const char *pty_name)
1108 int pty_slave = open (pty_name, O_RDWR);
1110 if (pty_slave == -1) {
1111 fprintf (stderr, "open (%s, O_RDWR): %s\r\n", pty_name,
1112 unix_error_string (errno));
1113 return -1;
1115 #if !defined(__osf__) && !defined(__linux__)
1116 #if defined (I_FIND) && defined (I_PUSH)
1117 if (!ioctl (pty_slave, I_FIND, "ptem"))
1118 if (ioctl (pty_slave, I_PUSH, "ptem") == -1) {
1119 fprintf (stderr, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
1120 pty_slave, unix_error_string (errno));
1121 close (pty_slave);
1122 return -1;
1125 if (!ioctl (pty_slave, I_FIND, "ldterm"))
1126 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1) {
1127 fprintf (stderr,
1128 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
1129 pty_slave, unix_error_string (errno));
1130 close (pty_slave);
1131 return -1;
1133 #if !defined(sgi) && !defined(__sgi)
1134 if (!ioctl (pty_slave, I_FIND, "ttcompat"))
1135 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1) {
1136 fprintf (stderr,
1137 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
1138 pty_slave, unix_error_string (errno));
1139 close (pty_slave);
1140 return -1;
1142 #endif /* sgi || __sgi */
1143 #endif /* I_FIND && I_PUSH */
1144 #endif /* __osf__ || __linux__ */
1146 fcntl(pty_slave, F_SETFD, FD_CLOEXEC);
1147 return pty_slave;
1150 #else /* !HAVE_GRANTPT */
1152 /* BSD version of pty_open_master */
1153 static int pty_open_master (char *pty_name)
1155 int pty_master;
1156 const char *ptr1, *ptr2;
1158 strcpy (pty_name, "/dev/ptyXX");
1159 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1161 pty_name [8] = *ptr1;
1162 for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
1164 pty_name [9] = *ptr2;
1166 /* Try to open master */
1167 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1168 if (errno == ENOENT) /* Different from EIO */
1169 return -1; /* Out of pty devices */
1170 else
1171 continue; /* Try next pty device */
1173 pty_name [5] = 't'; /* Change "pty" to "tty" */
1174 if (access (pty_name, 6)){
1175 close (pty_master);
1176 pty_name [5] = 'p';
1177 continue;
1179 return pty_master;
1182 return -1; /* Ran out of pty devices */
1185 /* BSD version of pty_open_slave */
1186 static int
1187 pty_open_slave (const char *pty_name)
1189 int pty_slave;
1190 struct group *group_info = getgrnam ("tty");
1192 if (group_info != NULL) {
1193 /* The following two calls will only succeed if we are root */
1194 /* [Commented out while permissions problem is investigated] */
1195 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1196 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1198 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1199 fprintf (stderr, "open (pty_name, O_RDWR): %s\r\n", pty_name);
1200 fcntl(pty_slave, F_SETFD, FD_CLOEXEC);
1201 return pty_slave;
1204 #endif /* !HAVE_GRANTPT */
1205 #endif /* HAVE_SUBSHELL_SUPPORT */