*** empty log message ***
[midnight-commander.git] / src / subshell.c
blob597bc5338e4d79ece32d76ef307769b4acf37db4
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 #ifdef __QNX__
53 # include <unix.h> /* exec*() from <process.h> */
54 #endif
56 #include "global.h" /* For home_dir */
57 #include "tty.h"
58 #include "dir.h" /* Required by panel.h below */
59 #include "util.h" /* Required by panel.h */
60 #include "panel.h" /* For WPanel and current_panel */
61 #include "dialog.h" /* For query_dialog() */
62 #include "main.h" /* For cpanel, quit & init_sigchld() */
63 #include "cons.saver.h" /* For handle_console(), etc. */
64 #include "key.h" /* XCTRL and ALT macros */
65 #include "subshell.h"
67 #ifndef WEXITSTATUS
68 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
69 #endif
71 #ifndef WIFEXITED
72 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
73 #endif
75 /* Local functions */
76 static void init_raw_mode (void);
77 static int feed_subshell (int how, int fail_on_error);
78 static void synchronize (void);
79 static int pty_open_master (char *pty_name);
80 static int pty_open_slave (const char *pty_name);
82 /* }}} */
83 /* {{{ Definitions */
85 #ifndef STDIN_FILENO
86 # define STDIN_FILENO 0
87 #endif
89 #ifndef STDOUT_FILENO
90 # define STDOUT_FILENO 1
91 #endif
93 #ifndef STDERR_FILENO
94 # define STDERR_FILENO 2
95 #endif
97 /* If using a subshell for evaluating commands this is true */
98 int use_subshell =
99 #ifdef SUBSHELL_OPTIONAL
100 FALSE;
101 #else
102 TRUE;
103 #endif
105 /* File descriptor of the pseudoterminal used by the subshell */
106 int subshell_pty = 0;
108 /* If true, the child forked in init_subshell will wait in a loop to be attached by gdb */
109 int debug_subshell = 0;
111 /* The key for switching back to MC from the subshell */
112 char subshell_switch_key = XCTRL('o');
114 /* State of the subshell:
115 * INACTIVE: the default state; awaiting a command
116 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
117 * RUNNING_COMMAND: return to MC when the current command finishes */
118 enum subshell_state_enum subshell_state;
120 /* Holds the latest prompt captured from the subshell */
121 char *subshell_prompt = NULL;
123 /* Initial length of the buffer for the subshell's prompt */
124 #define INITIAL_PROMPT_SIZE 10
126 /* Used by the child process to indicate failure to start the subshell */
127 #define FORK_FAILURE 69 /* Arbitrary */
129 /* Initial length of the buffer for all I/O with the subshell */
130 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
132 /* For pipes */
133 enum {READ=0, WRITE=1};
136 /* Local variables */
138 static char *pty_buffer; /* For reading/writing on the subshell's pty */
139 static int pty_buffer_size; /* The buffer grows as needed */
140 static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
141 static pid_t subshell_pid = 1; /* The subshell's process ID */
142 static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
144 /* Subshell type (gleaned from the SHELL environment variable, if available) */
145 static enum {BASH, TCSH, ZSH} subshell_type;
147 /* Flag to indicate whether the subshell is ready for next command */
148 static int subshell_ready;
150 /* The following two flags can be changed by the SIGCHLD handler. This is */
151 /* OK, because the `int' type is updated atomically on all known machines */
152 static volatile int subshell_alive, subshell_stopped;
154 /* We store the terminal's initial mode here so that we can configure
155 the pty similarly, and also so we can restore the real terminal to
156 sanity if we have to exit abruptly */
157 static struct termios shell_mode;
159 /* This is a transparent mode for the terminal where MC is running on */
160 /* It is used when the shell is active, so that the control signals */
161 /* are delivered to the shell pty */
162 static struct termios raw_mode;
164 /* This counter indicates how many characters of prompt we have read */
165 /* FIXME: try to figure out why this had to become global */
166 static int prompt_pos;
168 /* }}} */
170 #ifdef HAVE_GRANTPT
171 # define SYNC_PTY_SIDES
172 #else
173 # define SYNC_PTY_SIDES
174 #endif
176 #undef SYNC_PTY_SIDES
178 #ifdef SYNC_PTY_SIDES
179 /* Handler for SIGUSR1 (used below), does nothing but accept the signal */
180 static void sigusr1_handler (int sig)
183 #endif
186 * Prepare child process to running the shell and run it.
188 * Modifies the global variables (in the child process only):
189 * shell_mode
191 * Returns: never.
193 static void init_subshell_child (const char *pty_name)
195 int pty_slave;
196 char *init_file = NULL;
198 setsid (); /* Get a fresh terminal session */
200 /* {{{ Open the slave side of the pty: again */
201 pty_slave = pty_open_slave (pty_name);
203 /* This must be done before closing the master side of the pty, */
204 /* or it will fail on certain idiotic systems, such as Solaris. */
206 /* Close master side of pty. This is important; apart from */
207 /* freeing up the descriptor for use in the subshell, it also */
208 /* means that when MC exits, the subshell will get a SIGHUP and */
209 /* exit too, because there will be no more descriptors pointing */
210 /* at the master side of the pty and so it will disappear. */
212 close (subshell_pty);
214 #ifdef SYNC_PTY_SIDES
215 /* Give our parent process (MC) the go-ahead */
216 kill (getppid (), SIGUSR1);
217 #endif
219 /* }}} */
220 /* {{{ Make sure that it has become our controlling terminal */
222 /* Redundant on Linux and probably most systems, but just in case: */
224 #ifdef TIOCSCTTY
225 ioctl (pty_slave, TIOCSCTTY, 0);
226 #endif
228 /* }}} */
229 /* {{{ Configure its terminal modes and window size */
231 /* Set up the pty with the same termios flags as our own tty, plus */
232 /* TOSTOP, which keeps background processes from writing to the pty */
234 shell_mode.c_lflag |= TOSTOP; /* So background writers get SIGTTOU */
235 if (tcsetattr (pty_slave, TCSANOW, &shell_mode))
237 perror (__FILE__": couldn't set pty terminal modes");
238 _exit (FORK_FAILURE);
241 /* Set the pty's size (80x25 by default on Linux) according to the */
242 /* size of the real terminal as calculated by ncurses, if possible */
243 #if defined TIOCSWINSZ && !defined SCO_FLAVOR
245 struct winsize tty_size;
246 tty_size.ws_row = LINES;
247 tty_size.ws_col = COLS;
248 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
250 if (ioctl (pty_slave, TIOCSWINSZ, &tty_size))
251 perror (__FILE__": couldn't set pty size");
253 #endif
255 /* }}} */
256 /* {{{ Set up the subshell's environment and init file name */
258 /* It simplifies things to change to our home directory here, */
259 /* and the user's startup file may do a `cd' command anyway */
260 chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
262 switch (subshell_type)
264 case BASH:
265 init_file = ".mc/bashrc";
266 if (access (init_file, R_OK) == -1)
267 init_file = ".bashrc";
269 /* Make MC's special commands not show up in bash's history */
270 putenv ("HISTCONTROL=ignorespace");
272 /* Allow alternative readline settings for MC */
273 if (access (".mc/inputrc", R_OK) == 0)
274 putenv ("INPUTRC=.mc/inputrc");
276 break;
278 case TCSH:
279 init_file = ".mc/tcshrc";
280 if (access (init_file, R_OK) == -1)
281 init_file += 3;
282 break;
284 case ZSH:
285 break;
287 default:
288 fprintf (stderr, __FILE__": unimplemented subshell type %d\n",
289 subshell_type);
290 _exit (FORK_FAILURE);
293 /* }}} */
294 /* {{{ Attach all our standard file descriptors to the pty */
296 /* This is done just before the fork, because stderr must still */
297 /* be connected to the real tty during the above error messages; */
298 /* otherwise the user will never see them. */
300 dup2 (pty_slave, STDIN_FILENO);
301 dup2 (pty_slave, STDOUT_FILENO);
302 dup2 (pty_slave, STDERR_FILENO);
304 /* }}} */
305 /* {{{ Execute the subshell at last */
307 close (subshell_pipe[READ]);
308 close (pty_slave); /* These may be FD_CLOEXEC, but just in case... */
310 switch (subshell_type)
312 case BASH:
313 execl (shell, "bash", "-rcfile", init_file, NULL);
314 break;
316 case TCSH:
317 execl (shell, "tcsh", NULL); /* What's the -rcfile equivalent? */
318 break;
320 case ZSH:
321 /* change from "+Z" to "-Z" by Michael Bramer
322 * (Debian-mc-maintainer) <grisu@debian.org> from a patch from
323 * Radovan Garabik <garabik@center.fmph.uniba.sk>
325 execl (shell, "zsh", "-Z", NULL);
327 break;
330 /* If we get this far, everything failed miserably */
331 _exit (FORK_FAILURE);
333 /* }}} */
336 /* {{{ init_subshell */
339 * Fork the subshell, and set up many, many things.
341 * Possibly modifies the global variables:
342 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
343 * use_subshell - Is set to FALSE if we can't run the subshell
344 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
347 void init_subshell (void)
349 /* {{{ Local variables */
351 /* This must be remembered across calls to init_subshell() */
352 static char pty_name[BUF_SMALL];
353 int pty_slave = -1;
355 /* Braindead tcsh can't redirect output to a file descriptor? */
356 char tcsh_fifo[sizeof "/tmp/mc.pipe.1234567890"];
359 #ifdef SYNC_PTY_SIDES
360 /* Used to wait for a SIGUSR1 signal from the subprocess */
361 sigset_t sigusr1_mask, old_mask;
362 #endif
364 /* }}} */
366 /* Take the current (hopefully pristine) tty mode and make */
367 /* a raw mode based on it now, before we do anything else with it */
368 init_raw_mode ();
370 if (subshell_pty == 0) /* First time through */
372 /* {{{ Find out what type of shell we have */
374 if (strstr (shell, "/zsh"))
375 subshell_type = ZSH;
376 else if (strstr (shell, "/tcsh"))
377 subshell_type = TCSH;
378 else if (strstr (shell, "/bash") || getenv ("BASH"))
379 subshell_type = BASH;
380 else
382 use_subshell = FALSE;
383 return;
386 /* }}} */
387 /* {{{ Open a pty for talking to the subshell */
389 /* FIXME: We may need to open a fresh pty each time on SVR4 */
391 subshell_pty = pty_open_master (pty_name);
392 if (subshell_pty == -1)
394 fputs (__FILE__": couldn't open master side of pty\n", stderr);
395 perror ("pty_open_master");
396 use_subshell = FALSE;
397 return;
399 pty_slave = pty_open_slave (pty_name);
400 if (pty_slave == -1)
402 fprintf (stderr, "couldn't open slave side of pty (%s)\n\r",
403 pty_name);
404 use_subshell = FALSE;
405 return;
409 /* }}} */
410 /* {{{ Initialise the pty's I/O buffer */
412 pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
413 pty_buffer = (char *) g_malloc (pty_buffer_size);
415 /* }}} */
416 /* {{{ Create a pipe for receiving the subshell's CWD */
418 if (subshell_type == TCSH)
420 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "/tmp/mc.pipe.%d", getpid ());
421 if (mkfifo (tcsh_fifo, 0600) == -1)
423 perror (__FILE__": mkfifo");
424 use_subshell = FALSE;
425 return;
428 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
430 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1 ||
431 (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
433 fprintf (stderr, _("Couldn't open named pipe %s\n"), tcsh_fifo);
434 perror (__FILE__": open");
435 use_subshell = FALSE;
436 return;
439 else /* subshell_type is BASH or ZSH */
440 if (pipe (subshell_pipe))
442 perror (__FILE__": couldn't create pipe");
443 use_subshell = FALSE;
444 return;
447 /* }}} */
450 /* {{{ Define a handler for the sigusr1 signal */
452 #ifdef SYNC_PTY_SIDES
453 sigemptyset (&sigusr1_mask);
454 sigaddset (&sigusr1_mask, SIGUSR1);
455 sigprocmask (SIG_BLOCK, &sigusr1_mask, &old_mask);
456 signal (SIGUSR1, sigusr1_handler);
457 #endif
459 /* }}} */
460 /* {{{ Fork the subshell */
462 subshell_alive = TRUE;
463 subshell_stopped = FALSE;
464 subshell_pid = fork ();
466 if (subshell_pid == -1)
468 perror (__FILE__": couldn't spawn the subshell process");
469 /* We exit here because, if the process table is full, the */
470 /* other method of running user commands won't work either */
471 exit (1);
474 /* }}} */
476 if (subshell_pid == 0) /* We are in the child process */
478 init_subshell_child (pty_name);
481 /* pty_slave is only opened when called the first time */
482 if (pty_slave != -1) {
483 close(pty_slave);
486 #ifdef SYNC_PTY_SIDES
487 sigsuspend (&old_mask);
488 signal (SIGUSR1, SIG_DFL);
489 sigprocmask (SIG_SETMASK, &old_mask, NULL);
490 /* ...before installing our handler for SIGCHLD. */
491 #endif
493 #if 0
494 /* {{{ Install our handler for SIGCHLD */
496 init_sigchld ();
498 /* We could have received the SIGCHLD signal for the subshell
499 * before installing the init_sigchld */
500 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
501 if (pid == subshell_pid){
502 use_subshell = FALSE;
503 return;
506 /* }}} */
507 #endif
509 /* {{{ Set up `precmd' or equivalent for reading the subshell's CWD */
511 switch (subshell_type)
513 char precmd[BUF_SMALL];
515 case BASH:
516 g_snprintf (precmd, sizeof (precmd), " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
517 subshell_pipe[WRITE]);
518 goto write_it;
520 case ZSH:
521 g_snprintf (precmd, sizeof (precmd), "precmd(){ pwd>&%d;kill -STOP $$ }\n",
522 subshell_pipe[WRITE]);
523 goto write_it;
525 case TCSH:
526 g_snprintf (precmd, sizeof (precmd),
527 "set echo_style=both;"
528 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
529 tcsh_fifo);
531 write_it:
532 write (subshell_pty, precmd, strlen (precmd));
535 /* }}} */
536 /* {{{ Wait until the subshell has started up and processed the command */
538 subshell_state = RUNNING_COMMAND;
539 enable_interrupt_key ();
540 if (!feed_subshell (QUIETLY, TRUE)){
541 use_subshell = FALSE;
543 disable_interrupt_key ();
544 if (!subshell_alive)
545 use_subshell = FALSE; /* Subshell died instantly, so don't use it */
547 /* }}} */
550 /* }}} */
552 static void init_raw_mode ()
554 static int initialized = 0;
556 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
557 /* original settings. However, here we need to make this tty very raw, */
558 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
559 /* pty. So, instead of changing the code for execute(), pre_exec(), */
560 /* etc, we just set up the modes we need here, before each command. */
562 if (initialized == 0) /* First time: initialise `raw_mode' */
564 tcgetattr (STDOUT_FILENO, &raw_mode);
565 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
566 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
567 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
568 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
569 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
570 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
571 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
572 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
573 initialized = 1;
577 /* {{{ invoke_subshell */
579 int invoke_subshell (const char *command, int how, char **new_dir)
581 /* {{{ Make the MC terminal transparent */
583 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
585 /* }}} */
587 /* Make the subshell change to MC's working directory */
588 if (new_dir)
589 do_subshell_chdir (cpanel->cwd, TRUE, 1);
591 if (command == NULL) /* The user has done "C-o" from MC */
593 if (subshell_state == INACTIVE)
595 subshell_state = ACTIVE;
596 /* FIXME: possibly take out this hack; the user can
597 re-play it by hitting C-hyphen a few times! */
598 write (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
601 else /* MC has passed us a user command */
603 if (how == QUIETLY)
604 write (subshell_pty, " ", 1);
605 /* FIXME: if command is long (>8KB ?) we go comma */
606 write (subshell_pty, command, strlen (command));
607 write (subshell_pty, "\n", 1);
608 subshell_state = RUNNING_COMMAND;
609 subshell_ready = FALSE;
612 feed_subshell (how, FALSE);
614 if (new_dir && subshell_alive && strcmp (subshell_cwd, cpanel->cwd))
615 *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
617 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
618 while (!subshell_alive && !quit && use_subshell)
619 init_subshell ();
621 prompt_pos = 0;
623 return quit;
626 /* }}} */
627 /* {{{ read_subshell_prompt */
629 int read_subshell_prompt (int how)
631 /* {{{ Local variables */
633 int clear_now = FALSE;
634 static int prompt_size = INITIAL_PROMPT_SIZE;
635 int bytes = 0, i, rc = 0;
636 struct timeval timeleft = {0, 0};
638 fd_set tmp;
639 FD_ZERO (&tmp);
640 FD_SET (subshell_pty, &tmp);
642 /* }}} */
644 if (subshell_prompt == NULL) /* First time through */
646 subshell_prompt = (char *) g_malloc (prompt_size);
647 *subshell_prompt = '\0';
648 prompt_pos = 0;
651 while (subshell_alive &&
652 (rc = select (FD_SETSIZE, &tmp, NULL, NULL, &timeleft)))
654 /* {{{ Check for `select' errors */
656 if (rc == -1) {
657 if (errno == EINTR)
658 continue;
659 else {
660 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
661 perror ("\n"__FILE__": select (FD_SETSIZE, &tmp...)");
662 exit (1);
666 /* }}} */
668 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
669 if (how == VISIBLY)
670 write (STDOUT_FILENO, pty_buffer, bytes);
672 /* {{{ Extract the prompt from the shell output */
674 for (i=0; i<bytes; ++i)
675 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r'){
676 prompt_pos = 0;
677 clear_now = FALSE;
678 } else {
679 clear_now = TRUE;
680 if (!pty_buffer [i])
681 continue;
683 subshell_prompt[prompt_pos++] = pty_buffer[i];
684 if (prompt_pos == prompt_size)
685 subshell_prompt = (char *) g_realloc (subshell_prompt,
686 prompt_size *= 2);
689 /* Sometimes we get an empty new line and then nothing,
690 * we better just keep the old prompt instead. */
691 if (clear_now)
692 subshell_prompt[prompt_pos] = '\0';
694 /* }}} */
696 if (rc == 0 && bytes == 0)
697 return FALSE;
698 return TRUE;
701 /* }}} */
702 /* {{{ resize_subshell */
704 void resize_subshell (void)
706 #if defined TIOCSWINSZ && !defined SCO_FLAVOR
707 struct winsize tty_size;
709 tty_size.ws_row = LINES;
710 tty_size.ws_col = COLS;
711 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
713 if (ioctl (subshell_pty, TIOCSWINSZ, &tty_size))
714 perror (__FILE__": couldn't set pty size");
715 #endif
718 /* }}} */
719 /* {{{ exit_subshell */
721 int exit_subshell (void)
723 int quit = TRUE;
725 if (subshell_state != INACTIVE && subshell_alive)
726 quit = !query_dialog (_(" Warning "), _(" The shell is still active. Quit anyway? "),
727 0, 2, _("&Yes"), _("&No"));
729 #if AIX_TCSH_CODE_BELOW_IS_IT_FIXED
730 /* New Test code */
731 else
733 if (subshell_type == TCSH)
734 g_snprintf (pty_buffer, pty_buffer_size, " echo -n Jobs:>/tmp/mc.pipe.%d;jobs>/tmp/"
735 "mc.pipe.%d;kill -STOP $$\n", getpid (), getpid ());
736 else
737 g_snprintf (pty_buffer, pty_buffer_size, " echo -n Jobs:>&%d;jobs>&%d;kill -STOP $$\n",
738 subshell_pipe[WRITE], subshell_pipe[WRITE]);
739 write (subshell_pty, pty_buffer, strlen (pty_buffer));
741 #ifndef HAVE_GRANTPT /* FIXME */
742 if (subshell_type == ZSH)
743 /* Here we have to drain the shell output, because zsh does a */
744 /* tcsetattr(SHTTY, TCSADRAIN...) which will block if we don't */
745 read (subshell_pty, pty_buffer, pty_buffer_size);
746 #endif
748 /* TCSH + AIX hang here, fix this before removing the ifdef above */
749 if (read (subshell_pipe[READ], pty_buffer, pty_buffer_size) == 5)
750 quit = TRUE;
751 else
752 quit = !query_dialog (_(" Warning "), _(" There are stopped jobs.")
753 _(" Quit anyway? "), 0, 2, _("&Yes"), _("&No"));
755 synchronize ();
756 subshell_state = RUNNING_COMMAND;
757 feed_subshell (QUIETLY, FALSE); /* Drain the shell output (again) */
759 #endif
761 if (quit && subshell_type == TCSH)
763 /* We abuse of pty_buffer here, but it doesn't matter at this stage */
764 g_snprintf (pty_buffer, pty_buffer_size, "/tmp/mc.pipe.%d", getpid ());
765 if (unlink (pty_buffer) == -1)
766 perror (__FILE__": couldn't remove named pipe /tmp/mc.pipe.NNN");
769 return quit;
772 /* }}} */
775 * Carefully quote directory name to allow entering any directory safely,
776 * no matter what weird characters it may contain in its name.
777 * NOTE: Treat directory name an untrusted data, don't allow it to cause
778 * executing any commands in the shell. Escape all control characters.
779 * Use following technique:
781 * for bash - echo with `-e', 3-digit octal numbers:
782 * cd "`echo -e '\ooo...\ooo'`"
784 * for zsh and tcsh - echo without `-e', 4-digit octal numbers:
785 * cd "`echo '\oooo...\oooo'`"
787 static char *
788 subshell_name_quote (const char *s)
790 char *ret, *d;
791 const char bash_start[] = "\"`echo -e '";
792 const char nonbash_start[] = "\"`echo '";
793 const char common_end[] = "'`\"";
796 * Factor 5 because we need \, 0 and 3 other digits per character
797 * in the worst case (tcsh and zsh).
799 d = ret = g_malloc (5 * strlen (s) + 16);
801 /* Prevent interpreting leading `-' as a switch for `cd' */
802 if (*s == '-') {
803 *d++ = '.';
804 *d++ = '/';
808 * Print every character in octal format with the leading backslash.
809 * tcsh and zsh require leading 0, bash doesn't like 4-digit octals
810 * and requires `-e' for echo.
812 if (subshell_type == BASH) {
813 memcpy (d, bash_start, sizeof (bash_start) - 1);
814 d += sizeof (bash_start) - 1;
815 for (; *s; s++) {
816 sprintf(d, "\\%03o", (unsigned char) *s);
817 d += 4;
819 } else {
820 memcpy (d, nonbash_start, sizeof (nonbash_start) - 1);
821 d += sizeof (nonbash_start) - 1;
822 for (; *s; s++) {
823 sprintf(d, "\\0%03o", (unsigned char) *s);
824 d += 5;
828 memcpy (d, common_end, sizeof (common_end));
830 return ret;
835 /* {{{ do_subshell_chdir */
836 /* If it actually changed the directory it returns true */
837 void do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
839 if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, cpanel->cwd))){
840 /* We have to repaint the subshell prompt if we read it from
841 * the main program. Please note that in the code after this
842 * if, the cd command that is sent will make the subshell
843 * repaint the prompt, so we don't have to paint it. */
844 if (do_update)
845 do_update_prompt ();
846 return;
849 /* The initial space keeps this out of the command history (in bash
850 because we set "HISTCONTROL=ignorespace") */
851 write (subshell_pty, " cd ", 4);
852 if (*directory) {
853 char *temp;
854 temp = subshell_name_quote (directory);
855 write (subshell_pty, temp, strlen (temp));
856 g_free (temp);
857 } else {
858 write (subshell_pty, "/", 1);
860 write (subshell_pty, "\n", 1);
862 subshell_state = RUNNING_COMMAND;
863 feed_subshell (QUIETLY, FALSE);
865 if (subshell_alive && strcmp (subshell_cwd, cpanel->cwd) && strcmp (cpanel->cwd, "."))
866 fprintf (stderr, _("Warning: Couldn't change to %s.\n"), cpanel->cwd);
868 if (reset_prompt)
869 prompt_pos = 0;
870 update_prompt = FALSE;
871 /* Make sure that MC never stores the CWD in a silly format */
872 /* like /usr////lib/../bin, or the strcmp() above will fail */
875 /* }}} */
876 /* {{{ subshell_get_console_attributes */
878 void subshell_get_console_attributes (void)
880 /* {{{ Get our current terminal modes */
882 if (tcgetattr (STDOUT_FILENO, &shell_mode))
884 perror (__FILE__": couldn't get terminal settings");
885 use_subshell = FALSE;
886 return;
889 /* }}} */
892 /* }}} */
893 /* {{{ sigchld_handler */
895 /* Figure out whether the subshell has stopped, exited or been killed */
896 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
898 void sigchld_handler (int sig)
900 int status;
901 pid_t pid;
903 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
905 if (pid == subshell_pid) {
906 /* {{{ Figure out what has happened to the subshell */
908 # ifdef SIGTSTP
909 if (WIFSTOPPED (status))
911 if (WSTOPSIG (status) == SIGTSTP)
912 /* The user has suspended the subshell. Revive it */
913 kill (subshell_pid, SIGCONT);
914 else
915 /* The subshell has received a SIGSTOP signal */
916 subshell_stopped = TRUE;
918 else /* The subshell has either exited normally or been killed */
919 # endif
921 subshell_alive = FALSE;
922 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
923 quit |= SUBSHELL_EXIT; /* Exited normally */
926 /* }}} */
929 #if defined(linux) || defined(__linux__)
930 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
932 if (pid == cons_saver_pid) {
934 # ifdef SIGTSTP
935 if (WIFSTOPPED (status))
936 /* Someone has stopped cons.saver - restart it */
937 kill (pid, SIGCONT);
938 else
939 # endif
941 /* cons.saver has died - disable confole saving */
942 handle_console (CONSOLE_DONE);
943 console_flag = 0;
947 #endif /* linux || __linux__ */
948 /* If we get here, some other child exited; ignore it */
949 # ifdef __EMX__ /* Need to report */
950 pid = wait(&status);
951 # endif
954 /* }}} */
956 /* {{{ feed_subshell */
958 /* Feed the subshell our keyboard input until it says it's finished */
960 static int feed_subshell (int how, int fail_on_error)
962 /* {{{ Local variables */
963 fd_set read_set; /* For `select' */
964 int bytes; /* For the return value from `read' */
965 int i; /* Loop counter */
967 struct timeval wtime; /* Maximum time we wait for the subshell */
968 struct timeval *wptr;
969 /* }}} */
971 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
972 wtime.tv_sec = 10;
973 wtime.tv_usec = 0;
974 wptr = fail_on_error ? &wtime : NULL;
976 while (1) {
977 if (!subshell_alive)
978 return FALSE;
980 /* {{{ Prepare the file-descriptor set and call `select' */
982 FD_ZERO (&read_set);
983 FD_SET (subshell_pty, &read_set);
984 FD_SET (subshell_pipe[READ], &read_set);
985 if (how == VISIBLY)
986 FD_SET (STDIN_FILENO, &read_set);
988 if (select (FD_SETSIZE, &read_set, NULL, NULL, wptr) == -1){
990 /* Despite using SA_RESTART, we still have to check for this */
991 if (errno == EINTR)
992 continue; /* try all over again */
993 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
994 perror ("\n"__FILE__": select (FD_SETSIZE, &read_set...)");
995 exit (1);
997 /* }}} */
999 if (FD_ISSET (subshell_pty, &read_set))
1000 /* {{{ Read from the subshell, write to stdout */
1002 /* This loop improves performance by reducing context switches
1003 by a factor of 20 or so... unfortunately, it also hangs MC
1004 randomly, because of an apparent Linux bug. Investigate. */
1005 /* for (i=0; i<5; ++i) * FIXME -- experimental */
1007 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
1008 /* Patch from viro@math.psu.edu
1009 * add by MichaelBramer (Debian MC-Maintainer */
1010 if (bytes == -1 && errno == EIO && !subshell_alive)
1012 return FALSE;
1014 if (bytes == -1)
1015 /* end from the patch */
1017 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1018 perror ("\n"__FILE__": read (subshell_pty...)");
1019 exit (1);
1021 if (bytes > 0)
1022 if (how == VISIBLY)
1023 write (STDOUT_FILENO, pty_buffer, bytes);
1026 /* }}} */
1028 else if (FD_ISSET (subshell_pipe[READ], &read_set))
1029 /* {{{ Read the subshell's CWD and capture its prompt */
1032 bytes = read (subshell_pipe[READ], subshell_cwd, MC_MAXPATHLEN+1);
1033 if (bytes == -1)
1035 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1036 perror ("\n"__FILE__": read (subshell_pipe[READ]...)");
1037 exit (1);
1039 if (bytes >= 1)
1040 subshell_cwd[bytes-1] = 0; /* Squash the final '\n' */
1042 synchronize ();
1044 subshell_ready = TRUE;
1045 if (subshell_state == RUNNING_COMMAND)
1047 subshell_state = INACTIVE;
1048 return 1;
1052 /* }}} */
1054 else if (FD_ISSET (STDIN_FILENO, &read_set))
1055 /* {{{ Read from stdin, write to the subshell */
1058 bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
1059 if (bytes == -1)
1061 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1062 perror ("\n"__FILE__": read (STDIN_FILENO, pty_buffer...)");
1063 exit (1);
1066 for (i=0; i<bytes; ++i)
1067 if (pty_buffer[i] == subshell_switch_key)
1069 write (subshell_pty, pty_buffer, i);
1070 if (subshell_ready)
1071 subshell_state = INACTIVE;
1072 return TRUE;
1075 write (subshell_pty, pty_buffer, bytes);
1076 subshell_ready = FALSE;
1077 } else {
1078 return FALSE;
1081 /* }}} */
1085 /* }}} */
1086 /* {{{ synchronize */
1088 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1089 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1091 static void synchronize (void)
1093 sigset_t sigchld_mask, old_mask;
1095 sigemptyset (&sigchld_mask);
1096 sigaddset (&sigchld_mask, SIGCHLD);
1097 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
1099 /* Wait until the subshell has stopped */
1100 while (subshell_alive && !subshell_stopped)
1101 sigsuspend (&old_mask);
1102 subshell_stopped = FALSE;
1103 # ifdef SIGTSTP
1104 kill (subshell_pid, SIGCONT);
1105 # endif
1107 sigprocmask (SIG_SETMASK, &old_mask, NULL);
1108 /* We can't do any better without modifying the shell(s) */
1111 /* }}} */
1112 /* {{{ pty opening functions */
1114 #ifdef SCO_FLAVOR
1116 /* {{{ SCO version of pty_open_master */
1118 static int pty_open_master (char *pty_name)
1120 int pty_master;
1121 int num;
1122 char *ptr;
1124 strcpy (pty_name, "/dev/ptyp");
1125 ptr = pty_name+9;
1126 for (num=0;;num++)
1128 g_snprintf(ptr, 9, "%d",num); /* surpriiise ... SCO lacks itoa() */
1129 /* Try to open master */
1130 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1131 if (errno == ENOENT) /* Different from EIO */
1132 return -1; /* Out of pty devices */
1133 else
1134 continue; /* Try next pty device */
1136 pty_name [5] = 't'; /* Change "pty" to "tty" */
1137 if (access (pty_name, 6)){
1138 close (pty_master);
1139 pty_name [5] = 'p';
1140 continue;
1142 return pty_master;
1144 return -1; /* Ran out of pty devices */
1147 /* }}} */
1148 /* {{{ SCO version of pty_open_slave */
1150 static int pty_open_slave (const char *pty_name)
1152 int pty_slave;
1153 struct group *group_info = getgrnam ("terminal");
1155 if (group_info != NULL)
1157 /* The following two calls will only succeed if we are root */
1158 /* [Commented out while permissions problem is investigated] */
1159 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1160 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1162 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1163 perror ("open (pty_name, O_RDWR)");
1164 return pty_slave;
1167 /* }}} */
1169 #elif HAVE_GRANTPT /* !HAVE_SCO */
1171 /* {{{ System V version of pty_open_master */
1173 static int pty_open_master (char *pty_name)
1175 char *slave_name;
1176 int pty_master;
1179 #ifdef HAVE_GETPT
1180 /* getpt () is a GNU extension (glibc 2.1.x) */
1181 pty_master = getpt ();
1182 #else
1183 strcpy (pty_name, "/dev/ptmx");
1184 pty_master = open (pty_name, O_RDWR);
1185 #endif
1186 if (pty_master == -1)
1187 return -1;
1189 if (grantpt (pty_master) == -1 /* Grant access to slave */
1190 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
1191 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
1193 close (pty_master);
1194 return -1;
1196 strcpy (pty_name, slave_name);
1197 return pty_master;
1200 /* }}} */
1201 /* {{{ System V version of pty_open_slave */
1203 static int pty_open_slave (const char *pty_name)
1205 int pty_slave = open (pty_name, O_RDWR);
1207 if (pty_slave == -1)
1209 perror ("open (pty_name, O_RDWR)");
1210 return -1;
1213 #if !defined(__osf__) && !defined(linux) && !defined(__linux__)
1214 #if defined (I_FIND) && defined (I_PUSH)
1215 if (!ioctl (pty_slave, I_FIND, "ptem"))
1216 if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
1218 perror ("ioctl (pty_slave, I_PUSH, \"ptem\")");
1219 close (pty_slave);
1220 return -1;
1223 if (!ioctl (pty_slave, I_FIND, "ldterm"))
1224 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
1226 perror ("ioctl (pty_slave, I_PUSH, \"ldterm\")");
1227 close (pty_slave);
1228 return -1;
1231 #if !defined(sgi) && !defined(__sgi)
1232 if (!ioctl (pty_slave, I_FIND, "ttcompat"))
1233 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
1235 perror ("ioctl (pty_slave, I_PUSH, \"ttcompat\")");
1236 close (pty_slave);
1237 return -1;
1239 #endif /* sgi || __sgi */
1240 #endif /* I_FIND && I_PUSH */
1241 #endif /* __osf__ || linux || __linux__ */
1243 return pty_slave;
1246 /* }}} */
1248 #else /* !HAVE_SCO && !HAVE_GRANTPT */
1250 /* {{{ BSD version of pty_open_master */
1252 static int pty_open_master (char *pty_name)
1254 int pty_master;
1255 char *ptr1, *ptr2;
1257 strcpy (pty_name, "/dev/ptyXX");
1258 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1260 pty_name [8] = *ptr1;
1261 for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
1263 pty_name [9] = *ptr2;
1265 /* Try to open master */
1266 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1267 if (errno == ENOENT) /* Different from EIO */
1268 return -1; /* Out of pty devices */
1269 else
1270 continue; /* Try next pty device */
1272 pty_name [5] = 't'; /* Change "pty" to "tty" */
1273 if (access (pty_name, 6)){
1274 close (pty_master);
1275 pty_name [5] = 'p';
1276 continue;
1278 return pty_master;
1281 return -1; /* Ran out of pty devices */
1284 /* }}} */
1285 /* {{{ BSD version of pty_open_slave */
1287 static int pty_open_slave (const char *pty_name)
1289 int pty_slave;
1290 struct group *group_info = getgrnam ("tty");
1292 if (group_info != NULL)
1294 /* The following two calls will only succeed if we are root */
1295 /* [Commented out while permissions problem is investigated] */
1296 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1297 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1299 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1300 perror ("open (pty_name, O_RDWR)");
1301 return pty_slave;
1304 /* }}} */
1306 #endif /* !HAVE_SCO && !HAVE_GRANTPT */
1308 /* }}} */
1310 #endif /* HAVE_SUBSHELL_SUPPORT */
1312 /* {{{ Emacs local variables */
1315 Cause emacs to enter folding mode for this file:
1316 Local variables:
1317 end:
1320 /* }}} */