Merge branch '132_search_skip_hidden'
[midnight-commander.git] / src / subshell.c
blob99cf28ce4b0215ab41103b9e1fefe1b8ffbb7135
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 #include <config.h>
21 #ifdef HAVE_SUBSHELL_SUPPORT
23 #ifndef _GNU_SOURCE
24 # define _GNU_SOURCE 1
25 #endif
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <signal.h>
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_IOCTL_H
36 # include <sys/ioctl.h>
37 #endif
38 #ifdef HAVE_TERMIOS_H
39 #include <termios.h>
40 #endif
41 #include <unistd.h>
43 #ifdef HAVE_STROPTS_H
44 # include <stropts.h> /* For I_PUSH */
45 #endif /* HAVE_STROPTS_H */
47 #include "global.h"
48 #include "tty.h" /* LINES */
49 #include "panel.h" /* current_panel */
50 #include "wtools.h" /* query_dialog() */
51 #include "main.h" /* do_update_prompt() */
52 #include "cons.saver.h" /* handle_console() */
53 #include "key.h" /* XCTRL */
54 #include "subshell.h"
56 #ifndef WEXITSTATUS
57 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
58 #endif
60 #ifndef WIFEXITED
61 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
62 #endif
64 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
65 static char tcsh_fifo[128];
67 /* Local functions */
68 static void init_raw_mode (void);
69 static int feed_subshell (int how, int fail_on_error);
70 static void synchronize (void);
71 static int pty_open_master (char *pty_name);
72 static int pty_open_slave (const char *pty_name);
73 static int resize_tty (int fd);
75 #ifndef STDIN_FILENO
76 # define STDIN_FILENO 0
77 #endif
79 #ifndef STDOUT_FILENO
80 # define STDOUT_FILENO 1
81 #endif
83 #ifndef STDERR_FILENO
84 # define STDERR_FILENO 2
85 #endif
87 /* If using a subshell for evaluating commands this is true */
88 int use_subshell =
89 #ifdef SUBSHELL_OPTIONAL
90 FALSE;
91 #else
92 TRUE;
93 #endif
95 /* File descriptors of the pseudoterminal used by the subshell */
96 int subshell_pty = 0;
97 static int subshell_pty_slave = -1;
99 /* The key for switching back to MC from the subshell */
100 static const char subshell_switch_key = XCTRL('o') & 255;
102 /* State of the subshell:
103 * INACTIVE: the default state; awaiting a command
104 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
105 * RUNNING_COMMAND: return to MC when the current command finishes */
106 enum subshell_state_enum subshell_state;
108 /* Holds the latest prompt captured from the subshell */
109 char *subshell_prompt = NULL;
111 /* Initial length of the buffer for the subshell's prompt */
112 #define INITIAL_PROMPT_SIZE 10
114 /* Used by the child process to indicate failure to start the subshell */
115 #define FORK_FAILURE 69 /* Arbitrary */
117 /* Initial length of the buffer for all I/O with the subshell */
118 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
120 /* For pipes */
121 enum {READ=0, WRITE=1};
123 static char *pty_buffer; /* For reading/writing on the subshell's pty */
124 static int pty_buffer_size; /* The buffer grows as needed */
125 static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
126 static pid_t subshell_pid = 1; /* The subshell's process ID */
127 static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
129 /* Subshell type (gleaned from the SHELL environment variable, if available) */
130 static enum {BASH, TCSH, ZSH} subshell_type;
132 /* Flag to indicate whether the subshell is ready for next command */
133 static int subshell_ready;
135 /* The following two flags can be changed by the SIGCHLD handler. This is */
136 /* OK, because the `int' type is updated atomically on all known machines */
137 static volatile int subshell_alive, subshell_stopped;
139 /* We store the terminal's initial mode here so that we can configure
140 the pty similarly, and also so we can restore the real terminal to
141 sanity if we have to exit abruptly */
142 static struct termios shell_mode;
144 /* This is a transparent mode for the terminal where MC is running on */
145 /* It is used when the shell is active, so that the control signals */
146 /* are delivered to the shell pty */
147 static struct termios raw_mode;
149 /* This counter indicates how many characters of prompt we have read */
150 /* FIXME: try to figure out why this had to become global */
151 static int prompt_pos;
155 * Write all data, even if the write() call is interrupted.
157 static ssize_t
158 write_all (int fd, const void *buf, size_t count)
160 ssize_t ret;
161 ssize_t written = 0;
162 while (count > 0) {
163 ret = write (fd, (const unsigned char *) buf + written, count);
164 if (ret < 0) {
165 if (errno == EINTR) {
166 continue;
167 } else {
168 return written > 0 ? written : ret;
171 count -= ret;
172 written += ret;
174 return written;
178 * Prepare child process to running the shell and run it.
180 * Modifies the global variables (in the child process only):
181 * shell_mode
183 * Returns: never.
185 static void
186 init_subshell_child (const char *pty_name)
188 const char *init_file = NULL;
189 #ifdef HAVE_GETSID
190 pid_t mc_sid;
191 #endif /* HAVE_GETSID */
193 setsid (); /* Get a fresh terminal session */
195 /* Make sure that it has become our controlling terminal */
197 /* Redundant on Linux and probably most systems, but just in case: */
199 #ifdef TIOCSCTTY
200 ioctl (subshell_pty_slave, TIOCSCTTY, 0);
201 #endif
203 /* Configure its terminal modes and window size */
205 /* Set up the pty with the same termios flags as our own tty, plus */
206 /* TOSTOP, which keeps background processes from writing to the pty */
208 shell_mode.c_lflag |= TOSTOP; /* So background writers get SIGTTOU */
209 if (tcsetattr (subshell_pty_slave, TCSANOW, &shell_mode)) {
210 fprintf (stderr, "Cannot set pty terminal modes: %s\r\n",
211 unix_error_string (errno));
212 _exit (FORK_FAILURE);
215 /* Set the pty's size (80x25 by default on Linux) according to the */
216 /* size of the real terminal as calculated by ncurses, if possible */
217 resize_tty (subshell_pty_slave);
219 /* Set up the subshell's environment and init file name */
221 /* It simplifies things to change to our home directory here, */
222 /* and the user's startup file may do a `cd' command anyway */
223 chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
225 #ifdef HAVE_GETSID
226 /* Set MC_SID to prevent running one mc from another */
227 mc_sid = getsid (0);
228 if (mc_sid != -1) {
229 char sid_str[BUF_SMALL];
230 g_snprintf (sid_str, sizeof (sid_str), "MC_SID=%ld",
231 (long) mc_sid);
232 putenv (g_strdup (sid_str));
234 #endif /* HAVE_GETSID */
236 switch (subshell_type) {
237 case BASH:
238 init_file = ".mc/bashrc";
239 if (access (init_file, R_OK) == -1)
240 init_file = ".bashrc";
242 /* Make MC's special commands not show up in bash's history */
243 putenv ("HISTCONTROL=ignorespace");
245 /* Allow alternative readline settings for MC */
246 if (access (".mc/inputrc", R_OK) == 0)
247 putenv ("INPUTRC=.mc/inputrc");
249 break;
251 /* TODO: Find a way to pass initfile to TCSH and ZSH */
252 case TCSH:
253 case ZSH:
254 break;
256 default:
257 fprintf (stderr, __FILE__ ": unimplemented subshell type %d\r\n",
258 subshell_type);
259 _exit (FORK_FAILURE);
262 /* Attach all our standard file descriptors to the pty */
264 /* This is done just before the fork, because stderr must still */
265 /* be connected to the real tty during the above error messages; */
266 /* otherwise the user will never see them. */
268 dup2 (subshell_pty_slave, STDIN_FILENO);
269 dup2 (subshell_pty_slave, STDOUT_FILENO);
270 dup2 (subshell_pty_slave, STDERR_FILENO);
272 close (subshell_pipe[READ]);
273 close (subshell_pty_slave); /* These may be FD_CLOEXEC, but just in case... */
274 /* Close master side of pty. This is important; apart from */
275 /* freeing up the descriptor for use in the subshell, it also */
276 /* means that when MC exits, the subshell will get a SIGHUP and */
277 /* exit too, because there will be no more descriptors pointing */
278 /* at the master side of the pty and so it will disappear. */
279 close (subshell_pty);
281 /* Execute the subshell at last */
283 switch (subshell_type) {
284 case BASH:
285 execl (shell, "bash", "-rcfile", init_file, (char *) NULL);
286 break;
288 case TCSH:
289 execl (shell, "tcsh", (char *) NULL);
290 break;
292 case ZSH:
293 /* Use -g to exclude cmds beginning with space from history
294 * and -Z to use the line editor on non-interactive term */
295 execl (shell, "zsh", "-Z", "-g", (char *) NULL);
297 break;
300 /* If we get this far, everything failed miserably */
301 _exit (FORK_FAILURE);
305 #ifdef HAVE_GETSID
307 * Check MC_SID to prevent running one mc from another.
308 * Return:
309 * 0 if no parent mc in our session was found,
310 * 1 if parent mc was found and the user wants to continue,
311 * 2 if parent mc was found and the user wants to quit mc.
313 static int
314 check_sid (void)
316 pid_t my_sid, old_sid;
317 const char *sid_str;
318 int r;
320 sid_str = getenv ("MC_SID");
321 if (!sid_str)
322 return 0;
324 old_sid = (pid_t) strtol (sid_str, NULL, 0);
325 if (!old_sid)
326 return 0;
328 my_sid = getsid (0);
329 if (my_sid == -1)
330 return 0;
332 /* The parent mc is in a different session, it's OK */
333 if (old_sid != my_sid)
334 return 0;
336 r = query_dialog (_("Warning"),
337 _("GNU Midnight Commander is already\n"
338 "running on this terminal.\n"
339 "Subshell support will be disabled."), D_ERROR, 2,
340 _("&OK"), _("&Quit"));
341 if (r != 0) {
342 return 2;
345 return 1;
347 #endif /* HAVE_GETSID */
351 * Fork the subshell, and set up many, many things.
353 * Possibly modifies the global variables:
354 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
355 * use_subshell - Is set to FALSE if we can't run the subshell
356 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
359 void
360 init_subshell (void)
362 /* This must be remembered across calls to init_subshell() */
363 static char pty_name[BUF_SMALL];
364 char precmd[BUF_SMALL];
366 #ifdef HAVE_GETSID
367 switch (check_sid ()) {
368 case 1:
369 use_subshell = FALSE;
370 return;
371 case 2:
372 use_subshell = FALSE;
373 midnight_shutdown = 1;
374 return;
376 #endif /* HAVE_GETSID */
378 /* Take the current (hopefully pristine) tty mode and make */
379 /* a raw mode based on it now, before we do anything else with it */
380 init_raw_mode ();
382 if (subshell_pty == 0) { /* First time through */
383 /* Find out what type of shell we have */
385 if (strstr (shell, "/zsh") || getenv ("ZSH_VERSION"))
386 subshell_type = ZSH;
387 else if (strstr (shell, "/tcsh"))
388 subshell_type = TCSH;
389 else if (strstr (shell, "/bash") || getenv ("BASH"))
390 subshell_type = BASH;
391 else {
392 use_subshell = FALSE;
393 return;
396 /* Open a pty for talking to the subshell */
398 /* FIXME: We may need to open a fresh pty each time on SVR4 */
400 subshell_pty = pty_open_master (pty_name);
401 if (subshell_pty == -1) {
402 fprintf (stderr, "Cannot open master side of pty: %s\r\n",
403 unix_error_string (errno));
404 use_subshell = FALSE;
405 return;
407 subshell_pty_slave = pty_open_slave (pty_name);
408 if (subshell_pty_slave == -1) {
409 fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
410 pty_name, unix_error_string (errno));
411 use_subshell = FALSE;
412 return;
415 /* Initialise the pty's I/O buffer */
417 pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
418 pty_buffer = g_malloc (pty_buffer_size);
420 /* Create a pipe for receiving the subshell's CWD */
422 if (subshell_type == TCSH) {
423 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
424 mc_tmpdir (), (int) getpid ());
425 if (mkfifo (tcsh_fifo, 0600) == -1) {
426 fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo,
427 unix_error_string (errno));
428 use_subshell = FALSE;
429 return;
432 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
434 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
435 || (subshell_pipe[WRITE] =
436 open (tcsh_fifo, O_RDWR)) == -1) {
437 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
438 perror (__FILE__": open");
439 use_subshell = FALSE;
440 return;
442 } else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe)) {
443 perror (__FILE__": couldn't create pipe");
444 use_subshell = FALSE;
445 return;
449 /* Fork the subshell */
451 subshell_alive = TRUE;
452 subshell_stopped = FALSE;
453 subshell_pid = fork ();
455 if (subshell_pid == -1) {
456 fprintf (stderr, "Cannot spawn the subshell process: %s\r\n",
457 unix_error_string (errno));
458 /* We exit here because, if the process table is full, the */
459 /* other method of running user commands won't work either */
460 exit (1);
463 if (subshell_pid == 0) { /* We are in the child process */
464 init_subshell_child (pty_name);
467 /* Set up `precmd' or equivalent for reading the subshell's CWD */
469 switch (subshell_type) {
470 case BASH:
471 g_snprintf (precmd, sizeof (precmd),
472 " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
473 subshell_pipe[WRITE]);
474 break;
476 case ZSH:
477 g_snprintf (precmd, sizeof (precmd),
478 " precmd(){ pwd>&%d;kill -STOP $$ }\n",
479 subshell_pipe[WRITE]);
480 break;
482 case TCSH:
483 g_snprintf (precmd, sizeof (precmd),
484 "set echo_style=both;"
485 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
486 tcsh_fifo);
487 break;
489 write_all (subshell_pty, precmd, strlen (precmd));
491 /* Wait until the subshell has started up and processed the command */
493 subshell_state = RUNNING_COMMAND;
494 enable_interrupt_key ();
495 if (!feed_subshell (QUIETLY, TRUE)) {
496 use_subshell = FALSE;
498 disable_interrupt_key ();
499 if (!subshell_alive)
500 use_subshell = FALSE; /* Subshell died instantly, so don't use it */
504 static void init_raw_mode ()
506 static int initialized = 0;
508 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
509 /* original settings. However, here we need to make this tty very raw, */
510 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
511 /* pty. So, instead of changing the code for execute(), pre_exec(), */
512 /* etc, we just set up the modes we need here, before each command. */
514 if (initialized == 0) /* First time: initialise `raw_mode' */
516 tcgetattr (STDOUT_FILENO, &raw_mode);
517 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
518 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
519 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
520 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
521 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
522 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
523 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
524 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
525 initialized = 1;
530 int invoke_subshell (const char *command, int how, char **new_dir)
532 /* Make the MC terminal transparent */
533 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
535 /* Make the subshell change to MC's working directory */
536 if (new_dir)
537 do_subshell_chdir (current_panel->cwd, TRUE, 1);
539 if (command == NULL) /* The user has done "C-o" from MC */
541 if (subshell_state == INACTIVE)
543 subshell_state = ACTIVE;
544 /* FIXME: possibly take out this hack; the user can
545 re-play it by hitting C-hyphen a few times! */
546 write_all (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
549 else /* MC has passed us a user command */
551 if (how == QUIETLY)
552 write_all (subshell_pty, " ", 1);
553 /* FIXME: if command is long (>8KB ?) we go comma */
554 write_all (subshell_pty, command, strlen (command));
555 write_all (subshell_pty, "\n", 1);
556 subshell_state = RUNNING_COMMAND;
557 subshell_ready = FALSE;
560 feed_subshell (how, FALSE);
562 if (new_dir && subshell_alive && strcmp (subshell_cwd, current_panel->cwd))
563 *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
565 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
566 while (!subshell_alive && !quit && use_subshell)
567 init_subshell ();
569 prompt_pos = 0;
571 return quit;
576 read_subshell_prompt (void)
578 static int prompt_size = INITIAL_PROMPT_SIZE;
579 int bytes = 0, i, rc = 0;
580 struct timeval timeleft = { 0, 0 };
582 fd_set tmp;
583 FD_ZERO (&tmp);
584 FD_SET (subshell_pty, &tmp);
586 if (subshell_prompt == NULL) { /* First time through */
587 subshell_prompt = g_malloc (prompt_size);
588 *subshell_prompt = '\0';
589 prompt_pos = 0;
592 while (subshell_alive
593 && (rc =
594 select (subshell_pty + 1, &tmp, NULL, NULL, &timeleft))) {
595 /* Check for `select' errors */
596 if (rc == -1) {
597 if (errno == EINTR)
598 continue;
599 else {
600 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n",
601 unix_error_string (errno));
602 exit (1);
606 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
608 /* Extract the prompt from the shell output */
610 for (i = 0; i < bytes; ++i)
611 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r') {
612 prompt_pos = 0;
613 } else {
614 if (!pty_buffer[i])
615 continue;
617 subshell_prompt[prompt_pos++] = pty_buffer[i];
618 if (prompt_pos == prompt_size)
619 subshell_prompt =
620 g_realloc (subshell_prompt, prompt_size *= 2);
623 subshell_prompt[prompt_pos] = '\0';
625 if (rc == 0 && bytes == 0)
626 return FALSE;
627 return TRUE;
630 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
631 static int resize_tty (int fd)
633 #if defined TIOCSWINSZ
634 struct winsize tty_size;
636 tty_size.ws_row = LINES;
637 tty_size.ws_col = COLS;
638 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
640 return ioctl (fd, TIOCSWINSZ, &tty_size);
641 #else
642 return 0;
643 #endif
646 /* Resize subshell_pty */
647 void resize_subshell (void)
649 if (use_subshell == 0)
650 return;
652 resize_tty (subshell_pty);
656 exit_subshell (void)
658 int subshell_quit = TRUE;
660 if (subshell_state != INACTIVE && subshell_alive)
661 subshell_quit =
662 !query_dialog (_("Warning"),
663 _(" The shell is still active. Quit anyway? "),
664 D_NORMAL, 2, _("&Yes"), _("&No"));
666 if (subshell_quit) {
667 if (subshell_type == TCSH) {
668 if (unlink (tcsh_fifo) == -1)
669 fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
670 tcsh_fifo, unix_error_string (errno));
673 g_free (subshell_prompt);
674 g_free (pty_buffer);
675 subshell_prompt = NULL;
676 pty_buffer = NULL;
679 return subshell_quit;
684 * Carefully quote directory name to allow entering any directory safely,
685 * no matter what weird characters it may contain in its name.
686 * NOTE: Treat directory name an untrusted data, don't allow it to cause
687 * executing any commands in the shell. Escape all control characters.
688 * Use following technique:
690 * printf(1) with format string containing a single conversion specifier,
691 * "b", and an argument which contains a copy of the string passed to
692 * subshell_name_quote() with all characters, except digits and letters,
693 * replaced by the backslash-escape sequence \0nnn, where "nnn" is the
694 * numeric value of the character converted to octal number.
696 * cd "`printf "%b" 'ABC\0nnnDEF\0nnnXYZ'`"
699 static char *
700 subshell_name_quote (const char *s)
702 char *ret, *d;
703 const char quote_cmd_start[] = "\"`printf \"%b\" '";
704 const char quote_cmd_end[] = "'`\"";
706 /* Factor 5 because we need \, 0 and 3 other digits per character. */
707 d = ret = g_malloc (1 + (5 * strlen (s)) + (sizeof(quote_cmd_start) - 1)
708 + (sizeof(quote_cmd_end) - 1));
709 if (!d)
710 return NULL;
712 /* Prevent interpreting leading `-' as a switch for `cd' */
713 if (*s == '-') {
714 *d++ = '.';
715 *d++ = '/';
718 /* Copy the beginning of the command to the buffer */
719 strcpy (d, quote_cmd_start);
720 d += sizeof(quote_cmd_start) - 1;
723 * Print every character except digits and letters as a backslash-escape
724 * sequence of the form \0nnn, where "nnn" is the numeric value of the
725 * character converted to octal number.
727 for (; *s; s++) {
728 if (isalnum ((unsigned char) *s)) {
729 *d++ = (unsigned char) *s;
730 } else {
731 sprintf (d, "\\0%03o", (unsigned char) *s);
732 d += 5;
736 strcpy (d, quote_cmd_end);
738 return ret;
742 /* If it actually changed the directory it returns true */
743 void
744 do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
746 if (!
747 (subshell_state == INACTIVE
748 && strcmp (subshell_cwd, current_panel->cwd))) {
749 /* We have to repaint the subshell prompt if we read it from
750 * the main program. Please note that in the code after this
751 * if, the cd command that is sent will make the subshell
752 * repaint the prompt, so we don't have to paint it. */
753 if (do_update)
754 do_update_prompt ();
755 return;
758 /* The initial space keeps this out of the command history (in bash
759 because we set "HISTCONTROL=ignorespace") */
760 write_all (subshell_pty, " cd ", 4);
761 if (*directory) {
762 char *temp = subshell_name_quote (directory);
763 if (temp) {
764 write_all (subshell_pty, temp, strlen (temp));
765 g_free (temp);
766 } else {
767 /* Should not happen unless the directory name is so long
768 that we don't have memory to quote it. */
769 write_all (subshell_pty, ".", 1);
771 } else {
772 write_all (subshell_pty, "/", 1);
774 write_all (subshell_pty, "\n", 1);
776 subshell_state = RUNNING_COMMAND;
777 feed_subshell (QUIETLY, FALSE);
779 if (subshell_alive) {
780 int bPathNotEq = strcmp (subshell_cwd, current_panel->cwd);
782 if (bPathNotEq && subshell_type == TCSH) {
783 char rp_subshell_cwd[PATH_MAX];
784 char rp_current_panel_cwd[PATH_MAX];
786 char *p_subshell_cwd =
787 mc_realpath (subshell_cwd, rp_subshell_cwd);
788 char *p_current_panel_cwd =
789 mc_realpath (current_panel->cwd, rp_current_panel_cwd);
791 if (p_subshell_cwd == NULL)
792 p_subshell_cwd = subshell_cwd;
793 if (p_current_panel_cwd == NULL)
794 p_current_panel_cwd = current_panel->cwd;
795 bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd);
798 if (bPathNotEq && strcmp (current_panel->cwd, ".")) {
799 char *cwd = strip_password (g_strdup (current_panel->cwd), 1);
800 fprintf (stderr, _("Warning: Cannot change to %s.\n"), cwd);
801 g_free (cwd);
805 if (reset_prompt)
806 prompt_pos = 0;
807 update_prompt = FALSE;
808 /* Make sure that MC never stores the CWD in a silly format */
809 /* like /usr////lib/../bin, or the strcmp() above will fail */
813 void
814 subshell_get_console_attributes (void)
816 /* Get our current terminal modes */
818 if (tcgetattr (STDOUT_FILENO, &shell_mode)) {
819 fprintf (stderr, "Cannot get terminal settings: %s\r\n",
820 unix_error_string (errno));
821 use_subshell = FALSE;
822 return;
827 /* Figure out whether the subshell has stopped, exited or been killed */
828 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
829 void
830 sigchld_handler (int sig)
832 int status;
833 pid_t pid;
835 (void) sig;
837 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
839 if (pid == subshell_pid) {
840 /* Figure out what has happened to the subshell */
842 if (WIFSTOPPED (status)) {
843 if (WSTOPSIG (status) == SIGSTOP) {
844 /* The subshell has received a SIGSTOP signal */
845 subshell_stopped = TRUE;
846 } else {
847 /* The user has suspended the subshell. Revive it */
848 kill (subshell_pid, SIGCONT);
850 } else {
851 /* The subshell has either exited normally or been killed */
852 subshell_alive = FALSE;
853 delete_select_channel (subshell_pty);
854 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
855 quit |= SUBSHELL_EXIT; /* Exited normally */
858 #ifdef __linux__
859 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
861 if (pid == cons_saver_pid) {
863 if (WIFSTOPPED (status))
864 /* Someone has stopped cons.saver - restart it */
865 kill (pid, SIGCONT);
866 else {
867 /* cons.saver has died - disable confole saving */
868 handle_console (CONSOLE_DONE);
869 console_flag = 0;
873 #endif /* __linux__ */
875 /* If we got here, some other child exited; ignore it */
879 /* Feed the subshell our keyboard input until it says it's finished */
880 static int
881 feed_subshell (int how, int fail_on_error)
883 fd_set read_set; /* For `select' */
884 int maxfdp;
885 int bytes; /* For the return value from `read' */
886 int i; /* Loop counter */
888 struct timeval wtime; /* Maximum time we wait for the subshell */
889 struct timeval *wptr;
891 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
892 wtime.tv_sec = 10;
893 wtime.tv_usec = 0;
894 wptr = fail_on_error ? &wtime : NULL;
896 while (1) {
897 if (!subshell_alive)
898 return FALSE;
900 /* Prepare the file-descriptor set and call `select' */
902 FD_ZERO (&read_set);
903 FD_SET (subshell_pty, &read_set);
904 FD_SET (subshell_pipe[READ], &read_set);
905 maxfdp = max (subshell_pty, subshell_pipe[READ]);
906 if (how == VISIBLY) {
907 FD_SET (STDIN_FILENO, &read_set);
908 maxfdp = max (maxfdp, STDIN_FILENO);
911 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1) {
913 /* Despite using SA_RESTART, we still have to check for this */
914 if (errno == EINTR)
915 continue; /* try all over again */
916 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
917 fprintf (stderr, "select (FD_SETSIZE, &read_set...): %s\r\n",
918 unix_error_string (errno));
919 exit (1);
922 if (FD_ISSET (subshell_pty, &read_set))
923 /* Read from the subshell, write to stdout */
925 /* This loop improves performance by reducing context switches
926 by a factor of 20 or so... unfortunately, it also hangs MC
927 randomly, because of an apparent Linux bug. Investigate. */
928 /* for (i=0; i<5; ++i) * FIXME -- experimental */
930 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
932 /* The subshell has died */
933 if (bytes == -1 && errno == EIO && !subshell_alive)
934 return FALSE;
936 if (bytes <= 0) {
937 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
938 fprintf (stderr, "read (subshell_pty...): %s\r\n",
939 unix_error_string (errno));
940 exit (1);
943 if (how == VISIBLY)
944 write_all (STDOUT_FILENO, pty_buffer, bytes);
947 else if (FD_ISSET (subshell_pipe[READ], &read_set))
948 /* Read the subshell's CWD and capture its prompt */
951 bytes =
952 read (subshell_pipe[READ], subshell_cwd,
953 MC_MAXPATHLEN + 1);
954 if (bytes <= 0) {
955 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
956 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n",
957 unix_error_string (errno));
958 exit (1);
961 subshell_cwd[bytes - 1] = 0; /* Squash the final '\n' */
963 synchronize ();
965 subshell_ready = TRUE;
966 if (subshell_state == RUNNING_COMMAND) {
967 subshell_state = INACTIVE;
968 return 1;
972 else if (FD_ISSET (STDIN_FILENO, &read_set))
973 /* Read from stdin, write to the subshell */
975 bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
976 if (bytes <= 0) {
977 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
978 fprintf (stderr,
979 "read (STDIN_FILENO, pty_buffer...): %s\r\n",
980 unix_error_string (errno));
981 exit (1);
984 for (i = 0; i < bytes; ++i)
985 if (pty_buffer[i] == subshell_switch_key) {
986 write_all (subshell_pty, pty_buffer, i);
987 if (subshell_ready)
988 subshell_state = INACTIVE;
989 return TRUE;
992 write_all (subshell_pty, pty_buffer, bytes);
993 subshell_ready = FALSE;
994 } else {
995 return FALSE;
1001 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1002 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1003 static void synchronize (void)
1005 sigset_t sigchld_mask, old_mask;
1007 sigemptyset (&sigchld_mask);
1008 sigaddset (&sigchld_mask, SIGCHLD);
1009 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
1012 * SIGCHLD should not be blocked, but we unblock it just in case.
1013 * This is known to be useful for cygwin 1.3.12 and older.
1015 sigdelset (&old_mask, SIGCHLD);
1017 /* Wait until the subshell has stopped */
1018 while (subshell_alive && !subshell_stopped)
1019 sigsuspend (&old_mask);
1021 if (subshell_state != ACTIVE) {
1022 /* Discard all remaining data from stdin to the subshell */
1023 tcflush (subshell_pty_slave, TCIFLUSH);
1026 subshell_stopped = FALSE;
1027 kill (subshell_pid, SIGCONT);
1029 sigprocmask (SIG_SETMASK, &old_mask, NULL);
1030 /* We can't do any better without modifying the shell(s) */
1033 /* pty opening functions */
1035 #ifdef HAVE_GRANTPT
1037 /* System V version of pty_open_master */
1039 static int pty_open_master (char *pty_name)
1041 char *slave_name;
1042 int pty_master;
1044 #ifdef HAVE_POSIX_OPENPT
1045 pty_master = posix_openpt(O_RDWR);
1046 #elif HAVE_GETPT
1047 /* getpt () is a GNU extension (glibc 2.1.x) */
1048 pty_master = getpt ();
1049 #elif IS_AIX
1050 strcpy (pty_name, "/dev/ptc");
1051 pty_master = open (pty_name, O_RDWR);
1052 #else
1053 strcpy (pty_name, "/dev/ptmx");
1054 pty_master = open (pty_name, O_RDWR);
1055 #endif
1057 if (pty_master == -1)
1058 return -1;
1060 if (grantpt (pty_master) == -1 /* Grant access to slave */
1061 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
1062 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
1064 close (pty_master);
1065 return -1;
1067 strcpy (pty_name, slave_name);
1068 return pty_master;
1071 /* System V version of pty_open_slave */
1072 static int
1073 pty_open_slave (const char *pty_name)
1075 int pty_slave = open (pty_name, O_RDWR);
1077 if (pty_slave == -1) {
1078 fprintf (stderr, "open (%s, O_RDWR): %s\r\n", pty_name,
1079 unix_error_string (errno));
1080 return -1;
1082 #if !defined(__osf__) && !defined(__linux__)
1083 #if defined (I_FIND) && defined (I_PUSH)
1084 if (!ioctl (pty_slave, I_FIND, "ptem"))
1085 if (ioctl (pty_slave, I_PUSH, "ptem") == -1) {
1086 fprintf (stderr, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
1087 pty_slave, unix_error_string (errno));
1088 close (pty_slave);
1089 return -1;
1092 if (!ioctl (pty_slave, I_FIND, "ldterm"))
1093 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1) {
1094 fprintf (stderr,
1095 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
1096 pty_slave, unix_error_string (errno));
1097 close (pty_slave);
1098 return -1;
1100 #if !defined(sgi) && !defined(__sgi)
1101 if (!ioctl (pty_slave, I_FIND, "ttcompat"))
1102 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1) {
1103 fprintf (stderr,
1104 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
1105 pty_slave, unix_error_string (errno));
1106 close (pty_slave);
1107 return -1;
1109 #endif /* sgi || __sgi */
1110 #endif /* I_FIND && I_PUSH */
1111 #endif /* __osf__ || __linux__ */
1113 fcntl(pty_slave, F_SETFD, FD_CLOEXEC);
1114 return pty_slave;
1117 #else /* !HAVE_GRANTPT */
1119 /* BSD version of pty_open_master */
1120 static int pty_open_master (char *pty_name)
1122 int pty_master;
1123 const char *ptr1, *ptr2;
1125 strcpy (pty_name, "/dev/ptyXX");
1126 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1128 pty_name [8] = *ptr1;
1129 for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
1131 pty_name [9] = *ptr2;
1133 /* Try to open master */
1134 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1135 if (errno == ENOENT) /* Different from EIO */
1136 return -1; /* Out of pty devices */
1137 else
1138 continue; /* Try next pty device */
1140 pty_name [5] = 't'; /* Change "pty" to "tty" */
1141 if (access (pty_name, 6)){
1142 close (pty_master);
1143 pty_name [5] = 'p';
1144 continue;
1146 return pty_master;
1149 return -1; /* Ran out of pty devices */
1152 /* BSD version of pty_open_slave */
1153 static int
1154 pty_open_slave (const char *pty_name)
1156 int pty_slave;
1157 struct group *group_info = getgrnam ("tty");
1159 if (group_info != NULL) {
1160 /* The following two calls will only succeed if we are root */
1161 /* [Commented out while permissions problem is investigated] */
1162 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1163 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1165 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1166 fprintf (stderr, "open (pty_name, O_RDWR): %s\r\n", pty_name);
1167 fcntl(pty_slave, F_SETFD, FD_CLOEXEC);
1168 return pty_slave;
1171 #endif /* !HAVE_GRANTPT */
1172 #endif /* HAVE_SUBSHELL_SUPPORT */