* sldisply.c (SLtt_initialize): Fix typo. Change Is_Bg_BGR
[midnight-commander.git] / src / subshell.c
blob1b0f62e1e7afedc3d887e07251e5defe86bc99f6
1 /* Concurrent shell support for the Midnight Commander
2 Copyright (C) 1994, 1995 Dugan Porter
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of Version 2 of the GNU General Public
6 License, as published by the Free Software Foundation.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 #include <config.h>
20 #ifdef HAVE_SUBSHELL_SUPPORT
22 #ifndef _GNU_SOURCE
23 # define _GNU_SOURCE 1
24 #endif
26 #include <ctype.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <signal.h>
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_IOCTL_H
35 # include <sys/ioctl.h>
36 #endif
37 #ifdef HAVE_TERMIOS_H
38 #include <termios.h>
39 #endif
40 #include <unistd.h>
42 #ifdef HAVE_STROPTS_H
43 # include <stropts.h> /* For I_PUSH */
44 #endif /* HAVE_STROPTS_H */
46 #include "global.h"
47 #include "tty.h" /* LINES */
48 #include "panel.h" /* current_panel */
49 #include "wtools.h" /* query_dialog() */
50 #include "main.h" /* do_update_prompt() */
51 #include "cons.saver.h" /* handle_console() */
52 #include "key.h" /* XCTRL */
53 #include "subshell.h"
55 #ifndef WEXITSTATUS
56 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
57 #endif
59 #ifndef WIFEXITED
60 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
61 #endif
63 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
64 static char tcsh_fifo[128];
66 /* Local functions */
67 static void init_raw_mode (void);
68 static int feed_subshell (int how, int fail_on_error);
69 static void synchronize (void);
70 static int pty_open_master (char *pty_name);
71 static int pty_open_slave (const char *pty_name);
72 static int resize_tty (int fd);
74 #ifndef STDIN_FILENO
75 # define STDIN_FILENO 0
76 #endif
78 #ifndef STDOUT_FILENO
79 # define STDOUT_FILENO 1
80 #endif
82 #ifndef STDERR_FILENO
83 # define STDERR_FILENO 2
84 #endif
86 /* If using a subshell for evaluating commands this is true */
87 int use_subshell =
88 #ifdef SUBSHELL_OPTIONAL
89 FALSE;
90 #else
91 TRUE;
92 #endif
94 /* File descriptor of the pseudoterminal used by the subshell */
95 int subshell_pty = 0;
97 /* The key for switching back to MC from the subshell */
98 static const char subshell_switch_key = XCTRL('o') & 255;
100 /* State of the subshell:
101 * INACTIVE: the default state; awaiting a command
102 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
103 * RUNNING_COMMAND: return to MC when the current command finishes */
104 enum subshell_state_enum subshell_state;
106 /* Holds the latest prompt captured from the subshell */
107 char *subshell_prompt = NULL;
109 /* Initial length of the buffer for the subshell's prompt */
110 #define INITIAL_PROMPT_SIZE 10
112 /* Used by the child process to indicate failure to start the subshell */
113 #define FORK_FAILURE 69 /* Arbitrary */
115 /* Initial length of the buffer for all I/O with the subshell */
116 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
118 /* For pipes */
119 enum {READ=0, WRITE=1};
121 static char *pty_buffer; /* For reading/writing on the subshell's pty */
122 static int pty_buffer_size; /* The buffer grows as needed */
123 static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
124 static pid_t subshell_pid = 1; /* The subshell's process ID */
125 static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
127 /* Subshell type (gleaned from the SHELL environment variable, if available) */
128 static enum {BASH, TCSH, ZSH} subshell_type;
130 /* Flag to indicate whether the subshell is ready for next command */
131 static int subshell_ready;
133 /* The following two flags can be changed by the SIGCHLD handler. This is */
134 /* OK, because the `int' type is updated atomically on all known machines */
135 static volatile int subshell_alive, subshell_stopped;
137 /* We store the terminal's initial mode here so that we can configure
138 the pty similarly, and also so we can restore the real terminal to
139 sanity if we have to exit abruptly */
140 static struct termios shell_mode;
142 /* This is a transparent mode for the terminal where MC is running on */
143 /* It is used when the shell is active, so that the control signals */
144 /* are delivered to the shell pty */
145 static struct termios raw_mode;
147 /* This counter indicates how many characters of prompt we have read */
148 /* FIXME: try to figure out why this had to become global */
149 static int prompt_pos;
153 * Prepare child process to running the shell and run it.
155 * Modifies the global variables (in the child process only):
156 * shell_mode
158 * Returns: never.
160 static void
161 init_subshell_child (const char *pty_name)
163 int pty_slave;
164 const char *init_file = NULL;
165 #ifdef HAVE_GETSID
166 pid_t mc_sid;
167 #endif /* HAVE_GETSID */
169 setsid (); /* Get a fresh terminal session */
171 /* Open the slave side of the pty: again */
172 pty_slave = pty_open_slave (pty_name);
174 /* This must be done before closing the master side of the pty, */
175 /* or it will fail on certain idiotic systems, such as Solaris. */
177 /* Close master side of pty. This is important; apart from */
178 /* freeing up the descriptor for use in the subshell, it also */
179 /* means that when MC exits, the subshell will get a SIGHUP and */
180 /* exit too, because there will be no more descriptors pointing */
181 /* at the master side of the pty and so it will disappear. */
183 close (subshell_pty);
185 /* Make sure that it has become our controlling terminal */
187 /* Redundant on Linux and probably most systems, but just in case: */
189 #ifdef TIOCSCTTY
190 ioctl (pty_slave, TIOCSCTTY, 0);
191 #endif
193 /* Configure its terminal modes and window size */
195 /* Set up the pty with the same termios flags as our own tty, plus */
196 /* TOSTOP, which keeps background processes from writing to the pty */
198 shell_mode.c_lflag |= TOSTOP; /* So background writers get SIGTTOU */
199 if (tcsetattr (pty_slave, TCSANOW, &shell_mode)) {
200 fprintf (stderr, "Cannot set pty terminal modes: %s\r\n",
201 unix_error_string (errno));
202 _exit (FORK_FAILURE);
205 /* Set the pty's size (80x25 by default on Linux) according to the */
206 /* size of the real terminal as calculated by ncurses, if possible */
207 resize_tty (pty_slave);
209 /* Set up the subshell's environment and init file name */
211 /* It simplifies things to change to our home directory here, */
212 /* and the user's startup file may do a `cd' command anyway */
213 chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
215 #ifdef HAVE_GETSID
216 /* Set MC_SID to prevent running one mc from another */
217 mc_sid = getsid (0);
218 if (mc_sid != -1) {
219 char sid_str[BUF_SMALL];
220 g_snprintf (sid_str, sizeof (sid_str), "MC_SID=%ld",
221 (long) mc_sid);
222 putenv (g_strdup (sid_str));
224 #endif /* HAVE_GETSID */
226 switch (subshell_type) {
227 case BASH:
228 init_file = ".mc/bashrc";
229 if (access (init_file, R_OK) == -1)
230 init_file = ".bashrc";
232 /* Make MC's special commands not show up in bash's history */
233 putenv ("HISTCONTROL=ignorespace");
235 /* Allow alternative readline settings for MC */
236 if (access (".mc/inputrc", R_OK) == 0)
237 putenv ("INPUTRC=.mc/inputrc");
239 break;
241 /* TODO: Find a way to pass initfile to TCSH and ZSH */
242 case TCSH:
243 case ZSH:
244 break;
246 default:
247 fprintf (stderr, __FILE__ ": unimplemented subshell type %d\r\n",
248 subshell_type);
249 _exit (FORK_FAILURE);
252 /* Attach all our standard file descriptors to the pty */
254 /* This is done just before the fork, because stderr must still */
255 /* be connected to the real tty during the above error messages; */
256 /* otherwise the user will never see them. */
258 dup2 (pty_slave, STDIN_FILENO);
259 dup2 (pty_slave, STDOUT_FILENO);
260 dup2 (pty_slave, STDERR_FILENO);
262 /* Execute the subshell at last */
264 close (subshell_pipe[READ]);
265 close (pty_slave); /* These may be FD_CLOEXEC, but just in case... */
267 switch (subshell_type) {
268 case BASH:
269 execl (shell, "bash", "-rcfile", init_file, (char *) NULL);
270 break;
272 case TCSH:
273 execl (shell, "tcsh", (char *) NULL);
274 break;
276 case ZSH:
277 /* Use -g to exclude cmds beginning with space from history
278 * and -Z to use the line editor on non-interactive term */
279 execl (shell, "zsh", "-Z", "-g", (char *) NULL);
281 break;
284 /* If we get this far, everything failed miserably */
285 _exit (FORK_FAILURE);
289 #ifdef HAVE_GETSID
291 * Check MC_SID to prevent running one mc from another.
292 * Return:
293 * 0 if no parent mc in our session was found,
294 * 1 if parent mc was found and the user wants to continue,
295 * 2 if parent mc was found and the user wants to quit mc.
297 static int
298 check_sid (void)
300 pid_t my_sid, old_sid;
301 const char *sid_str;
302 int r;
304 sid_str = getenv ("MC_SID");
305 if (!sid_str)
306 return 0;
308 old_sid = (pid_t) strtol (sid_str, NULL, 0);
309 if (!old_sid)
310 return 0;
312 my_sid = getsid (0);
313 if (my_sid == -1)
314 return 0;
316 /* The parent mc is in a different session, it's OK */
317 if (old_sid != my_sid)
318 return 0;
320 r = query_dialog (_("Warning"),
321 _("GNU Midnight Commander is already\n"
322 "running on this terminal.\n"
323 "Subshell support will be disabled."), D_ERROR, 2,
324 _("&OK"), _("&Quit"));
325 if (r != 0) {
326 return 2;
329 return 1;
331 #endif /* HAVE_GETSID */
335 * Fork the subshell, and set up many, many things.
337 * Possibly modifies the global variables:
338 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
339 * use_subshell - Is set to FALSE if we can't run the subshell
340 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
343 void
344 init_subshell (void)
346 /* This must be remembered across calls to init_subshell() */
347 static char pty_name[BUF_SMALL];
348 char precmd[BUF_SMALL];
349 int pty_slave = -1;
351 #ifdef HAVE_GETSID
352 switch (check_sid ()) {
353 case 1:
354 use_subshell = FALSE;
355 return;
356 case 2:
357 use_subshell = FALSE;
358 midnight_shutdown = 1;
359 return;
361 #endif /* HAVE_GETSID */
363 /* Take the current (hopefully pristine) tty mode and make */
364 /* a raw mode based on it now, before we do anything else with it */
365 init_raw_mode ();
367 if (subshell_pty == 0) { /* First time through */
368 /* Find out what type of shell we have */
370 if (strstr (shell, "/zsh") || getenv ("ZSH_VERSION"))
371 subshell_type = ZSH;
372 else if (strstr (shell, "/tcsh"))
373 subshell_type = TCSH;
374 else if (strstr (shell, "/bash") || getenv ("BASH"))
375 subshell_type = BASH;
376 else {
377 use_subshell = FALSE;
378 return;
381 /* Open a pty for talking to the subshell */
383 /* FIXME: We may need to open a fresh pty each time on SVR4 */
385 subshell_pty = pty_open_master (pty_name);
386 if (subshell_pty == -1) {
387 fprintf (stderr, "Cannot open master side of pty: %s\r\n",
388 unix_error_string (errno));
389 use_subshell = FALSE;
390 return;
392 pty_slave = pty_open_slave (pty_name);
393 if (pty_slave == -1) {
394 fprintf (stderr, "Cannot open slave side of pty %s: %s\r\n",
395 pty_name, unix_error_string (errno));
396 use_subshell = FALSE;
397 return;
400 /* Initialise the pty's I/O buffer */
402 pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
403 pty_buffer = g_malloc (pty_buffer_size);
405 /* Create a pipe for receiving the subshell's CWD */
407 if (subshell_type == TCSH) {
408 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
409 mc_tmpdir (), (int) getpid ());
410 if (mkfifo (tcsh_fifo, 0600) == -1) {
411 fprintf (stderr, "mkfifo(%s) failed: %s\r\n", tcsh_fifo,
412 unix_error_string (errno));
413 use_subshell = FALSE;
414 return;
417 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
419 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1
420 || (subshell_pipe[WRITE] =
421 open (tcsh_fifo, O_RDWR)) == -1) {
422 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
423 perror (__FILE__": open");
424 use_subshell = FALSE;
425 return;
427 } else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe)) {
428 perror (__FILE__": couldn't create pipe");
429 use_subshell = FALSE;
430 return;
434 /* Fork the subshell */
436 subshell_alive = TRUE;
437 subshell_stopped = FALSE;
438 subshell_pid = fork ();
440 if (subshell_pid == -1) {
441 fprintf (stderr, "Cannot spawn the subshell process: %s\r\n",
442 unix_error_string (errno));
443 /* We exit here because, if the process table is full, the */
444 /* other method of running user commands won't work either */
445 exit (1);
448 if (subshell_pid == 0) { /* We are in the child process */
449 init_subshell_child (pty_name);
452 /* pty_slave is only opened when called the first time */
453 if (pty_slave != -1) {
454 close (pty_slave);
457 /* Set up `precmd' or equivalent for reading the subshell's CWD */
459 switch (subshell_type) {
460 case BASH:
461 g_snprintf (precmd, sizeof (precmd),
462 " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
463 subshell_pipe[WRITE]);
464 break;
466 case ZSH:
467 g_snprintf (precmd, sizeof (precmd),
468 " precmd(){ pwd>&%d;kill -STOP $$ }\n",
469 subshell_pipe[WRITE]);
470 break;
472 case TCSH:
473 g_snprintf (precmd, sizeof (precmd),
474 "set echo_style=both;"
475 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
476 tcsh_fifo);
477 break;
479 write (subshell_pty, precmd, strlen (precmd));
481 /* Wait until the subshell has started up and processed the command */
483 subshell_state = RUNNING_COMMAND;
484 enable_interrupt_key ();
485 if (!feed_subshell (QUIETLY, TRUE)) {
486 use_subshell = FALSE;
488 disable_interrupt_key ();
489 if (!subshell_alive)
490 use_subshell = FALSE; /* Subshell died instantly, so don't use it */
494 static void init_raw_mode ()
496 static int initialized = 0;
498 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
499 /* original settings. However, here we need to make this tty very raw, */
500 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
501 /* pty. So, instead of changing the code for execute(), pre_exec(), */
502 /* etc, we just set up the modes we need here, before each command. */
504 if (initialized == 0) /* First time: initialise `raw_mode' */
506 tcgetattr (STDOUT_FILENO, &raw_mode);
507 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
508 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
509 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
510 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
511 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
512 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
513 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
514 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
515 initialized = 1;
520 int invoke_subshell (const char *command, int how, char **new_dir)
522 /* Make the MC terminal transparent */
523 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
525 /* Make the subshell change to MC's working directory */
526 if (new_dir)
527 do_subshell_chdir (current_panel->cwd, TRUE, 1);
529 if (command == NULL) /* The user has done "C-o" from MC */
531 if (subshell_state == INACTIVE)
533 subshell_state = ACTIVE;
534 /* FIXME: possibly take out this hack; the user can
535 re-play it by hitting C-hyphen a few times! */
536 write (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
539 else /* MC has passed us a user command */
541 if (how == QUIETLY)
542 write (subshell_pty, " ", 1);
543 /* FIXME: if command is long (>8KB ?) we go comma */
544 write (subshell_pty, command, strlen (command));
545 write (subshell_pty, "\n", 1);
546 subshell_state = RUNNING_COMMAND;
547 subshell_ready = FALSE;
550 feed_subshell (how, FALSE);
552 if (new_dir && subshell_alive && strcmp (subshell_cwd, current_panel->cwd))
553 *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
555 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
556 while (!subshell_alive && !quit && use_subshell)
557 init_subshell ();
559 prompt_pos = 0;
561 return quit;
566 read_subshell_prompt (void)
568 static int prompt_size = INITIAL_PROMPT_SIZE;
569 int bytes = 0, i, rc = 0;
570 struct timeval timeleft = { 0, 0 };
572 fd_set tmp;
573 FD_ZERO (&tmp);
574 FD_SET (subshell_pty, &tmp);
576 if (subshell_prompt == NULL) { /* First time through */
577 subshell_prompt = g_malloc (prompt_size);
578 *subshell_prompt = '\0';
579 prompt_pos = 0;
582 while (subshell_alive
583 && (rc =
584 select (subshell_pty + 1, &tmp, NULL, NULL, &timeleft))) {
585 /* Check for `select' errors */
586 if (rc == -1) {
587 if (errno == EINTR)
588 continue;
589 else {
590 fprintf (stderr, "select (FD_SETSIZE, &tmp...): %s\r\n",
591 unix_error_string (errno));
592 exit (1);
596 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
598 /* Extract the prompt from the shell output */
600 for (i = 0; i < bytes; ++i)
601 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r') {
602 prompt_pos = 0;
603 } else {
604 if (!pty_buffer[i])
605 continue;
607 subshell_prompt[prompt_pos++] = pty_buffer[i];
608 if (prompt_pos == prompt_size)
609 subshell_prompt =
610 g_realloc (subshell_prompt, prompt_size *= 2);
613 subshell_prompt[prompt_pos] = '\0';
615 if (rc == 0 && bytes == 0)
616 return FALSE;
617 return TRUE;
620 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
621 static int resize_tty (int fd)
623 #if defined TIOCSWINSZ
624 struct winsize tty_size;
626 tty_size.ws_row = LINES;
627 tty_size.ws_col = COLS;
628 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
630 return ioctl (fd, TIOCSWINSZ, &tty_size);
631 #else
632 return 0;
633 #endif
636 /* Resize subshell_pty */
637 void resize_subshell (void)
639 resize_tty (subshell_pty);
643 exit_subshell (void)
645 int quit = TRUE;
647 if (subshell_state != INACTIVE && subshell_alive)
648 quit =
649 !query_dialog (_("Warning"),
650 _(" The shell is still active. Quit anyway? "),
651 0, 2, _("&Yes"), _("&No"));
653 if (quit) {
654 if (subshell_type == TCSH) {
655 if (unlink (tcsh_fifo) == -1)
656 fprintf (stderr, "Cannot remove named pipe %s: %s\r\n",
657 tcsh_fifo, unix_error_string (errno));
660 g_free (subshell_prompt);
661 g_free (pty_buffer);
662 subshell_prompt = NULL;
663 pty_buffer = NULL;
666 return quit;
671 * Carefully quote directory name to allow entering any directory safely,
672 * no matter what weird characters it may contain in its name.
673 * NOTE: Treat directory name an untrusted data, don't allow it to cause
674 * executing any commands in the shell. Escape all control characters.
675 * Use following technique:
677 * for bash - echo with `-e', 3-digit octal numbers:
678 * cd "`echo -e '\ooo...\ooo'`"
680 * for zsh - echo with `-e', 4-digit octal numbers:
681 * cd "`echo '\oooo...\oooo'`"
683 * for tcsh - echo without `-e', 4-digit octal numbers:
684 * cd "`echo '\oooo...\oooo'`"
686 static char *
687 subshell_name_quote (const char *s)
689 char *ret, *d;
690 const char echo_cmd[] = "\"`echo '";
691 const char echo_e_cmd[] = "\"`echo -e '";
692 const char common_end[] = "'`\"";
693 const char *cmd_start;
694 int len;
697 * Factor 5 because we need \, 0 and 3 other digits per character
698 * in the worst case (tcsh and zsh).
700 d = ret = g_malloc (5 * strlen (s) + 16);
701 if (!d)
702 return NULL;
704 /* Prevent interpreting leading `-' as a switch for `cd' */
705 if (*s == '-') {
706 *d++ = '.';
707 *d++ = '/';
710 /* echo in tcsh doesn't understand the "-e" option */
711 if (subshell_type == TCSH)
712 cmd_start = echo_cmd;
713 else
714 cmd_start = echo_e_cmd;
716 /* Copy the beginning of the command to the buffer */
717 len = strlen (cmd_start);
718 memcpy (d, cmd_start, len);
719 d += len;
722 * Print every character in octal format with the leading backslash.
723 * tcsh and zsh may require 4-digit octals, bash < 2.05b doesn't like them.
725 if (subshell_type == BASH) {
726 for (; *s; s++) {
727 /* Must quote numbers, so that they are not glued to octals */
728 if (isalpha ((unsigned char) *s)) {
729 *d++ = (unsigned char) *s;
730 } else {
731 sprintf (d, "\\%03o", (unsigned char) *s);
732 d += 4;
735 } else {
736 for (; *s; s++) {
737 if (isalnum ((unsigned char) *s)) {
738 *d++ = (unsigned char) *s;
739 } else {
740 sprintf (d, "\\0%03o", (unsigned char) *s);
741 d += 5;
746 memcpy (d, common_end, sizeof (common_end));
748 return ret;
752 /* If it actually changed the directory it returns true */
753 void
754 do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
756 if (!
757 (subshell_state == INACTIVE
758 && strcmp (subshell_cwd, current_panel->cwd))) {
759 /* We have to repaint the subshell prompt if we read it from
760 * the main program. Please note that in the code after this
761 * if, the cd command that is sent will make the subshell
762 * repaint the prompt, so we don't have to paint it. */
763 if (do_update)
764 do_update_prompt ();
765 return;
768 /* The initial space keeps this out of the command history (in bash
769 because we set "HISTCONTROL=ignorespace") */
770 write (subshell_pty, " cd ", 4);
771 if (*directory) {
772 char *temp = subshell_name_quote (directory);
773 if (temp) {
774 write (subshell_pty, temp, strlen (temp));
775 g_free (temp);
776 } else {
777 /* Should not happen unless the directory name is so long
778 that we don't have memory to quote it. */
779 write (subshell_pty, ".", 1);
781 } else {
782 write (subshell_pty, "/", 1);
784 write (subshell_pty, "\n", 1);
786 subshell_state = RUNNING_COMMAND;
787 feed_subshell (QUIETLY, FALSE);
789 if (subshell_alive) {
790 int bPathNotEq = strcmp (subshell_cwd, current_panel->cwd);
792 if (bPathNotEq && subshell_type == TCSH) {
793 char rp_subshell_cwd[PATH_MAX];
794 char rp_current_panel_cwd[PATH_MAX];
796 char *p_subshell_cwd =
797 mc_realpath (subshell_cwd, rp_subshell_cwd);
798 char *p_current_panel_cwd =
799 mc_realpath (current_panel->cwd, rp_current_panel_cwd);
801 if (p_subshell_cwd == NULL)
802 p_subshell_cwd = subshell_cwd;
803 if (p_current_panel_cwd == NULL)
804 p_current_panel_cwd = current_panel->cwd;
805 bPathNotEq = strcmp (p_subshell_cwd, p_current_panel_cwd);
808 if (bPathNotEq && strcmp (current_panel->cwd, ".")) {
809 char *cwd = strip_password (g_strdup (current_panel->cwd), 1);
810 fprintf (stderr, _("Warning: Cannot change to %s.\n"), cwd);
811 g_free (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 */
823 void
824 subshell_get_console_attributes (void)
826 /* Get our current terminal modes */
828 if (tcgetattr (STDOUT_FILENO, &shell_mode)) {
829 fprintf (stderr, "Cannot get terminal settings: %s\r\n",
830 unix_error_string (errno));
831 use_subshell = FALSE;
832 return;
837 /* Figure out whether the subshell has stopped, exited or been killed */
838 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
839 void
840 sigchld_handler (int sig)
842 int status;
843 pid_t pid;
845 (void) sig;
847 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
849 if (pid == subshell_pid) {
850 /* Figure out what has happened to the subshell */
852 if (WIFSTOPPED (status)) {
853 if (WSTOPSIG (status) == SIGSTOP) {
854 /* The subshell has received a SIGSTOP signal */
855 subshell_stopped = TRUE;
856 } else {
857 /* The user has suspended the subshell. Revive it */
858 kill (subshell_pid, SIGCONT);
860 } else {
861 /* The subshell has either exited normally or been killed */
862 subshell_alive = FALSE;
863 delete_select_channel (subshell_pty);
864 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
865 quit |= SUBSHELL_EXIT; /* Exited normally */
868 #ifdef __linux__
869 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
871 if (pid == cons_saver_pid) {
873 if (WIFSTOPPED (status))
874 /* Someone has stopped cons.saver - restart it */
875 kill (pid, SIGCONT);
876 else {
877 /* cons.saver has died - disable confole saving */
878 handle_console (CONSOLE_DONE);
879 console_flag = 0;
883 #endif /* __linux__ */
885 /* If we got here, some other child exited; ignore it */
886 #ifdef __EMX__ /* Need to report */
887 pid = wait (&status);
888 #endif
892 /* Feed the subshell our keyboard input until it says it's finished */
893 static int
894 feed_subshell (int how, int fail_on_error)
896 fd_set read_set; /* For `select' */
897 int maxfdp;
898 int bytes; /* For the return value from `read' */
899 int i; /* Loop counter */
901 struct timeval wtime; /* Maximum time we wait for the subshell */
902 struct timeval *wptr;
904 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
905 wtime.tv_sec = 10;
906 wtime.tv_usec = 0;
907 wptr = fail_on_error ? &wtime : NULL;
909 while (1) {
910 if (!subshell_alive)
911 return FALSE;
913 /* Prepare the file-descriptor set and call `select' */
915 FD_ZERO (&read_set);
916 FD_SET (subshell_pty, &read_set);
917 FD_SET (subshell_pipe[READ], &read_set);
918 maxfdp = max (subshell_pty, subshell_pipe[READ]);
919 if (how == VISIBLY) {
920 FD_SET (STDIN_FILENO, &read_set);
921 maxfdp = max (maxfdp, STDIN_FILENO);
924 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1) {
926 /* Despite using SA_RESTART, we still have to check for this */
927 if (errno == EINTR)
928 continue; /* try all over again */
929 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
930 fprintf (stderr, "select (FD_SETSIZE, &read_set...): %s\r\n",
931 unix_error_string (errno));
932 exit (1);
935 if (FD_ISSET (subshell_pty, &read_set))
936 /* Read from the subshell, write to stdout */
938 /* This loop improves performance by reducing context switches
939 by a factor of 20 or so... unfortunately, it also hangs MC
940 randomly, because of an apparent Linux bug. Investigate. */
941 /* for (i=0; i<5; ++i) * FIXME -- experimental */
943 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
945 /* The subshell has died */
946 if (bytes == -1 && errno == EIO && !subshell_alive)
947 return FALSE;
949 if (bytes <= 0) {
950 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
951 fprintf (stderr, "read (subshell_pty...): %s\r\n",
952 unix_error_string (errno));
953 exit (1);
956 if (how == VISIBLY)
957 write (STDOUT_FILENO, pty_buffer, bytes);
960 else if (FD_ISSET (subshell_pipe[READ], &read_set))
961 /* Read the subshell's CWD and capture its prompt */
964 bytes =
965 read (subshell_pipe[READ], subshell_cwd,
966 MC_MAXPATHLEN + 1);
967 if (bytes <= 0) {
968 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
969 fprintf (stderr, "read (subshell_pipe[READ]...): %s\r\n",
970 unix_error_string (errno));
971 exit (1);
974 subshell_cwd[bytes - 1] = 0; /* Squash the final '\n' */
976 synchronize ();
978 subshell_ready = TRUE;
979 if (subshell_state == RUNNING_COMMAND) {
980 subshell_state = INACTIVE;
981 return 1;
985 else if (FD_ISSET (STDIN_FILENO, &read_set))
986 /* Read from stdin, write to the subshell */
988 bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
989 if (bytes <= 0) {
990 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
991 fprintf (stderr,
992 "read (STDIN_FILENO, pty_buffer...): %s\r\n",
993 unix_error_string (errno));
994 exit (1);
997 for (i = 0; i < bytes; ++i)
998 if (pty_buffer[i] == subshell_switch_key) {
999 write (subshell_pty, pty_buffer, i);
1000 if (subshell_ready)
1001 subshell_state = INACTIVE;
1002 return TRUE;
1005 write (subshell_pty, pty_buffer, bytes);
1006 subshell_ready = FALSE;
1007 } else {
1008 return FALSE;
1014 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1015 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1016 static void synchronize (void)
1018 sigset_t sigchld_mask, old_mask;
1020 sigemptyset (&sigchld_mask);
1021 sigaddset (&sigchld_mask, SIGCHLD);
1022 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
1025 * SIGCHLD should not be blocked, but we unblock it just in case.
1026 * This is known to be useful for cygwin 1.3.12 and older.
1028 sigdelset (&old_mask, SIGCHLD);
1030 /* Wait until the subshell has stopped */
1031 while (subshell_alive && !subshell_stopped)
1032 sigsuspend (&old_mask);
1034 /* Discard all remaining data from stdin to the subshell */
1035 tcflush (subshell_pty, TCOFLUSH);
1037 subshell_stopped = FALSE;
1038 kill (subshell_pid, SIGCONT);
1040 sigprocmask (SIG_SETMASK, &old_mask, NULL);
1041 /* We can't do any better without modifying the shell(s) */
1044 /* pty opening functions */
1046 #ifdef HAVE_GRANTPT
1048 /* System V version of pty_open_master */
1050 static int pty_open_master (char *pty_name)
1052 char *slave_name;
1053 int pty_master;
1055 #ifdef HAVE_POSIX_OPENPT
1056 pty_master = posix_openpt(O_RDWR);
1057 #elif HAVE_GETPT
1058 /* getpt () is a GNU extension (glibc 2.1.x) */
1059 pty_master = getpt ();
1060 #elif IS_AIX
1061 strcpy (pty_name, "/dev/ptc");
1062 pty_master = open (pty_name, O_RDWR);
1063 #else
1064 strcpy (pty_name, "/dev/ptmx");
1065 pty_master = open (pty_name, O_RDWR);
1066 #endif
1068 if (pty_master == -1)
1069 return -1;
1071 if (grantpt (pty_master) == -1 /* Grant access to slave */
1072 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
1073 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
1075 close (pty_master);
1076 return -1;
1078 strcpy (pty_name, slave_name);
1079 return pty_master;
1082 /* System V version of pty_open_slave */
1083 static int
1084 pty_open_slave (const char *pty_name)
1086 int pty_slave = open (pty_name, O_RDWR);
1088 if (pty_slave == -1) {
1089 fprintf (stderr, "open (%s, O_RDWR): %s\r\n", pty_name,
1090 unix_error_string (errno));
1091 return -1;
1093 #if !defined(__osf__) && !defined(__linux__)
1094 #if defined (I_FIND) && defined (I_PUSH)
1095 if (!ioctl (pty_slave, I_FIND, "ptem"))
1096 if (ioctl (pty_slave, I_PUSH, "ptem") == -1) {
1097 fprintf (stderr, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
1098 pty_slave, unix_error_string (errno));
1099 close (pty_slave);
1100 return -1;
1103 if (!ioctl (pty_slave, I_FIND, "ldterm"))
1104 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1) {
1105 fprintf (stderr,
1106 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
1107 pty_slave, unix_error_string (errno));
1108 close (pty_slave);
1109 return -1;
1111 #if !defined(sgi) && !defined(__sgi)
1112 if (!ioctl (pty_slave, I_FIND, "ttcompat"))
1113 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1) {
1114 fprintf (stderr,
1115 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
1116 pty_slave, unix_error_string (errno));
1117 close (pty_slave);
1118 return -1;
1120 #endif /* sgi || __sgi */
1121 #endif /* I_FIND && I_PUSH */
1122 #endif /* __osf__ || __linux__ */
1124 return pty_slave;
1127 #else /* !HAVE_GRANTPT */
1129 /* BSD version of pty_open_master */
1130 static int pty_open_master (char *pty_name)
1132 int pty_master;
1133 const char *ptr1, *ptr2;
1135 strcpy (pty_name, "/dev/ptyXX");
1136 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1138 pty_name [8] = *ptr1;
1139 for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
1141 pty_name [9] = *ptr2;
1143 /* Try to open master */
1144 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1145 if (errno == ENOENT) /* Different from EIO */
1146 return -1; /* Out of pty devices */
1147 else
1148 continue; /* Try next pty device */
1150 pty_name [5] = 't'; /* Change "pty" to "tty" */
1151 if (access (pty_name, 6)){
1152 close (pty_master);
1153 pty_name [5] = 'p';
1154 continue;
1156 return pty_master;
1159 return -1; /* Ran out of pty devices */
1162 /* BSD version of pty_open_slave */
1163 static int
1164 pty_open_slave (const char *pty_name)
1166 int pty_slave;
1167 struct group *group_info = getgrnam ("tty");
1169 if (group_info != NULL) {
1170 /* The following two calls will only succeed if we are root */
1171 /* [Commented out while permissions problem is investigated] */
1172 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1173 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1175 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1176 fprintf (stderr, "open (pty_name, O_RDWR): %s\r\n", pty_name);
1177 return pty_slave;
1180 #endif /* !HAVE_GRANTPT */
1181 #endif /* HAVE_SUBSHELL_SUPPORT */