1 /* Concurrent shell support for the Midnight Commander
2 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3 2005, 2006, 2007 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of Version 2 of the GNU General Public
7 License, as published by the Free Software Foundation.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * \brief Source: concurrent shell support
25 #ifdef HAVE_SUBSHELL_SUPPORT
28 # define _GNU_SOURCE 1
38 #include <sys/types.h>
40 #ifdef HAVE_SYS_IOCTL_H
41 # include <sys/ioctl.h>
47 # include <stropts.h> /* For I_PUSH */
48 #endif /* HAVE_STROPTS_H */
50 #include "lib/global.h"
51 #include "lib/tty/tty.h" /* LINES */
52 #include "panel.h" /* current_panel */
53 #include "wtools.h" /* query_dialog() */
54 #include "main.h" /* do_update_prompt() */
55 #include "cons.saver.h" /* handle_console() */
56 #include "lib/tty/key.h" /* XCTRL */
60 #include "lib/vfs/mc-vfs/vfs.h"
63 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
67 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
70 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
71 static char tcsh_fifo
[128];
74 static void init_raw_mode (void);
75 static int feed_subshell (int how
, int fail_on_error
);
76 static void synchronize (void);
77 static int pty_open_master (char *pty_name
);
78 static int pty_open_slave (const char *pty_name
);
79 static int resize_tty (int fd
);
82 # define STDIN_FILENO 0
86 # define STDOUT_FILENO 1
90 # define STDERR_FILENO 2
93 /* If using a subshell for evaluating commands this is true */
95 #ifdef SUBSHELL_OPTIONAL
101 /* File descriptors of the pseudoterminal used by the subshell */
102 int subshell_pty
= 0;
103 static int subshell_pty_slave
= -1;
105 /* The key for switching back to MC from the subshell */
106 static const char subshell_switch_key
= XCTRL('o') & 255;
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 */
127 enum {READ
=0, WRITE
=1};
129 static char *pty_buffer
; /* For reading/writing on the subshell's pty */
130 static int pty_buffer_size
; /* The buffer grows as needed */
131 static int subshell_pipe
[2]; /* To pass CWD info from the subshell to MC */
132 static pid_t subshell_pid
= 1; /* The subshell's process ID */
133 static char subshell_cwd
[MC_MAXPATHLEN
+1]; /* One extra char for final '\n' */
135 /* Subshell type (gleaned from the SHELL environment variable, if available) */
143 /* Flag to indicate whether the subshell is ready for next command */
144 static int subshell_ready
;
146 /* The following two flags can be changed by the SIGCHLD handler. This is */
147 /* OK, because the `int' type is updated atomically on all known machines */
148 static volatile int subshell_alive
, subshell_stopped
;
150 /* We store the terminal's initial mode here so that we can configure
151 the pty similarly, and also so we can restore the real terminal to
152 sanity if we have to exit abruptly */
153 static struct termios shell_mode
;
155 /* This is a transparent mode for the terminal where MC is running on */
156 /* It is used when the shell is active, so that the control signals */
157 /* are delivered to the shell pty */
158 static struct termios raw_mode
;
160 /* This counter indicates how many characters of prompt we have read */
161 /* FIXME: try to figure out why this had to become global */
162 static int prompt_pos
;
166 * Write all data, even if the write() call is interrupted.
169 write_all (int fd
, const void *buf
, size_t count
)
174 ret
= write (fd
, (const unsigned char *) buf
+ written
, count
);
176 if (errno
== EINTR
) {
179 return written
> 0 ? written
: ret
;
189 * Prepare child process to running the shell and run it.
191 * Modifies the global variables (in the child process only):
197 init_subshell_child (const char *pty_name
)
199 const char *init_file
= NULL
;
203 setsid (); /* Get a fresh terminal session */
205 /* Make sure that it has become our controlling terminal */
207 /* Redundant on Linux and probably most systems, but just in case: */
210 ioctl (subshell_pty_slave
, TIOCSCTTY
, 0);
213 /* Configure its terminal modes and window size */
215 /* Set up the pty with the same termios flags as our own tty */
216 if (tcsetattr (subshell_pty_slave
, TCSANOW
, &shell_mode
)) {
217 fprintf (stderr
, "Cannot set pty terminal modes: %s\r\n",
218 unix_error_string (errno
));
219 _exit (FORK_FAILURE
);
222 /* Set the pty's size (80x25 by default on Linux) according to the */
223 /* size of the real terminal as calculated by ncurses, if possible */
224 resize_tty (subshell_pty_slave
);
226 /* Set up the subshell's environment and init file name */
228 /* It simplifies things to change to our home directory here, */
229 /* and the user's startup file may do a `cd' command anyway */
230 chdir (home_dir
); /* FIXME? What about when we re-run the subshell? */
232 /* Set MC_SID to prevent running one mc from another */
235 char sid_str
[BUF_SMALL
];
236 g_snprintf (sid_str
, sizeof (sid_str
), "MC_SID=%ld",
238 putenv (g_strdup (sid_str
));
241 switch (subshell_type
) {
243 init_file
= MC_USERCONF_DIR PATH_SEP_STR
"bashrc";
244 if (access (init_file
, R_OK
) == -1)
245 init_file
= ".bashrc";
247 /* Make MC's special commands not show up in bash's history */
248 putenv ((char*)"HISTCONTROL=ignorespace");
250 /* Allow alternative readline settings for MC */
251 if (access (MC_USERCONF_DIR PATH_SEP_STR
"inputrc", R_OK
) == 0)
252 putenv ((char*)"INPUTRC=" MC_USERCONF_DIR PATH_SEP_STR
"/inputrc");
256 /* TODO: Find a way to pass initfile to TCSH and ZSH */
263 fprintf (stderr
, __FILE__
": unimplemented subshell type %d\r\n",
265 _exit (FORK_FAILURE
);
268 /* Attach all our standard file descriptors to the pty */
270 /* This is done just before the fork, because stderr must still */
271 /* be connected to the real tty during the above error messages; */
272 /* otherwise the user will never see them. */
274 dup2 (subshell_pty_slave
, STDIN_FILENO
);
275 dup2 (subshell_pty_slave
, STDOUT_FILENO
);
276 dup2 (subshell_pty_slave
, STDERR_FILENO
);
278 close (subshell_pipe
[READ
]);
279 close (subshell_pty_slave
); /* These may be FD_CLOEXEC, but just in case... */
280 /* Close master side of pty. This is important; apart from */
281 /* freeing up the descriptor for use in the subshell, it also */
282 /* means that when MC exits, the subshell will get a SIGHUP and */
283 /* exit too, because there will be no more descriptors pointing */
284 /* at the master side of the pty and so it will disappear. */
285 close (subshell_pty
);
287 /* Execute the subshell at last */
289 switch (subshell_type
) {
291 execl (shell
, "bash", "-rcfile", init_file
, (char *) NULL
);
295 execl (shell
, "tcsh", (char *) NULL
);
299 /* Use -g to exclude cmds beginning with space from history
300 * and -Z to use the line editor on non-interactive term */
301 execl (shell
, "zsh", "-Z", "-g", (char *) NULL
);
306 execl (shell
, "fish", (char *) NULL
);
310 /* If we get this far, everything failed miserably */
311 _exit (FORK_FAILURE
);
316 * Check MC_SID to prevent running one mc from another.
318 * 0 if no parent mc in our session was found,
319 * 1 if parent mc was found and the user wants to continue,
320 * 2 if parent mc was found and the user wants to quit mc.
325 pid_t my_sid
, old_sid
;
329 sid_str
= getenv ("MC_SID");
333 old_sid
= (pid_t
) strtol (sid_str
, NULL
, 0);
341 /* The parent mc is in a different session, it's OK */
342 if (old_sid
!= my_sid
)
345 r
= query_dialog (_("Warning"),
346 _("GNU Midnight Commander is already\n"
347 "running on this terminal.\n"
348 "Subshell support will be disabled."), D_ERROR
, 2,
349 _("&OK"), _("&Quit"));
359 * Fork the subshell, and set up many, many things.
361 * Possibly modifies the global variables:
362 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
363 * use_subshell - Is set to FALSE if we can't run the subshell
364 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
370 /* This must be remembered across calls to init_subshell() */
371 static char pty_name
[BUF_SMALL
];
372 char precmd
[BUF_SMALL
];
374 switch (check_sid ()) {
376 use_subshell
= FALSE
;
379 use_subshell
= FALSE
;
380 midnight_shutdown
= 1;
384 /* Take the current (hopefully pristine) tty mode and make */
385 /* a raw mode based on it now, before we do anything else with it */
388 if (subshell_pty
== 0) { /* First time through */
389 /* Find out what type of shell we have */
391 if (strstr (shell
, "/zsh") || getenv ("ZSH_VERSION"))
393 else if (strstr (shell
, "/tcsh"))
394 subshell_type
= TCSH
;
395 else if (strstr (shell
, "/csh"))
396 subshell_type
= TCSH
;
397 else if (strstr (shell
, "/bash") || getenv ("BASH"))
398 subshell_type
= BASH
;
399 else if (strstr (shell
, "/fish"))
400 subshell_type
= FISH
;
402 use_subshell
= FALSE
;
406 /* Open a pty for talking to the subshell */
408 /* FIXME: We may need to open a fresh pty each time on SVR4 */
410 subshell_pty
= pty_open_master (pty_name
);
411 if (subshell_pty
== -1) {
412 fprintf (stderr
, "Cannot open master side of pty: %s\r\n",
413 unix_error_string (errno
));
414 use_subshell
= FALSE
;
417 subshell_pty_slave
= pty_open_slave (pty_name
);
418 if (subshell_pty_slave
== -1) {
419 fprintf (stderr
, "Cannot open slave side of pty %s: %s\r\n",
420 pty_name
, unix_error_string (errno
));
421 use_subshell
= FALSE
;
425 /* Initialise the pty's I/O buffer */
427 pty_buffer_size
= INITIAL_PTY_BUFFER_SIZE
;
428 pty_buffer
= g_malloc (pty_buffer_size
);
430 /* Create a pipe for receiving the subshell's CWD */
432 if (subshell_type
== TCSH
) {
433 g_snprintf (tcsh_fifo
, sizeof (tcsh_fifo
), "%s/mc.pipe.%d",
434 mc_tmpdir (), (int) getpid ());
435 if (mkfifo (tcsh_fifo
, 0600) == -1) {
436 fprintf (stderr
, "mkfifo(%s) failed: %s\r\n", tcsh_fifo
,
437 unix_error_string (errno
));
438 use_subshell
= FALSE
;
442 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
444 if ((subshell_pipe
[READ
] = open (tcsh_fifo
, O_RDWR
)) == -1
445 || (subshell_pipe
[WRITE
] =
446 open (tcsh_fifo
, O_RDWR
)) == -1) {
447 fprintf (stderr
, _("Cannot open named pipe %s\n"), tcsh_fifo
);
448 perror (__FILE__
": open");
449 use_subshell
= FALSE
;
452 } else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe
)) {
453 perror (__FILE__
": couldn't create pipe");
454 use_subshell
= FALSE
;
459 /* Fork the subshell */
461 subshell_alive
= TRUE
;
462 subshell_stopped
= FALSE
;
463 subshell_pid
= fork ();
465 if (subshell_pid
== -1) {
466 fprintf (stderr
, "Cannot spawn the subshell process: %s\r\n",
467 unix_error_string (errno
));
468 /* We exit here because, if the process table is full, the */
469 /* other method of running user commands won't work either */
473 if (subshell_pid
== 0) { /* We are in the child process */
474 init_subshell_child (pty_name
);
477 /* Set up `precmd' or equivalent for reading the subshell's CWD */
479 switch (subshell_type
) {
481 g_snprintf (precmd
, sizeof (precmd
),
482 " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
483 subshell_pipe
[WRITE
]);
487 g_snprintf (precmd
, sizeof (precmd
),
488 " precmd(){ pwd>&%d;kill -STOP $$ }\n",
489 subshell_pipe
[WRITE
]);
493 g_snprintf (precmd
, sizeof (precmd
),
494 "set echo_style=both;"
495 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
499 g_snprintf (precmd
, sizeof (precmd
),
500 "function fish_prompt ; pwd>&%d;kill -STOP %%self; end\n",
501 subshell_pipe
[WRITE
]);
505 write_all (subshell_pty
, precmd
, strlen (precmd
));
507 /* Wait until the subshell has started up and processed the command */
509 subshell_state
= RUNNING_COMMAND
;
510 tty_enable_interrupt_key ();
511 if (!feed_subshell (QUIETLY
, TRUE
)) {
512 use_subshell
= FALSE
;
514 tty_disable_interrupt_key ();
516 use_subshell
= FALSE
; /* Subshell died instantly, so don't use it */
520 static void init_raw_mode ()
522 static int initialized
= 0;
524 /* MC calls tty_reset_shell_mode() in pre_exec() to set the real tty to its */
525 /* original settings. However, here we need to make this tty very raw, */
526 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
527 /* pty. So, instead of changing the code for execute(), pre_exec(), */
528 /* etc, we just set up the modes we need here, before each command. */
530 if (initialized
== 0) /* First time: initialise `raw_mode' */
532 tcgetattr (STDOUT_FILENO
, &raw_mode
);
533 raw_mode
.c_lflag
&= ~ICANON
; /* Disable line-editing chars, etc. */
534 raw_mode
.c_lflag
&= ~ISIG
; /* Disable intr, quit & suspend chars */
535 raw_mode
.c_lflag
&= ~ECHO
; /* Disable input echoing */
536 raw_mode
.c_iflag
&= ~IXON
; /* Pass ^S/^Q to subshell undisturbed */
537 raw_mode
.c_iflag
&= ~ICRNL
; /* Don't translate CRs into LFs */
538 raw_mode
.c_oflag
&= ~OPOST
; /* Don't postprocess output */
539 raw_mode
.c_cc
[VTIME
] = 0; /* IE: wait forever, and return as */
540 raw_mode
.c_cc
[VMIN
] = 1; /* soon as a character is available */
546 int invoke_subshell (const char *command
, int how
, char **new_dir
)
550 /* Make the MC terminal transparent */
551 tcsetattr (STDOUT_FILENO
, TCSANOW
, &raw_mode
);
553 /* Make the subshell change to MC's working directory */
555 do_subshell_chdir (current_panel
->cwd
, TRUE
, 1);
557 if (command
== NULL
) /* The user has done "C-o" from MC */
559 if (subshell_state
== INACTIVE
)
561 subshell_state
= ACTIVE
;
562 /* FIXME: possibly take out this hack; the user can
563 re-play it by hitting C-hyphen a few times! */
565 write_all (subshell_pty
, " \b", 2); /* Hack to make prompt reappear */
568 else /* MC has passed us a user command */
571 write_all (subshell_pty
, " ", 1);
572 /* FIXME: if command is long (>8KB ?) we go comma */
573 write_all (subshell_pty
, command
, strlen (command
));
574 write_all (subshell_pty
, "\n", 1);
575 subshell_state
= RUNNING_COMMAND
;
576 subshell_ready
= FALSE
;
579 feed_subshell (how
, FALSE
);
581 pcwd
= vfs_translate_path_n (current_panel
->cwd
);
582 if (new_dir
&& subshell_alive
&& strcmp (subshell_cwd
, pcwd
))
583 *new_dir
= subshell_cwd
; /* Make MC change to the subshell's CWD */
586 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
587 while (!subshell_alive
&& !quit
&& use_subshell
)
597 read_subshell_prompt (void)
599 static int prompt_size
= INITIAL_PROMPT_SIZE
;
600 int bytes
= 0, i
, rc
= 0;
601 struct timeval timeleft
= { 0, 0 };
605 FD_SET (subshell_pty
, &tmp
);
607 if (subshell_prompt
== NULL
) { /* First time through */
608 subshell_prompt
= g_malloc (prompt_size
);
609 *subshell_prompt
= '\0';
613 while (subshell_alive
615 select (subshell_pty
+ 1, &tmp
, NULL
, NULL
, &timeleft
))) {
616 /* Check for `select' errors */
621 fprintf (stderr
, "select (FD_SETSIZE, &tmp...): %s\r\n",
622 unix_error_string (errno
));
627 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
629 /* Extract the prompt from the shell output */
631 for (i
= 0; i
< bytes
; ++i
)
632 if (pty_buffer
[i
] == '\n' || pty_buffer
[i
] == '\r') {
638 subshell_prompt
[prompt_pos
++] = pty_buffer
[i
];
639 if (prompt_pos
== prompt_size
)
641 g_realloc (subshell_prompt
, prompt_size
*= 2);
644 subshell_prompt
[prompt_pos
] = '\0';
646 if (rc
== 0 && bytes
== 0)
651 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
652 static int resize_tty (int fd
)
654 #if defined TIOCSWINSZ
655 struct winsize tty_size
;
657 tty_size
.ws_row
= LINES
;
658 tty_size
.ws_col
= COLS
;
659 tty_size
.ws_xpixel
= tty_size
.ws_ypixel
= 0;
661 return ioctl (fd
, TIOCSWINSZ
, &tty_size
);
667 /* Resize subshell_pty */
668 void resize_subshell (void)
670 if (use_subshell
== 0)
673 resize_tty (subshell_pty
);
679 int subshell_quit
= TRUE
;
681 if (subshell_state
!= INACTIVE
&& subshell_alive
)
683 !query_dialog (_("Warning"),
684 _(" The shell is still active. Quit anyway? "),
685 D_NORMAL
, 2, _("&Yes"), _("&No"));
688 if (subshell_type
== TCSH
) {
689 if (unlink (tcsh_fifo
) == -1)
690 fprintf (stderr
, "Cannot remove named pipe %s: %s\r\n",
691 tcsh_fifo
, unix_error_string (errno
));
694 g_free (subshell_prompt
);
696 subshell_prompt
= NULL
;
700 return subshell_quit
;
705 * Carefully quote directory name to allow entering any directory safely,
706 * no matter what weird characters it may contain in its name.
707 * NOTE: Treat directory name an untrusted data, don't allow it to cause
708 * executing any commands in the shell. Escape all control characters.
709 * Use following technique:
711 * printf(1) with format string containing a single conversion specifier,
712 * "b", and an argument which contains a copy of the string passed to
713 * subshell_name_quote() with all characters, except digits and letters,
714 * replaced by the backslash-escape sequence \0nnn, where "nnn" is the
715 * numeric value of the character converted to octal number.
717 * cd "`printf "%b" 'ABC\0nnnDEF\0nnnXYZ'`"
721 subshell_name_quote (const char *s
)
725 const char *quote_cmd_start
, *quote_cmd_end
;
728 if (subshell_type
== FISH
) {
729 quote_cmd_start
= "(printf \"%b\" '";
730 quote_cmd_end
= "')";
732 quote_cmd_start
= "\"`printf \"%b\" '";
733 quote_cmd_end
= "'`\"";
736 /* Factor 5 because we need \, 0 and 3 other digits per character. */
737 d
= ret
= g_try_malloc (1 + (5 * strlen (s
)) + (strlen(quote_cmd_start
))
738 + (strlen(quote_cmd_end
)));
742 /* Prevent interpreting leading `-' as a switch for `cd' */
748 /* Copy the beginning of the command to the buffer */
749 strcpy (d
, quote_cmd_start
);
750 d
+= strlen(quote_cmd_start
);
753 * Print every character except digits and letters as a backslash-escape
754 * sequence of the form \0nnn, where "nnn" is the numeric value of the
755 * character converted to octal number.
758 for (; su
[0] != '\0'; ) {
759 n
= str_cget_next_char_safe (su
);
760 if (str_isalnum (su
)) {
761 memcpy (d
, su
, n
- su
);
764 for (c
= 0; c
< n
- su
; c
++) {
765 sprintf (d
, "\\0%03o", (unsigned char) su
[c
]);
772 strcpy (d
, quote_cmd_end
);
778 /* If it actually changed the directory it returns true */
780 do_subshell_chdir (const char *directory
, int do_update
, int reset_prompt
)
786 pcwd
= vfs_translate_path_n (current_panel
->cwd
);
789 (subshell_state
== INACTIVE
790 && strcmp (subshell_cwd
, pcwd
))) {
791 /* We have to repaint the subshell prompt if we read it from
792 * the main program. Please note that in the code after this
793 * if, the cd command that is sent will make the subshell
794 * repaint the prompt, so we don't have to paint it. */
801 /* The initial space keeps this out of the command history (in bash
802 because we set "HISTCONTROL=ignorespace") */
803 write_all (subshell_pty
, " cd ", 4);
805 translate
= vfs_translate_path_n (directory
);
807 temp
= subshell_name_quote (translate
);
809 write_all (subshell_pty
, temp
, strlen (temp
));
812 /* Should not happen unless the directory name is so long
813 that we don't have memory to quote it. */
814 write_all (subshell_pty
, ".", 1);
818 write_all (subshell_pty
, ".", 1);
821 write_all (subshell_pty
, "/", 1);
823 write_all (subshell_pty
, "\n", 1);
825 subshell_state
= RUNNING_COMMAND
;
826 feed_subshell (QUIETLY
, FALSE
);
828 if (subshell_alive
) {
829 int bPathNotEq
= strcmp (subshell_cwd
, pcwd
);
831 if (bPathNotEq
&& subshell_type
== TCSH
) {
832 char rp_subshell_cwd
[PATH_MAX
];
833 char rp_current_panel_cwd
[PATH_MAX
];
835 char *p_subshell_cwd
=
836 mc_realpath (subshell_cwd
, rp_subshell_cwd
);
837 char *p_current_panel_cwd
=
838 mc_realpath (pcwd
, rp_current_panel_cwd
);
840 if (p_subshell_cwd
== NULL
)
841 p_subshell_cwd
= subshell_cwd
;
842 if (p_current_panel_cwd
== NULL
)
843 p_current_panel_cwd
= pcwd
;
844 bPathNotEq
= strcmp (p_subshell_cwd
, p_current_panel_cwd
);
847 if (bPathNotEq
&& strcmp (pcwd
, ".")) {
848 char *cwd
= strip_password (g_strdup (pcwd
), 1);
849 fprintf (stderr
, _("Warning: Cannot change to %s.\n"), cwd
);
856 update_prompt
= FALSE
;
859 /* Make sure that MC never stores the CWD in a silly format */
860 /* like /usr////lib/../bin, or the strcmp() above will fail */
865 subshell_get_console_attributes (void)
867 /* Get our current terminal modes */
869 if (tcgetattr (STDOUT_FILENO
, &shell_mode
)) {
870 fprintf (stderr
, "Cannot get terminal settings: %s\r\n",
871 unix_error_string (errno
));
872 use_subshell
= FALSE
;
878 /* Figure out whether the subshell has stopped, exited or been killed */
879 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
881 sigchld_handler (int sig
)
888 pid
= waitpid (subshell_pid
, &status
, WUNTRACED
| WNOHANG
);
890 if (pid
== subshell_pid
) {
891 /* Figure out what has happened to the subshell */
893 if (WIFSTOPPED (status
)) {
894 if (WSTOPSIG (status
) == SIGSTOP
) {
895 /* The subshell has received a SIGSTOP signal */
896 subshell_stopped
= TRUE
;
898 /* The user has suspended the subshell. Revive it */
899 kill (subshell_pid
, SIGCONT
);
902 /* The subshell has either exited normally or been killed */
903 subshell_alive
= FALSE
;
904 delete_select_channel (subshell_pty
);
905 if (WIFEXITED (status
) && WEXITSTATUS (status
) != FORK_FAILURE
)
906 quit
|= SUBSHELL_EXIT
; /* Exited normally */
910 pid
= waitpid (cons_saver_pid
, &status
, WUNTRACED
| WNOHANG
);
912 if (pid
== cons_saver_pid
) {
914 if (WIFSTOPPED (status
))
915 /* Someone has stopped cons.saver - restart it */
918 /* cons.saver has died - disable confole saving */
919 handle_console (CONSOLE_DONE
);
924 #endif /* __linux__ */
926 /* If we got here, some other child exited; ignore it */
930 /* Feed the subshell our keyboard input until it says it's finished */
932 feed_subshell (int how
, int fail_on_error
)
934 fd_set read_set
; /* For `select' */
936 int bytes
; /* For the return value from `read' */
937 int i
; /* Loop counter */
939 struct timeval wtime
; /* Maximum time we wait for the subshell */
940 struct timeval
*wptr
;
942 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
945 wptr
= fail_on_error
? &wtime
: NULL
;
951 /* Prepare the file-descriptor set and call `select' */
954 FD_SET (subshell_pty
, &read_set
);
955 FD_SET (subshell_pipe
[READ
], &read_set
);
956 maxfdp
= max (subshell_pty
, subshell_pipe
[READ
]);
957 if (how
== VISIBLY
) {
958 FD_SET (STDIN_FILENO
, &read_set
);
959 maxfdp
= max (maxfdp
, STDIN_FILENO
);
962 if (select (maxfdp
+ 1, &read_set
, NULL
, NULL
, wptr
) == -1) {
964 /* Despite using SA_RESTART, we still have to check for this */
966 continue; /* try all over again */
967 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
968 fprintf (stderr
, "select (FD_SETSIZE, &read_set...): %s\r\n",
969 unix_error_string (errno
));
973 if (FD_ISSET (subshell_pty
, &read_set
))
974 /* Read from the subshell, write to stdout */
976 /* This loop improves performance by reducing context switches
977 by a factor of 20 or so... unfortunately, it also hangs MC
978 randomly, because of an apparent Linux bug. Investigate. */
979 /* for (i=0; i<5; ++i) * FIXME -- experimental */
981 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
983 /* The subshell has died */
984 if (bytes
== -1 && errno
== EIO
&& !subshell_alive
)
988 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
989 fprintf (stderr
, "read (subshell_pty...): %s\r\n",
990 unix_error_string (errno
));
995 write_all (STDOUT_FILENO
, pty_buffer
, bytes
);
998 else if (FD_ISSET (subshell_pipe
[READ
], &read_set
))
999 /* Read the subshell's CWD and capture its prompt */
1003 read (subshell_pipe
[READ
], subshell_cwd
,
1006 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1007 fprintf (stderr
, "read (subshell_pipe[READ]...): %s\r\n",
1008 unix_error_string (errno
));
1012 subshell_cwd
[bytes
- 1] = 0; /* Squash the final '\n' */
1016 subshell_ready
= TRUE
;
1017 if (subshell_state
== RUNNING_COMMAND
) {
1018 subshell_state
= INACTIVE
;
1023 else if (FD_ISSET (STDIN_FILENO
, &read_set
))
1024 /* Read from stdin, write to the subshell */
1026 bytes
= read (STDIN_FILENO
, pty_buffer
, pty_buffer_size
);
1028 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1030 "read (STDIN_FILENO, pty_buffer...): %s\r\n",
1031 unix_error_string (errno
));
1035 for (i
= 0; i
< bytes
; ++i
)
1036 if (pty_buffer
[i
] == subshell_switch_key
) {
1037 write_all (subshell_pty
, pty_buffer
, i
);
1039 subshell_state
= INACTIVE
;
1043 write_all (subshell_pty
, pty_buffer
, bytes
);
1045 if (pty_buffer
[bytes
-1] == '\n' || pty_buffer
[bytes
-1] == '\r')
1046 subshell_ready
= FALSE
;
1054 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1055 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1056 static void synchronize (void)
1058 sigset_t sigchld_mask
, old_mask
;
1060 sigemptyset (&sigchld_mask
);
1061 sigaddset (&sigchld_mask
, SIGCHLD
);
1062 sigprocmask (SIG_BLOCK
, &sigchld_mask
, &old_mask
);
1065 * SIGCHLD should not be blocked, but we unblock it just in case.
1066 * This is known to be useful for cygwin 1.3.12 and older.
1068 sigdelset (&old_mask
, SIGCHLD
);
1070 /* Wait until the subshell has stopped */
1071 while (subshell_alive
&& !subshell_stopped
)
1072 sigsuspend (&old_mask
);
1074 if (subshell_state
!= ACTIVE
) {
1075 /* Discard all remaining data from stdin to the subshell */
1076 tcflush (subshell_pty_slave
, TCIFLUSH
);
1079 subshell_stopped
= FALSE
;
1080 kill (subshell_pid
, SIGCONT
);
1082 sigprocmask (SIG_SETMASK
, &old_mask
, NULL
);
1083 /* We can't do any better without modifying the shell(s) */
1086 /* pty opening functions */
1090 /* System V version of pty_open_master */
1092 static int pty_open_master (char *pty_name
)
1097 #ifdef HAVE_POSIX_OPENPT
1098 pty_master
= posix_openpt(O_RDWR
);
1100 /* getpt () is a GNU extension (glibc 2.1.x) */
1101 pty_master
= getpt ();
1103 strcpy (pty_name
, "/dev/ptc");
1104 pty_master
= open (pty_name
, O_RDWR
);
1106 strcpy (pty_name
, "/dev/ptmx");
1107 pty_master
= open (pty_name
, O_RDWR
);
1110 if (pty_master
== -1)
1113 if (grantpt (pty_master
) == -1 /* Grant access to slave */
1114 || unlockpt (pty_master
) == -1 /* Clear slave's lock flag */
1115 || !(slave_name
= ptsname (pty_master
))) /* Get slave's name */
1120 strcpy (pty_name
, slave_name
);
1124 /* System V version of pty_open_slave */
1126 pty_open_slave (const char *pty_name
)
1128 int pty_slave
= open (pty_name
, O_RDWR
);
1130 if (pty_slave
== -1) {
1131 fprintf (stderr
, "open (%s, O_RDWR): %s\r\n", pty_name
,
1132 unix_error_string (errno
));
1135 #if !defined(__osf__) && !defined(__linux__)
1136 #if defined (I_FIND) && defined (I_PUSH)
1137 if (!ioctl (pty_slave
, I_FIND
, "ptem"))
1138 if (ioctl (pty_slave
, I_PUSH
, "ptem") == -1) {
1139 fprintf (stderr
, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
1140 pty_slave
, unix_error_string (errno
));
1145 if (!ioctl (pty_slave
, I_FIND
, "ldterm"))
1146 if (ioctl (pty_slave
, I_PUSH
, "ldterm") == -1) {
1148 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
1149 pty_slave
, unix_error_string (errno
));
1153 #if !defined(sgi) && !defined(__sgi)
1154 if (!ioctl (pty_slave
, I_FIND
, "ttcompat"))
1155 if (ioctl (pty_slave
, I_PUSH
, "ttcompat") == -1) {
1157 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
1158 pty_slave
, unix_error_string (errno
));
1162 #endif /* sgi || __sgi */
1163 #endif /* I_FIND && I_PUSH */
1164 #endif /* __osf__ || __linux__ */
1166 fcntl(pty_slave
, F_SETFD
, FD_CLOEXEC
);
1170 #else /* !HAVE_GRANTPT */
1172 /* BSD version of pty_open_master */
1173 static int pty_open_master (char *pty_name
)
1176 const char *ptr1
, *ptr2
;
1178 strcpy (pty_name
, "/dev/ptyXX");
1179 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
; ++ptr1
)
1181 pty_name
[8] = *ptr1
;
1182 for (ptr2
= "0123456789abcdef"; *ptr2
; ++ptr2
)
1184 pty_name
[9] = *ptr2
;
1186 /* Try to open master */
1187 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1188 if (errno
== ENOENT
) /* Different from EIO */
1189 return -1; /* Out of pty devices */
1191 continue; /* Try next pty device */
1193 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1194 if (access (pty_name
, 6)){
1202 return -1; /* Ran out of pty devices */
1205 /* BSD version of pty_open_slave */
1207 pty_open_slave (const char *pty_name
)
1210 struct group
*group_info
= getgrnam ("tty");
1212 if (group_info
!= NULL
) {
1213 /* The following two calls will only succeed if we are root */
1214 /* [Commented out while permissions problem is investigated] */
1215 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1216 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1218 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1219 fprintf (stderr
, "open (pty_name, O_RDWR): %s\r\n", pty_name
);
1220 fcntl(pty_slave
, F_SETFD
, FD_CLOEXEC
);
1224 #endif /* !HAVE_GRANTPT */
1225 #endif /* HAVE_SUBSHELL_SUPPORT */