*** empty log message ***
[midnight-commander.git] / src / subshell.c
blob36c56cdfc816d59257f9aabb82ea4a4a826d0054
1 /* {{{ Copyright notice */
3 /* Concurrent shell support for the Midnight Commander
4 Copyright (C) 1994, 1995 Dugan Porter
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of Version 2 of the GNU General Public
8 License, as published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 /* }}} */
22 #include <config.h>
23 #ifdef HAVE_SUBSHELL_SUPPORT
25 /* {{{ Declarations */
27 #ifndef _GNU_SOURCE
28 # define _GNU_SOURCE 1
29 #endif
31 #include <stdio.h>
32 #include <stdlib.h> /* For errno, putenv, etc. */
33 #include <errno.h> /* For errno on SunOS systems */
34 #include <termios.h> /* tcgetattr(), struct termios, etc. */
35 #include <sys/types.h> /* Required by unistd.h below */
36 #ifdef HAVE_SYS_IOCTL_H
37 # include <sys/ioctl.h> /* For ioctl() (surprise, surprise) */
38 #endif
39 #include <fcntl.h> /* For open(), etc. */
40 #include <string.h> /* strstr(), strcpy(), etc. */
41 #include <signal.h> /* sigaction(), sigprocmask(), etc. */
42 #include <sys/stat.h> /* Required by dir.h & panel.h below */
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h> /* For pipe, fork, setsid, access etc */
46 #endif
48 #ifdef HAVE_STROPTS_H
49 # include <stropts.h> /* For I_PUSH */
50 #endif /* HAVE_STROPTS_H */
52 #include "global.h" /* For home_dir */
53 #include "tty.h"
54 #include "dir.h" /* Required by panel.h below */
55 #include "util.h" /* Required by panel.h */
56 #include "panel.h" /* For WPanel and current_panel */
57 #include "dialog.h" /* For query_dialog() */
58 #include "main.h" /* For cpanel, quit & init_sigchld() */
59 #include "cons.saver.h" /* For handle_console(), etc. */
60 #include "key.h" /* XCTRL and ALT macros */
61 #include "subshell.h"
63 #ifndef WEXITSTATUS
64 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
65 #endif
67 #ifndef WIFEXITED
68 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
69 #endif
71 /* Local functions */
72 static void init_raw_mode (void);
73 static int feed_subshell (int how, int fail_on_error);
74 static void synchronize (void);
75 static int pty_open_master (char *pty_name);
76 static int pty_open_slave (const char *pty_name);
77 static int resize_tty (int fd);
79 /* }}} */
80 /* {{{ Definitions */
82 #ifndef STDIN_FILENO
83 # define STDIN_FILENO 0
84 #endif
86 #ifndef STDOUT_FILENO
87 # define STDOUT_FILENO 1
88 #endif
90 #ifndef STDERR_FILENO
91 # define STDERR_FILENO 2
92 #endif
94 /* If using a subshell for evaluating commands this is true */
95 int use_subshell =
96 #ifdef SUBSHELL_OPTIONAL
97 FALSE;
98 #else
99 TRUE;
100 #endif
102 /* File descriptor of the pseudoterminal used by the subshell */
103 int subshell_pty = 0;
105 /* The key for switching back to MC from the subshell */
106 char subshell_switch_key = XCTRL('o');
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};
130 /* Local variables */
132 static char *pty_buffer; /* For reading/writing on the subshell's pty */
133 static int pty_buffer_size; /* The buffer grows as needed */
134 static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
135 static pid_t subshell_pid = 1; /* The subshell's process ID */
136 static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
138 /* Subshell type (gleaned from the SHELL environment variable, if available) */
139 static enum {BASH, TCSH, ZSH} subshell_type;
141 /* Flag to indicate whether the subshell is ready for next command */
142 static int subshell_ready;
144 /* The following two flags can be changed by the SIGCHLD handler. This is */
145 /* OK, because the `int' type is updated atomically on all known machines */
146 static volatile int subshell_alive, subshell_stopped;
148 /* We store the terminal's initial mode here so that we can configure
149 the pty similarly, and also so we can restore the real terminal to
150 sanity if we have to exit abruptly */
151 static struct termios shell_mode;
153 /* This is a transparent mode for the terminal where MC is running on */
154 /* It is used when the shell is active, so that the control signals */
155 /* are delivered to the shell pty */
156 static struct termios raw_mode;
158 /* This counter indicates how many characters of prompt we have read */
159 /* FIXME: try to figure out why this had to become global */
160 static int prompt_pos;
162 /* }}} */
164 #ifdef HAVE_GRANTPT
165 # define SYNC_PTY_SIDES
166 #else
167 # define SYNC_PTY_SIDES
168 #endif
170 #undef SYNC_PTY_SIDES
172 #ifdef SYNC_PTY_SIDES
173 /* Handler for SIGUSR1 (used below), does nothing but accept the signal */
174 static void sigusr1_handler (int sig)
177 #endif
180 * Prepare child process to running the shell and run it.
182 * Modifies the global variables (in the child process only):
183 * shell_mode
185 * Returns: never.
187 static void init_subshell_child (const char *pty_name)
189 int pty_slave;
190 char *init_file = NULL;
192 setsid (); /* Get a fresh terminal session */
194 /* {{{ Open the slave side of the pty: again */
195 pty_slave = pty_open_slave (pty_name);
197 /* This must be done before closing the master side of the pty, */
198 /* or it will fail on certain idiotic systems, such as Solaris. */
200 /* Close master side of pty. This is important; apart from */
201 /* freeing up the descriptor for use in the subshell, it also */
202 /* means that when MC exits, the subshell will get a SIGHUP and */
203 /* exit too, because there will be no more descriptors pointing */
204 /* at the master side of the pty and so it will disappear. */
206 close (subshell_pty);
208 #ifdef SYNC_PTY_SIDES
209 /* Give our parent process (MC) the go-ahead */
210 kill (getppid (), SIGUSR1);
211 #endif
213 /* }}} */
214 /* {{{ Make sure that it has become our controlling terminal */
216 /* Redundant on Linux and probably most systems, but just in case: */
218 #ifdef TIOCSCTTY
219 ioctl (pty_slave, TIOCSCTTY, 0);
220 #endif
222 /* }}} */
223 /* {{{ Configure its terminal modes and window size */
225 /* Set up the pty with the same termios flags as our own tty, plus */
226 /* TOSTOP, which keeps background processes from writing to the pty */
228 shell_mode.c_lflag |= TOSTOP; /* So background writers get SIGTTOU */
229 if (tcsetattr (pty_slave, TCSANOW, &shell_mode))
231 perror (__FILE__": couldn't set pty terminal modes");
232 _exit (FORK_FAILURE);
235 /* Set the pty's size (80x25 by default on Linux) according to the */
236 /* size of the real terminal as calculated by ncurses, if possible */
237 resize_tty (pty_slave);
239 /* }}} */
240 /* {{{ Set up the subshell's environment and init file name */
242 /* It simplifies things to change to our home directory here, */
243 /* and the user's startup file may do a `cd' command anyway */
244 chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
246 switch (subshell_type)
248 case BASH:
249 init_file = ".mc/bashrc";
250 if (access (init_file, R_OK) == -1)
251 init_file = ".bashrc";
253 /* Make MC's special commands not show up in bash's history */
254 putenv ("HISTCONTROL=ignorespace");
256 /* Allow alternative readline settings for MC */
257 if (access (".mc/inputrc", R_OK) == 0)
258 putenv ("INPUTRC=.mc/inputrc");
260 break;
262 case TCSH:
263 init_file = ".mc/tcshrc";
264 if (access (init_file, R_OK) == -1)
265 init_file += 3;
266 break;
268 case ZSH:
269 break;
271 default:
272 fprintf (stderr, __FILE__": unimplemented subshell type %d\n",
273 subshell_type);
274 _exit (FORK_FAILURE);
277 /* }}} */
278 /* {{{ Attach all our standard file descriptors to the pty */
280 /* This is done just before the fork, because stderr must still */
281 /* be connected to the real tty during the above error messages; */
282 /* otherwise the user will never see them. */
284 dup2 (pty_slave, STDIN_FILENO);
285 dup2 (pty_slave, STDOUT_FILENO);
286 dup2 (pty_slave, STDERR_FILENO);
288 /* }}} */
289 /* {{{ Execute the subshell at last */
291 close (subshell_pipe[READ]);
292 close (pty_slave); /* These may be FD_CLOEXEC, but just in case... */
294 switch (subshell_type)
296 case BASH:
297 execl (shell, "bash", "-rcfile", init_file, NULL);
298 break;
300 case TCSH:
301 execl (shell, "tcsh", NULL); /* What's the -rcfile equivalent? */
302 break;
304 case ZSH:
305 /* change from "+Z" to "-Z" by Michael Bramer
306 * (Debian-mc-maintainer) <grisu@debian.org> from a patch from
307 * Radovan Garabik <garabik@center.fmph.uniba.sk>
309 execl (shell, "zsh", "-Z", NULL);
311 break;
314 /* If we get this far, everything failed miserably */
315 _exit (FORK_FAILURE);
317 /* }}} */
320 /* {{{ init_subshell */
323 * Fork the subshell, and set up many, many things.
325 * Possibly modifies the global variables:
326 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
327 * use_subshell - Is set to FALSE if we can't run the subshell
328 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
331 void init_subshell (void)
333 /* {{{ Local variables */
335 /* This must be remembered across calls to init_subshell() */
336 static char pty_name[BUF_SMALL];
337 int pty_slave = -1;
339 /* Braindead tcsh can't redirect output to a file descriptor? */
340 char tcsh_fifo[sizeof "/tmp/mc.pipe.1234567890"];
343 #ifdef SYNC_PTY_SIDES
344 /* Used to wait for a SIGUSR1 signal from the subprocess */
345 sigset_t sigusr1_mask, old_mask;
346 #endif
348 /* }}} */
350 /* Take the current (hopefully pristine) tty mode and make */
351 /* a raw mode based on it now, before we do anything else with it */
352 init_raw_mode ();
354 if (subshell_pty == 0) /* First time through */
356 /* {{{ Find out what type of shell we have */
358 if (strstr (shell, "/zsh"))
359 subshell_type = ZSH;
360 else if (strstr (shell, "/tcsh"))
361 subshell_type = TCSH;
362 else if (strstr (shell, "/bash") || getenv ("BASH"))
363 subshell_type = BASH;
364 else
366 use_subshell = FALSE;
367 return;
370 /* }}} */
371 /* {{{ Open a pty for talking to the subshell */
373 /* FIXME: We may need to open a fresh pty each time on SVR4 */
375 subshell_pty = pty_open_master (pty_name);
376 if (subshell_pty == -1)
378 fputs (__FILE__": couldn't open master side of pty\n", stderr);
379 perror ("pty_open_master");
380 use_subshell = FALSE;
381 return;
383 pty_slave = pty_open_slave (pty_name);
384 if (pty_slave == -1)
386 fprintf (stderr, "couldn't open slave side of pty (%s)\n\r",
387 pty_name);
388 use_subshell = FALSE;
389 return;
393 /* }}} */
394 /* {{{ Initialise the pty's I/O buffer */
396 pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
397 pty_buffer = (char *) g_malloc (pty_buffer_size);
399 /* }}} */
400 /* {{{ Create a pipe for receiving the subshell's CWD */
402 if (subshell_type == TCSH)
404 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "/tmp/mc.pipe.%d", getpid ());
405 if (mkfifo (tcsh_fifo, 0600) == -1)
407 perror (__FILE__": mkfifo");
408 use_subshell = FALSE;
409 return;
412 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
414 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1 ||
415 (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
417 fprintf (stderr, _("Couldn't open named pipe %s\n"), tcsh_fifo);
418 perror (__FILE__": open");
419 use_subshell = FALSE;
420 return;
423 else /* subshell_type is BASH or ZSH */
424 if (pipe (subshell_pipe))
426 perror (__FILE__": couldn't create pipe");
427 use_subshell = FALSE;
428 return;
431 /* }}} */
434 /* {{{ Define a handler for the sigusr1 signal */
436 #ifdef SYNC_PTY_SIDES
437 sigemptyset (&sigusr1_mask);
438 sigaddset (&sigusr1_mask, SIGUSR1);
439 sigprocmask (SIG_BLOCK, &sigusr1_mask, &old_mask);
440 signal (SIGUSR1, sigusr1_handler);
441 #endif
443 /* }}} */
444 /* {{{ Fork the subshell */
446 subshell_alive = TRUE;
447 subshell_stopped = FALSE;
448 subshell_pid = fork ();
450 if (subshell_pid == -1)
452 perror (__FILE__": couldn't spawn the subshell process");
453 /* We exit here because, if the process table is full, the */
454 /* other method of running user commands won't work either */
455 exit (1);
458 /* }}} */
460 if (subshell_pid == 0) /* We are in the child process */
462 init_subshell_child (pty_name);
465 /* pty_slave is only opened when called the first time */
466 if (pty_slave != -1) {
467 close(pty_slave);
470 #ifdef SYNC_PTY_SIDES
471 sigsuspend (&old_mask);
472 signal (SIGUSR1, SIG_DFL);
473 sigprocmask (SIG_SETMASK, &old_mask, NULL);
474 /* ...before installing our handler for SIGCHLD. */
475 #endif
477 #if 0
478 /* {{{ Install our handler for SIGCHLD */
480 init_sigchld ();
482 /* We could have received the SIGCHLD signal for the subshell
483 * before installing the init_sigchld */
484 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
485 if (pid == subshell_pid){
486 use_subshell = FALSE;
487 return;
490 /* }}} */
491 #endif
493 /* {{{ Set up `precmd' or equivalent for reading the subshell's CWD */
495 switch (subshell_type)
497 char precmd[BUF_SMALL];
499 case BASH:
500 g_snprintf (precmd, sizeof (precmd), " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
501 subshell_pipe[WRITE]);
502 goto write_it;
504 case ZSH:
505 g_snprintf (precmd, sizeof (precmd), "precmd(){ pwd>&%d;kill -STOP $$ }\n",
506 subshell_pipe[WRITE]);
507 goto write_it;
509 case TCSH:
510 g_snprintf (precmd, sizeof (precmd),
511 "set echo_style=both;"
512 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
513 tcsh_fifo);
515 write_it:
516 write (subshell_pty, precmd, strlen (precmd));
519 /* }}} */
520 /* {{{ Wait until the subshell has started up and processed the command */
522 subshell_state = RUNNING_COMMAND;
523 enable_interrupt_key ();
524 if (!feed_subshell (QUIETLY, TRUE)){
525 use_subshell = FALSE;
527 disable_interrupt_key ();
528 if (!subshell_alive)
529 use_subshell = FALSE; /* Subshell died instantly, so don't use it */
531 /* }}} */
534 /* }}} */
536 static void init_raw_mode ()
538 static int initialized = 0;
540 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
541 /* original settings. However, here we need to make this tty very raw, */
542 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
543 /* pty. So, instead of changing the code for execute(), pre_exec(), */
544 /* etc, we just set up the modes we need here, before each command. */
546 if (initialized == 0) /* First time: initialise `raw_mode' */
548 tcgetattr (STDOUT_FILENO, &raw_mode);
549 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
550 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
551 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
552 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
553 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
554 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
555 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
556 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
557 initialized = 1;
561 /* {{{ invoke_subshell */
563 int invoke_subshell (const char *command, int how, char **new_dir)
565 /* {{{ Make the MC terminal transparent */
567 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
569 /* }}} */
571 /* Make the subshell change to MC's working directory */
572 if (new_dir)
573 do_subshell_chdir (cpanel->cwd, TRUE, 1);
575 if (command == NULL) /* The user has done "C-o" from MC */
577 if (subshell_state == INACTIVE)
579 subshell_state = ACTIVE;
580 /* FIXME: possibly take out this hack; the user can
581 re-play it by hitting C-hyphen a few times! */
582 write (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
585 else /* MC has passed us a user command */
587 if (how == QUIETLY)
588 write (subshell_pty, " ", 1);
589 /* FIXME: if command is long (>8KB ?) we go comma */
590 write (subshell_pty, command, strlen (command));
591 write (subshell_pty, "\n", 1);
592 subshell_state = RUNNING_COMMAND;
593 subshell_ready = FALSE;
596 feed_subshell (how, FALSE);
598 if (new_dir && subshell_alive && strcmp (subshell_cwd, cpanel->cwd))
599 *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
601 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
602 while (!subshell_alive && !quit && use_subshell)
603 init_subshell ();
605 prompt_pos = 0;
607 return quit;
610 /* }}} */
611 /* {{{ read_subshell_prompt */
613 int read_subshell_prompt (void)
615 /* {{{ Local variables */
617 static int prompt_size = INITIAL_PROMPT_SIZE;
618 int bytes = 0, i, rc = 0;
619 struct timeval timeleft = {0, 0};
621 fd_set tmp;
622 FD_ZERO (&tmp);
623 FD_SET (subshell_pty, &tmp);
625 /* }}} */
627 if (subshell_prompt == NULL) /* First time through */
629 subshell_prompt = (char *) g_malloc (prompt_size);
630 *subshell_prompt = '\0';
631 prompt_pos = 0;
634 while (subshell_alive &&
635 (rc = select (subshell_pty + 1, &tmp, NULL, NULL, &timeleft)))
637 /* {{{ Check for `select' errors */
639 if (rc == -1) {
640 if (errno == EINTR)
641 continue;
642 else {
643 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
644 perror ("\n"__FILE__": select (FD_SETSIZE, &tmp...)");
645 exit (1);
649 /* }}} */
651 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
653 /* {{{ Extract the prompt from the shell output */
655 for (i=0; i<bytes; ++i)
656 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r'){
657 prompt_pos = 0;
658 } else {
659 if (!pty_buffer [i])
660 continue;
662 subshell_prompt[prompt_pos++] = pty_buffer[i];
663 if (prompt_pos == prompt_size)
664 subshell_prompt = (char *) g_realloc (subshell_prompt,
665 prompt_size *= 2);
668 subshell_prompt[prompt_pos] = '\0';
670 /* }}} */
672 if (rc == 0 && bytes == 0)
673 return FALSE;
674 return TRUE;
677 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
678 static int resize_tty (int fd)
680 #if defined TIOCSWINSZ && !defined SCO_FLAVOR
681 struct winsize tty_size;
683 tty_size.ws_row = LINES;
684 tty_size.ws_col = COLS;
685 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
687 return ioctl (fd, TIOCSWINSZ, &tty_size);
688 #endif
691 /* Resize subshell_pty */
692 void resize_subshell (void)
694 resize_tty (subshell_pty);
697 int exit_subshell (void)
699 int quit = TRUE;
701 if (subshell_state != INACTIVE && subshell_alive)
702 quit = !query_dialog (_(" Warning "), _(" The shell is still active. Quit anyway? "),
703 0, 2, _("&Yes"), _("&No"));
705 if (quit && subshell_type == TCSH)
707 /* We abuse of pty_buffer here, but it doesn't matter at this stage */
708 g_snprintf (pty_buffer, pty_buffer_size, "/tmp/mc.pipe.%d", getpid ());
709 if (unlink (pty_buffer) == -1)
710 perror (__FILE__": couldn't remove named pipe /tmp/mc.pipe.NNN");
713 g_free (subshell_prompt);
714 subshell_prompt = NULL;
716 return quit;
719 /* }}} */
722 * Carefully quote directory name to allow entering any directory safely,
723 * no matter what weird characters it may contain in its name.
724 * NOTE: Treat directory name an untrusted data, don't allow it to cause
725 * executing any commands in the shell. Escape all control characters.
726 * Use following technique:
728 * for bash - echo with `-e', 3-digit octal numbers:
729 * cd "`echo -e '\ooo...\ooo'`"
731 * for zsh and tcsh - echo without `-e', 4-digit octal numbers:
732 * cd "`echo '\oooo...\oooo'`"
734 static char *
735 subshell_name_quote (const char *s)
737 char *ret, *d;
738 const char bash_start[] = "\"`echo -e '";
739 const char nonbash_start[] = "\"`echo '";
740 const char common_end[] = "'`\"";
743 * Factor 5 because we need \, 0 and 3 other digits per character
744 * in the worst case (tcsh and zsh).
746 d = ret = g_malloc (5 * strlen (s) + 16);
748 /* Prevent interpreting leading `-' as a switch for `cd' */
749 if (*s == '-') {
750 *d++ = '.';
751 *d++ = '/';
755 * Print every character in octal format with the leading backslash.
756 * tcsh and zsh require leading 0, bash doesn't like 4-digit octals
757 * and requires `-e' for echo.
759 if (subshell_type == BASH) {
760 memcpy (d, bash_start, sizeof (bash_start) - 1);
761 d += sizeof (bash_start) - 1;
762 for (; *s; s++) {
763 sprintf(d, "\\%03o", (unsigned char) *s);
764 d += 4;
766 } else {
767 memcpy (d, nonbash_start, sizeof (nonbash_start) - 1);
768 d += sizeof (nonbash_start) - 1;
769 for (; *s; s++) {
770 sprintf(d, "\\0%03o", (unsigned char) *s);
771 d += 5;
775 memcpy (d, common_end, sizeof (common_end));
777 return ret;
782 /* {{{ do_subshell_chdir */
783 /* If it actually changed the directory it returns true */
784 void do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
786 if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, cpanel->cwd))){
787 /* We have to repaint the subshell prompt if we read it from
788 * the main program. Please note that in the code after this
789 * if, the cd command that is sent will make the subshell
790 * repaint the prompt, so we don't have to paint it. */
791 if (do_update)
792 do_update_prompt ();
793 return;
796 /* The initial space keeps this out of the command history (in bash
797 because we set "HISTCONTROL=ignorespace") */
798 write (subshell_pty, " cd ", 4);
799 if (*directory) {
800 char *temp;
801 temp = subshell_name_quote (directory);
802 write (subshell_pty, temp, strlen (temp));
803 g_free (temp);
804 } else {
805 write (subshell_pty, "/", 1);
807 write (subshell_pty, "\n", 1);
809 subshell_state = RUNNING_COMMAND;
810 feed_subshell (QUIETLY, FALSE);
812 if (subshell_alive && strcmp (subshell_cwd, cpanel->cwd) && strcmp (cpanel->cwd, "."))
813 fprintf (stderr, _("Warning: Couldn't change to %s.\n"), cpanel->cwd);
815 if (reset_prompt)
816 prompt_pos = 0;
817 update_prompt = FALSE;
818 /* Make sure that MC never stores the CWD in a silly format */
819 /* like /usr////lib/../bin, or the strcmp() above will fail */
822 /* }}} */
823 /* {{{ subshell_get_console_attributes */
825 void subshell_get_console_attributes (void)
827 /* {{{ Get our current terminal modes */
829 if (tcgetattr (STDOUT_FILENO, &shell_mode))
831 perror (__FILE__": couldn't get terminal settings");
832 use_subshell = FALSE;
833 return;
836 /* }}} */
839 /* }}} */
840 /* {{{ sigchld_handler */
842 /* Figure out whether the subshell has stopped, exited or been killed */
843 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
845 void sigchld_handler (int sig)
847 int status;
848 pid_t pid;
850 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
852 if (pid == subshell_pid) {
853 /* {{{ Figure out what has happened to the subshell */
855 if (WIFSTOPPED (status))
857 if (WSTOPSIG (status) == SIGSTOP) {
858 /* The subshell has received a SIGSTOP signal */
859 subshell_stopped = TRUE;
860 } else {
861 /* The user has suspended the subshell. Revive it */
862 kill (subshell_pid, SIGCONT);
865 else /* The subshell has either exited normally or been killed */
867 subshell_alive = FALSE;
868 delete_select_channel (subshell_pty);
869 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
870 quit |= SUBSHELL_EXIT; /* Exited normally */
873 /* }}} */
876 #if defined(linux) || defined(__linux__)
877 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
879 if (pid == cons_saver_pid) {
881 if (WIFSTOPPED (status))
882 /* Someone has stopped cons.saver - restart it */
883 kill (pid, SIGCONT);
884 else
886 /* cons.saver has died - disable confole saving */
887 handle_console (CONSOLE_DONE);
888 console_flag = 0;
892 #endif /* linux || __linux__ */
893 /* If we get here, some other child exited; ignore it */
894 # ifdef __EMX__ /* Need to report */
895 pid = wait(&status);
896 # endif
899 /* }}} */
901 /* {{{ feed_subshell */
903 /* Feed the subshell our keyboard input until it says it's finished */
905 static int feed_subshell (int how, int fail_on_error)
907 /* {{{ Local variables */
908 fd_set read_set; /* For `select' */
909 int maxfdp;
910 int bytes; /* For the return value from `read' */
911 int i; /* Loop counter */
913 struct timeval wtime; /* Maximum time we wait for the subshell */
914 struct timeval *wptr;
915 /* }}} */
917 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
918 wtime.tv_sec = 10;
919 wtime.tv_usec = 0;
920 wptr = fail_on_error ? &wtime : NULL;
922 while (1) {
923 if (!subshell_alive)
924 return FALSE;
926 /* {{{ Prepare the file-descriptor set and call `select' */
928 FD_ZERO (&read_set);
929 FD_SET (subshell_pty, &read_set);
930 FD_SET (subshell_pipe[READ], &read_set);
931 maxfdp = max (subshell_pty, subshell_pipe[READ]);
932 if (how == VISIBLY) {
933 FD_SET (STDIN_FILENO, &read_set);
934 maxfdp = max (maxfdp, STDIN_FILENO);
937 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1){
939 /* Despite using SA_RESTART, we still have to check for this */
940 if (errno == EINTR)
941 continue; /* try all over again */
942 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
943 perror ("\n"__FILE__": select (FD_SETSIZE, &read_set...)");
944 exit (1);
946 /* }}} */
948 if (FD_ISSET (subshell_pty, &read_set))
949 /* {{{ Read from the subshell, write to stdout */
951 /* This loop improves performance by reducing context switches
952 by a factor of 20 or so... unfortunately, it also hangs MC
953 randomly, because of an apparent Linux bug. Investigate. */
954 /* for (i=0; i<5; ++i) * FIXME -- experimental */
956 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
958 /* The subshell has died */
959 if (bytes == -1 && errno == EIO && !subshell_alive)
960 return FALSE;
962 if (bytes <= 0)
964 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
965 perror ("\n"__FILE__": read (subshell_pty...)");
966 exit (1);
969 if (how == VISIBLY)
970 write (STDOUT_FILENO, pty_buffer, bytes);
973 /* }}} */
975 else if (FD_ISSET (subshell_pipe[READ], &read_set))
976 /* {{{ Read the subshell's CWD and capture its prompt */
979 bytes = read (subshell_pipe[READ], subshell_cwd, MC_MAXPATHLEN+1);
980 if (bytes <= 0)
982 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
983 perror ("\n"__FILE__": read (subshell_pipe[READ]...)");
984 exit (1);
987 subshell_cwd[bytes-1] = 0; /* Squash the final '\n' */
989 synchronize ();
991 subshell_ready = TRUE;
992 if (subshell_state == RUNNING_COMMAND)
994 subshell_state = INACTIVE;
995 return 1;
999 /* }}} */
1001 else if (FD_ISSET (STDIN_FILENO, &read_set))
1002 /* {{{ Read from stdin, write to the subshell */
1005 bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
1006 if (bytes <= 0)
1008 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1009 perror ("\n"__FILE__": read (STDIN_FILENO, pty_buffer...)");
1010 exit (1);
1013 for (i=0; i<bytes; ++i)
1014 if (pty_buffer[i] == subshell_switch_key)
1016 write (subshell_pty, pty_buffer, i);
1017 if (subshell_ready)
1018 subshell_state = INACTIVE;
1019 return TRUE;
1022 write (subshell_pty, pty_buffer, bytes);
1023 subshell_ready = FALSE;
1024 } else {
1025 return FALSE;
1028 /* }}} */
1032 /* }}} */
1033 /* {{{ synchronize */
1035 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1036 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1038 static void synchronize (void)
1040 sigset_t sigchld_mask, old_mask;
1042 sigemptyset (&sigchld_mask);
1043 sigaddset (&sigchld_mask, SIGCHLD);
1044 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
1047 * SIGCHLD should not be blocked, but we unblock it just in case.
1048 * This is known to be useful for cygwin 1.3.12 and older.
1050 sigdelset (&old_mask, SIGCHLD);
1052 /* Wait until the subshell has stopped */
1053 while (subshell_alive && !subshell_stopped)
1054 sigsuspend (&old_mask);
1056 /* Discard all remaining data from stdin to the subshell */
1057 tcflush (subshell_pty, TCOFLUSH);
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 /* }}} */
1067 /* {{{ pty opening functions */
1069 #ifdef SCO_FLAVOR
1071 /* {{{ SCO version of pty_open_master */
1073 static int pty_open_master (char *pty_name)
1075 int pty_master;
1076 int num;
1077 char *ptr;
1079 strcpy (pty_name, "/dev/ptyp");
1080 ptr = pty_name+9;
1081 for (num=0;;num++)
1083 g_snprintf(ptr, 9, "%d",num); /* surpriiise ... SCO lacks itoa() */
1084 /* Try to open master */
1085 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1086 if (errno == ENOENT) /* Different from EIO */
1087 return -1; /* Out of pty devices */
1088 else
1089 continue; /* Try next pty device */
1091 pty_name [5] = 't'; /* Change "pty" to "tty" */
1092 if (access (pty_name, 6)){
1093 close (pty_master);
1094 pty_name [5] = 'p';
1095 continue;
1097 return pty_master;
1099 return -1; /* Ran out of pty devices */
1102 /* }}} */
1103 /* {{{ SCO version of pty_open_slave */
1105 static int pty_open_slave (const char *pty_name)
1107 int pty_slave;
1108 struct group *group_info = getgrnam ("terminal");
1110 if (group_info != NULL)
1112 /* The following two calls will only succeed if we are root */
1113 /* [Commented out while permissions problem is investigated] */
1114 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1115 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1117 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1118 perror ("open (pty_name, O_RDWR)");
1119 return pty_slave;
1122 /* }}} */
1124 #elif HAVE_GRANTPT /* !HAVE_SCO */
1126 /* {{{ System V version of pty_open_master */
1128 static int pty_open_master (char *pty_name)
1130 char *slave_name;
1131 int pty_master;
1134 #ifdef HAVE_GETPT
1135 /* getpt () is a GNU extension (glibc 2.1.x) */
1136 pty_master = getpt ();
1137 #else
1138 strcpy (pty_name, "/dev/ptmx");
1139 pty_master = open (pty_name, O_RDWR);
1140 #endif
1141 if (pty_master == -1)
1142 return -1;
1144 if (grantpt (pty_master) == -1 /* Grant access to slave */
1145 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
1146 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
1148 close (pty_master);
1149 return -1;
1151 strcpy (pty_name, slave_name);
1152 return pty_master;
1155 /* }}} */
1156 /* {{{ System V version of pty_open_slave */
1158 static int pty_open_slave (const char *pty_name)
1160 int pty_slave = open (pty_name, O_RDWR);
1162 if (pty_slave == -1)
1164 perror ("open (pty_name, O_RDWR)");
1165 return -1;
1168 #if !defined(__osf__) && !defined(linux) && !defined(__linux__)
1169 #if defined (I_FIND) && defined (I_PUSH)
1170 if (!ioctl (pty_slave, I_FIND, "ptem"))
1171 if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
1173 fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ptem\") failed\n");
1174 close (pty_slave);
1175 return -1;
1178 if (!ioctl (pty_slave, I_FIND, "ldterm"))
1179 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
1181 fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ldterm\") failed\n");
1182 close (pty_slave);
1183 return -1;
1186 #if !defined(sgi) && !defined(__sgi)
1187 if (!ioctl (pty_slave, I_FIND, "ttcompat"))
1188 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
1190 fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ttcompat\") failed\n");
1191 close (pty_slave);
1192 return -1;
1194 #endif /* sgi || __sgi */
1195 #endif /* I_FIND && I_PUSH */
1196 #endif /* __osf__ || linux || __linux__ */
1198 return pty_slave;
1201 /* }}} */
1203 #else /* !HAVE_SCO && !HAVE_GRANTPT */
1205 /* {{{ BSD version of pty_open_master */
1207 static int pty_open_master (char *pty_name)
1209 int pty_master;
1210 char *ptr1, *ptr2;
1212 strcpy (pty_name, "/dev/ptyXX");
1213 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1215 pty_name [8] = *ptr1;
1216 for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
1218 pty_name [9] = *ptr2;
1220 /* Try to open master */
1221 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1222 if (errno == ENOENT) /* Different from EIO */
1223 return -1; /* Out of pty devices */
1224 else
1225 continue; /* Try next pty device */
1227 pty_name [5] = 't'; /* Change "pty" to "tty" */
1228 if (access (pty_name, 6)){
1229 close (pty_master);
1230 pty_name [5] = 'p';
1231 continue;
1233 return pty_master;
1236 return -1; /* Ran out of pty devices */
1239 /* }}} */
1240 /* {{{ BSD version of pty_open_slave */
1242 static int pty_open_slave (const char *pty_name)
1244 int pty_slave;
1245 struct group *group_info = getgrnam ("tty");
1247 if (group_info != NULL)
1249 /* The following two calls will only succeed if we are root */
1250 /* [Commented out while permissions problem is investigated] */
1251 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1252 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1254 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1255 perror ("open (pty_name, O_RDWR)");
1256 return pty_slave;
1259 /* }}} */
1261 #endif /* !HAVE_SCO && !HAVE_GRANTPT */
1263 /* }}} */
1265 #endif /* HAVE_SUBSHELL_SUPPORT */
1267 /* {{{ Emacs local variables */
1270 Cause emacs to enter folding mode for this file:
1271 Local variables:
1272 end:
1275 /* }}} */