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.
23 #ifdef HAVE_SUBSHELL_SUPPORT
25 /* {{{ Declarations */
28 # define _GNU_SOURCE 1
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) */
39 #include <string.h> /* strstr(), strcpy(), etc. */
40 #include <signal.h> /* sigaction(), sigprocmask(), etc. */
41 #include <sys/stat.h> /* Required by dir.h & panel.h below */
44 # include <unistd.h> /* For pipe, fork, setsid, access etc */
48 # include <stropts.h> /* For I_PUSH */
49 #endif /* HAVE_STROPTS_H */
51 #include "global.h" /* For home_dir */
53 #include "dir.h" /* Required by panel.h below */
54 #include "util.h" /* Required by panel.h */
55 #include "panel.h" /* For WPanel and current_panel */
56 #include "dialog.h" /* For query_dialog() */
57 #include "main.h" /* For cpanel, quit & init_sigchld() */
58 #include "cons.saver.h" /* For handle_console(), etc. */
59 #include "key.h" /* XCTRL and ALT macros */
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
);
85 # define STDIN_FILENO 0
89 # define STDOUT_FILENO 1
93 # define STDERR_FILENO 2
96 /* If using a subshell for evaluating commands this is true */
98 #ifdef SUBSHELL_OPTIONAL
104 /* File descriptor of the pseudoterminal used by the subshell */
105 int subshell_pty
= 0;
107 /* The key for switching back to MC from the subshell */
108 char subshell_switch_key
= XCTRL('o');
110 /* State of the subshell:
111 * INACTIVE: the default state; awaiting a command
112 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
113 * RUNNING_COMMAND: return to MC when the current command finishes */
114 enum subshell_state_enum subshell_state
;
116 /* Holds the latest prompt captured from the subshell */
117 char *subshell_prompt
= NULL
;
119 /* Initial length of the buffer for the subshell's prompt */
120 #define INITIAL_PROMPT_SIZE 10
122 /* Used by the child process to indicate failure to start the subshell */
123 #define FORK_FAILURE 69 /* Arbitrary */
125 /* Initial length of the buffer for all I/O with the subshell */
126 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
129 enum {READ
=0, WRITE
=1};
132 /* Local variables */
134 static char *pty_buffer
; /* For reading/writing on the subshell's pty */
135 static int pty_buffer_size
; /* The buffer grows as needed */
136 static int subshell_pipe
[2]; /* To pass CWD info from the subshell to MC */
137 static pid_t subshell_pid
= 1; /* The subshell's process ID */
138 static char subshell_cwd
[MC_MAXPATHLEN
+1]; /* One extra char for final '\n' */
140 /* Subshell type (gleaned from the SHELL environment variable, if available) */
141 static enum {BASH
, TCSH
, ZSH
} subshell_type
;
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
;
167 # define SYNC_PTY_SIDES
169 # define SYNC_PTY_SIDES
172 #undef SYNC_PTY_SIDES
174 #ifdef SYNC_PTY_SIDES
175 /* Handler for SIGUSR1 (used below), does nothing but accept the signal */
176 static void sigusr1_handler (int sig
)
182 * Prepare child process to running the shell and run it.
184 * Modifies the global variables (in the child process only):
189 static void init_subshell_child (const char *pty_name
)
192 char *init_file
= NULL
;
194 setsid (); /* Get a fresh terminal session */
196 /* {{{ Open the slave side of the pty: again */
197 pty_slave
= pty_open_slave (pty_name
);
199 /* This must be done before closing the master side of the pty, */
200 /* or it will fail on certain idiotic systems, such as Solaris. */
202 /* Close master side of pty. This is important; apart from */
203 /* freeing up the descriptor for use in the subshell, it also */
204 /* means that when MC exits, the subshell will get a SIGHUP and */
205 /* exit too, because there will be no more descriptors pointing */
206 /* at the master side of the pty and so it will disappear. */
208 close (subshell_pty
);
210 #ifdef SYNC_PTY_SIDES
211 /* Give our parent process (MC) the go-ahead */
212 kill (getppid (), SIGUSR1
);
216 /* {{{ Make sure that it has become our controlling terminal */
218 /* Redundant on Linux and probably most systems, but just in case: */
221 ioctl (pty_slave
, TIOCSCTTY
, 0);
225 /* {{{ Configure its terminal modes and window size */
227 /* Set up the pty with the same termios flags as our own tty, plus */
228 /* TOSTOP, which keeps background processes from writing to the pty */
230 shell_mode
.c_lflag
|= TOSTOP
; /* So background writers get SIGTTOU */
231 if (tcsetattr (pty_slave
, TCSANOW
, &shell_mode
))
233 perror (__FILE__
": couldn't set pty terminal modes");
234 _exit (FORK_FAILURE
);
237 /* Set the pty's size (80x25 by default on Linux) according to the */
238 /* size of the real terminal as calculated by ncurses, if possible */
239 resize_tty (pty_slave
);
242 /* {{{ Set up the subshell's environment and init file name */
244 /* It simplifies things to change to our home directory here, */
245 /* and the user's startup file may do a `cd' command anyway */
246 chdir (home_dir
); /* FIXME? What about when we re-run the subshell? */
248 switch (subshell_type
)
251 init_file
= ".mc/bashrc";
252 if (access (init_file
, R_OK
) == -1)
253 init_file
= ".bashrc";
255 /* Make MC's special commands not show up in bash's history */
256 putenv ("HISTCONTROL=ignorespace");
258 /* Allow alternative readline settings for MC */
259 if (access (".mc/inputrc", R_OK
) == 0)
260 putenv ("INPUTRC=.mc/inputrc");
265 init_file
= ".mc/tcshrc";
266 if (access (init_file
, R_OK
) == -1)
274 fprintf (stderr
, __FILE__
": unimplemented subshell type %d\n",
276 _exit (FORK_FAILURE
);
280 /* {{{ Attach all our standard file descriptors to the pty */
282 /* This is done just before the fork, because stderr must still */
283 /* be connected to the real tty during the above error messages; */
284 /* otherwise the user will never see them. */
286 dup2 (pty_slave
, STDIN_FILENO
);
287 dup2 (pty_slave
, STDOUT_FILENO
);
288 dup2 (pty_slave
, STDERR_FILENO
);
291 /* {{{ Execute the subshell at last */
293 close (subshell_pipe
[READ
]);
294 close (pty_slave
); /* These may be FD_CLOEXEC, but just in case... */
296 switch (subshell_type
)
299 execl (shell
, "bash", "-rcfile", init_file
, NULL
);
303 execl (shell
, "tcsh", NULL
); /* What's the -rcfile equivalent? */
307 /* change from "+Z" to "-Z" by Michael Bramer
308 * (Debian-mc-maintainer) <grisu@debian.org> from a patch from
309 * Radovan Garabik <garabik@center.fmph.uniba.sk>
311 execl (shell
, "zsh", "-Z", NULL
);
316 /* If we get this far, everything failed miserably */
317 _exit (FORK_FAILURE
);
322 /* {{{ init_subshell */
325 * Fork the subshell, and set up many, many things.
327 * Possibly modifies the global variables:
328 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
329 * use_subshell - Is set to FALSE if we can't run the subshell
330 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
333 void init_subshell (void)
335 /* {{{ Local variables */
337 /* This must be remembered across calls to init_subshell() */
338 static char pty_name
[BUF_SMALL
];
342 #ifdef SYNC_PTY_SIDES
343 /* Used to wait for a SIGUSR1 signal from the subprocess */
344 sigset_t sigusr1_mask
, old_mask
;
349 /* Take the current (hopefully pristine) tty mode and make */
350 /* a raw mode based on it now, before we do anything else with it */
353 if (subshell_pty
== 0) /* First time through */
355 /* {{{ Find out what type of shell we have */
357 if (strstr (shell
, "/zsh"))
359 else if (strstr (shell
, "/tcsh"))
360 subshell_type
= TCSH
;
361 else if (strstr (shell
, "/bash") || getenv ("BASH"))
362 subshell_type
= BASH
;
365 use_subshell
= FALSE
;
370 /* {{{ Open a pty for talking to the subshell */
372 /* FIXME: We may need to open a fresh pty each time on SVR4 */
374 subshell_pty
= pty_open_master (pty_name
);
375 if (subshell_pty
== -1)
377 fputs (__FILE__
": couldn't open master side of pty\n", stderr
);
378 perror ("pty_open_master");
379 use_subshell
= FALSE
;
382 pty_slave
= pty_open_slave (pty_name
);
385 fprintf (stderr
, "couldn't open slave side of pty (%s)\n\r",
387 use_subshell
= FALSE
;
393 /* {{{ Initialise the pty's I/O buffer */
395 pty_buffer_size
= INITIAL_PTY_BUFFER_SIZE
;
396 pty_buffer
= (char *) g_malloc (pty_buffer_size
);
399 /* {{{ Create a pipe for receiving the subshell's CWD */
401 if (subshell_type
== TCSH
)
403 g_snprintf (tcsh_fifo
, sizeof (tcsh_fifo
), "%s/mc.pipe.%d",
404 mc_tmpdir(), getpid ());
405 if (mkfifo (tcsh_fifo
, 0600) == -1)
407 perror (__FILE__
": mkfifo");
408 use_subshell
= FALSE
;
412 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
414 if ((subshell_pipe
[READ
] = open (tcsh_fifo
, O_RDWR
)) == -1 ||
415 (subshell_pipe
[WRITE
] = open (tcsh_fifo
, O_RDWR
)) == -1)
417 fprintf (stderr
, _("Couldn't open named pipe %s\n"), tcsh_fifo
);
418 perror (__FILE__
": open");
419 use_subshell
= FALSE
;
423 else /* subshell_type is BASH or ZSH */
424 if (pipe (subshell_pipe
))
426 perror (__FILE__
": couldn't create pipe");
427 use_subshell
= FALSE
;
434 /* {{{ Define a handler for the sigusr1 signal */
436 #ifdef SYNC_PTY_SIDES
437 sigemptyset (&sigusr1_mask
);
438 sigaddset (&sigusr1_mask
, SIGUSR1
);
439 sigprocmask (SIG_BLOCK
, &sigusr1_mask
, &old_mask
);
440 signal (SIGUSR1
, sigusr1_handler
);
444 /* {{{ Fork the subshell */
446 subshell_alive
= TRUE
;
447 subshell_stopped
= FALSE
;
448 subshell_pid
= fork ();
450 if (subshell_pid
== -1)
452 perror (__FILE__
": couldn't spawn the subshell process");
453 /* We exit here because, if the process table is full, the */
454 /* other method of running user commands won't work either */
460 if (subshell_pid
== 0) /* We are in the child process */
462 init_subshell_child (pty_name
);
465 /* pty_slave is only opened when called the first time */
466 if (pty_slave
!= -1) {
470 #ifdef SYNC_PTY_SIDES
471 sigsuspend (&old_mask
);
472 signal (SIGUSR1
, SIG_DFL
);
473 sigprocmask (SIG_SETMASK
, &old_mask
, NULL
);
474 /* ...before installing our handler for SIGCHLD. */
478 /* {{{ Install our handler for SIGCHLD */
482 /* We could have received the SIGCHLD signal for the subshell
483 * before installing the init_sigchld */
484 pid
= waitpid (subshell_pid
, &status
, WUNTRACED
| WNOHANG
);
485 if (pid
== subshell_pid
){
486 use_subshell
= FALSE
;
493 /* {{{ Set up `precmd' or equivalent for reading the subshell's CWD */
495 switch (subshell_type
)
497 char precmd
[BUF_SMALL
];
500 g_snprintf (precmd
, sizeof (precmd
), " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
501 subshell_pipe
[WRITE
]);
505 g_snprintf (precmd
, sizeof (precmd
), "precmd(){ pwd>&%d;kill -STOP $$ }\n",
506 subshell_pipe
[WRITE
]);
510 g_snprintf (precmd
, sizeof (precmd
),
511 "set echo_style=both;"
512 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
516 write (subshell_pty
, precmd
, strlen (precmd
));
520 /* {{{ Wait until the subshell has started up and processed the command */
522 subshell_state
= RUNNING_COMMAND
;
523 enable_interrupt_key ();
524 if (!feed_subshell (QUIETLY
, TRUE
)){
525 use_subshell
= FALSE
;
527 disable_interrupt_key ();
529 use_subshell
= FALSE
; /* Subshell died instantly, so don't use it */
536 static void init_raw_mode ()
538 static int initialized
= 0;
540 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
541 /* original settings. However, here we need to make this tty very raw, */
542 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
543 /* pty. So, instead of changing the code for execute(), pre_exec(), */
544 /* etc, we just set up the modes we need here, before each command. */
546 if (initialized
== 0) /* First time: initialise `raw_mode' */
548 tcgetattr (STDOUT_FILENO
, &raw_mode
);
549 raw_mode
.c_lflag
&= ~ICANON
; /* Disable line-editing chars, etc. */
550 raw_mode
.c_lflag
&= ~ISIG
; /* Disable intr, quit & suspend chars */
551 raw_mode
.c_lflag
&= ~ECHO
; /* Disable input echoing */
552 raw_mode
.c_iflag
&= ~IXON
; /* Pass ^S/^Q to subshell undisturbed */
553 raw_mode
.c_iflag
&= ~ICRNL
; /* Don't translate CRs into LFs */
554 raw_mode
.c_oflag
&= ~OPOST
; /* Don't postprocess output */
555 raw_mode
.c_cc
[VTIME
] = 0; /* IE: wait forever, and return as */
556 raw_mode
.c_cc
[VMIN
] = 1; /* soon as a character is available */
561 /* {{{ invoke_subshell */
563 int invoke_subshell (const char *command
, int how
, char **new_dir
)
565 /* {{{ Make the MC terminal transparent */
567 tcsetattr (STDOUT_FILENO
, TCSANOW
, &raw_mode
);
571 /* Make the subshell change to MC's working directory */
573 do_subshell_chdir (cpanel
->cwd
, TRUE
, 1);
575 if (command
== NULL
) /* The user has done "C-o" from MC */
577 if (subshell_state
== INACTIVE
)
579 subshell_state
= ACTIVE
;
580 /* FIXME: possibly take out this hack; the user can
581 re-play it by hitting C-hyphen a few times! */
582 write (subshell_pty
, " \b", 2); /* Hack to make prompt reappear */
585 else /* MC has passed us a user command */
588 write (subshell_pty
, " ", 1);
589 /* FIXME: if command is long (>8KB ?) we go comma */
590 write (subshell_pty
, command
, strlen (command
));
591 write (subshell_pty
, "\n", 1);
592 subshell_state
= RUNNING_COMMAND
;
593 subshell_ready
= FALSE
;
596 feed_subshell (how
, FALSE
);
598 if (new_dir
&& subshell_alive
&& strcmp (subshell_cwd
, cpanel
->cwd
))
599 *new_dir
= subshell_cwd
; /* Make MC change to the subshell's CWD */
601 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
602 while (!subshell_alive
&& !quit
&& use_subshell
)
611 /* {{{ read_subshell_prompt */
613 int read_subshell_prompt (void)
615 /* {{{ Local variables */
617 static int prompt_size
= INITIAL_PROMPT_SIZE
;
618 int bytes
= 0, i
, rc
= 0;
619 struct timeval timeleft
= {0, 0};
623 FD_SET (subshell_pty
, &tmp
);
627 if (subshell_prompt
== NULL
) /* First time through */
629 subshell_prompt
= (char *) g_malloc (prompt_size
);
630 *subshell_prompt
= '\0';
634 while (subshell_alive
&&
635 (rc
= select (subshell_pty
+ 1, &tmp
, NULL
, NULL
, &timeleft
)))
637 /* {{{ Check for `select' errors */
643 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
644 perror ("\n"__FILE__
": select (FD_SETSIZE, &tmp...)");
651 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
653 /* {{{ Extract the prompt from the shell output */
655 for (i
=0; i
<bytes
; ++i
)
656 if (pty_buffer
[i
] == '\n' || pty_buffer
[i
] == '\r'){
662 subshell_prompt
[prompt_pos
++] = pty_buffer
[i
];
663 if (prompt_pos
== prompt_size
)
664 subshell_prompt
= (char *) g_realloc (subshell_prompt
,
668 subshell_prompt
[prompt_pos
] = '\0';
672 if (rc
== 0 && bytes
== 0)
677 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
678 static int resize_tty (int fd
)
680 #if defined TIOCSWINSZ && !defined SCO_FLAVOR
681 struct winsize tty_size
;
683 tty_size
.ws_row
= LINES
;
684 tty_size
.ws_col
= COLS
;
685 tty_size
.ws_xpixel
= tty_size
.ws_ypixel
= 0;
687 return ioctl (fd
, TIOCSWINSZ
, &tty_size
);
691 /* Resize subshell_pty */
692 void resize_subshell (void)
694 resize_tty (subshell_pty
);
697 int exit_subshell (void)
701 if (subshell_state
!= INACTIVE
&& subshell_alive
)
702 quit
= !query_dialog (_(" Warning "), _(" The shell is still active. Quit anyway? "),
703 0, 2, _("&Yes"), _("&No"));
705 if (quit
&& subshell_type
== TCSH
)
707 if (unlink (tcsh_fifo
) == -1)
708 perror (__FILE__
": couldn't remove named pipe /tmp/mc.pipe.NNN");
711 g_free (subshell_prompt
);
712 subshell_prompt
= NULL
;
720 * Carefully quote directory name to allow entering any directory safely,
721 * no matter what weird characters it may contain in its name.
722 * NOTE: Treat directory name an untrusted data, don't allow it to cause
723 * executing any commands in the shell. Escape all control characters.
724 * Use following technique:
726 * for bash - echo with `-e', 3-digit octal numbers:
727 * cd "`echo -e '\ooo...\ooo'`"
729 * for zsh - echo with `-e', 4-digit octal numbers:
730 * cd "`echo '\oooo...\oooo'`"
732 * for tcsh - echo without `-e', 4-digit octal numbers:
733 * cd "`echo '\oooo...\oooo'`"
736 subshell_name_quote (const char *s
)
739 const char echo_cmd
[] = "\"`echo '";
740 const char echo_e_cmd
[] = "\"`echo -e '";
741 const char common_end
[] = "'`\"";
742 const char *cmd_start
;
746 * Factor 5 because we need \, 0 and 3 other digits per character
747 * in the worst case (tcsh and zsh).
749 d
= ret
= g_malloc (5 * strlen (s
) + 16);
753 /* Prevent interpreting leading `-' as a switch for `cd' */
759 /* echo in tcsh doesn't understand the "-e" option */
760 if (subshell_type
== TCSH
)
761 cmd_start
= echo_cmd
;
763 cmd_start
= echo_e_cmd
;
765 /* Copy the beginning of the command to the buffer */
766 len
= strlen (cmd_start
);
767 memcpy (d
, cmd_start
, len
);
771 * Print every character in octal format with the leading backslash.
772 * tcsh and zsh may require 4-digit octals, bash doesn't like them.
774 if (subshell_type
== BASH
) {
776 sprintf(d
, "\\%03o", (unsigned char) *s
);
781 sprintf(d
, "\\0%03o", (unsigned char) *s
);
786 memcpy (d
, common_end
, sizeof (common_end
));
793 /* {{{ do_subshell_chdir */
794 /* If it actually changed the directory it returns true */
795 void do_subshell_chdir (const char *directory
, int do_update
, int reset_prompt
)
797 if (!(subshell_state
== INACTIVE
&& strcmp (subshell_cwd
, cpanel
->cwd
))){
798 /* We have to repaint the subshell prompt if we read it from
799 * the main program. Please note that in the code after this
800 * if, the cd command that is sent will make the subshell
801 * repaint the prompt, so we don't have to paint it. */
807 /* The initial space keeps this out of the command history (in bash
808 because we set "HISTCONTROL=ignorespace") */
809 write (subshell_pty
, " cd ", 4);
812 temp
= subshell_name_quote (directory
);
814 write (subshell_pty
, temp
, strlen (temp
));
817 /* Should not happen unless the directory name is so long
818 that we don't have memory to quote it. */
819 write (subshell_pty
, ".", 1);
822 write (subshell_pty
, "/", 1);
824 write (subshell_pty
, "\n", 1);
826 subshell_state
= RUNNING_COMMAND
;
827 feed_subshell (QUIETLY
, FALSE
);
829 if (subshell_alive
&& strcmp (subshell_cwd
, cpanel
->cwd
) && strcmp (cpanel
->cwd
, "."))
830 fprintf (stderr
, _("Warning: Couldn't change to %s.\n"), cpanel
->cwd
);
834 update_prompt
= FALSE
;
835 /* Make sure that MC never stores the CWD in a silly format */
836 /* like /usr////lib/../bin, or the strcmp() above will fail */
840 /* {{{ subshell_get_console_attributes */
842 void subshell_get_console_attributes (void)
844 /* {{{ Get our current terminal modes */
846 if (tcgetattr (STDOUT_FILENO
, &shell_mode
))
848 perror (__FILE__
": couldn't get terminal settings");
849 use_subshell
= FALSE
;
857 /* {{{ sigchld_handler */
859 /* Figure out whether the subshell has stopped, exited or been killed */
860 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
862 void sigchld_handler (int sig
)
867 pid
= waitpid (subshell_pid
, &status
, WUNTRACED
| WNOHANG
);
869 if (pid
== subshell_pid
) {
870 /* {{{ Figure out what has happened to the subshell */
872 if (WIFSTOPPED (status
))
874 if (WSTOPSIG (status
) == SIGSTOP
) {
875 /* The subshell has received a SIGSTOP signal */
876 subshell_stopped
= TRUE
;
878 /* The user has suspended the subshell. Revive it */
879 kill (subshell_pid
, SIGCONT
);
882 else /* The subshell has either exited normally or been killed */
884 subshell_alive
= FALSE
;
885 delete_select_channel (subshell_pty
);
886 if (WIFEXITED (status
) && WEXITSTATUS (status
) != FORK_FAILURE
)
887 quit
|= SUBSHELL_EXIT
; /* Exited normally */
893 #if defined(linux) || defined(__linux__)
894 pid
= waitpid (cons_saver_pid
, &status
, WUNTRACED
| WNOHANG
);
896 if (pid
== cons_saver_pid
) {
898 if (WIFSTOPPED (status
))
899 /* Someone has stopped cons.saver - restart it */
903 /* cons.saver has died - disable confole saving */
904 handle_console (CONSOLE_DONE
);
909 #endif /* linux || __linux__ */
910 /* If we get here, some other child exited; ignore it */
911 # ifdef __EMX__ /* Need to report */
918 /* {{{ feed_subshell */
920 /* Feed the subshell our keyboard input until it says it's finished */
922 static int feed_subshell (int how
, int fail_on_error
)
924 /* {{{ Local variables */
925 fd_set read_set
; /* For `select' */
927 int bytes
; /* For the return value from `read' */
928 int i
; /* Loop counter */
930 struct timeval wtime
; /* Maximum time we wait for the subshell */
931 struct timeval
*wptr
;
934 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
937 wptr
= fail_on_error
? &wtime
: NULL
;
943 /* {{{ Prepare the file-descriptor set and call `select' */
946 FD_SET (subshell_pty
, &read_set
);
947 FD_SET (subshell_pipe
[READ
], &read_set
);
948 maxfdp
= max (subshell_pty
, subshell_pipe
[READ
]);
949 if (how
== VISIBLY
) {
950 FD_SET (STDIN_FILENO
, &read_set
);
951 maxfdp
= max (maxfdp
, STDIN_FILENO
);
954 if (select (maxfdp
+ 1, &read_set
, NULL
, NULL
, wptr
) == -1){
956 /* Despite using SA_RESTART, we still have to check for this */
958 continue; /* try all over again */
959 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
960 perror ("\n"__FILE__
": select (FD_SETSIZE, &read_set...)");
965 if (FD_ISSET (subshell_pty
, &read_set
))
966 /* {{{ Read from the subshell, write to stdout */
968 /* This loop improves performance by reducing context switches
969 by a factor of 20 or so... unfortunately, it also hangs MC
970 randomly, because of an apparent Linux bug. Investigate. */
971 /* for (i=0; i<5; ++i) * FIXME -- experimental */
973 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
975 /* The subshell has died */
976 if (bytes
== -1 && errno
== EIO
&& !subshell_alive
)
981 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
982 perror ("\n"__FILE__
": read (subshell_pty...)");
987 write (STDOUT_FILENO
, pty_buffer
, bytes
);
992 else if (FD_ISSET (subshell_pipe
[READ
], &read_set
))
993 /* {{{ Read the subshell's CWD and capture its prompt */
996 bytes
= read (subshell_pipe
[READ
], subshell_cwd
, MC_MAXPATHLEN
+1);
999 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1000 perror ("\n"__FILE__
": read (subshell_pipe[READ]...)");
1004 subshell_cwd
[bytes
-1] = 0; /* Squash the final '\n' */
1008 subshell_ready
= TRUE
;
1009 if (subshell_state
== RUNNING_COMMAND
)
1011 subshell_state
= INACTIVE
;
1018 else if (FD_ISSET (STDIN_FILENO
, &read_set
))
1019 /* {{{ Read from stdin, write to the subshell */
1022 bytes
= read (STDIN_FILENO
, pty_buffer
, pty_buffer_size
);
1025 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1026 perror ("\n"__FILE__
": read (STDIN_FILENO, pty_buffer...)");
1030 for (i
=0; i
<bytes
; ++i
)
1031 if (pty_buffer
[i
] == subshell_switch_key
)
1033 write (subshell_pty
, pty_buffer
, i
);
1035 subshell_state
= INACTIVE
;
1039 write (subshell_pty
, pty_buffer
, bytes
);
1040 subshell_ready
= FALSE
;
1050 /* {{{ synchronize */
1052 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1053 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1055 static void synchronize (void)
1057 sigset_t sigchld_mask
, old_mask
;
1059 sigemptyset (&sigchld_mask
);
1060 sigaddset (&sigchld_mask
, SIGCHLD
);
1061 sigprocmask (SIG_BLOCK
, &sigchld_mask
, &old_mask
);
1064 * SIGCHLD should not be blocked, but we unblock it just in case.
1065 * This is known to be useful for cygwin 1.3.12 and older.
1067 sigdelset (&old_mask
, SIGCHLD
);
1069 /* Wait until the subshell has stopped */
1070 while (subshell_alive
&& !subshell_stopped
)
1071 sigsuspend (&old_mask
);
1073 /* Discard all remaining data from stdin to the subshell */
1074 tcflush (subshell_pty
, TCOFLUSH
);
1076 subshell_stopped
= FALSE
;
1077 kill (subshell_pid
, SIGCONT
);
1079 sigprocmask (SIG_SETMASK
, &old_mask
, NULL
);
1080 /* We can't do any better without modifying the shell(s) */
1084 /* {{{ pty opening functions */
1088 /* {{{ SCO version of pty_open_master */
1090 static int pty_open_master (char *pty_name
)
1096 strcpy (pty_name
, "/dev/ptyp");
1100 g_snprintf(ptr
, 9, "%d",num
); /* surpriiise ... SCO lacks itoa() */
1101 /* Try to open master */
1102 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1103 if (errno
== ENOENT
) /* Different from EIO */
1104 return -1; /* Out of pty devices */
1106 continue; /* Try next pty device */
1108 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1109 if (access (pty_name
, 6)){
1116 return -1; /* Ran out of pty devices */
1120 /* {{{ SCO version of pty_open_slave */
1122 static int pty_open_slave (const char *pty_name
)
1125 struct group
*group_info
= getgrnam ("terminal");
1127 if (group_info
!= NULL
)
1129 /* The following two calls will only succeed if we are root */
1130 /* [Commented out while permissions problem is investigated] */
1131 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1132 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1134 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1135 perror ("open (pty_name, O_RDWR)");
1141 #elif HAVE_GRANTPT /* !HAVE_SCO */
1143 /* {{{ System V version of pty_open_master */
1145 static int pty_open_master (char *pty_name
)
1152 /* getpt () is a GNU extension (glibc 2.1.x) */
1153 pty_master
= getpt ();
1155 strcpy (pty_name
, "/dev/ptmx");
1156 pty_master
= open (pty_name
, O_RDWR
);
1158 if (pty_master
== -1)
1161 if (grantpt (pty_master
) == -1 /* Grant access to slave */
1162 || unlockpt (pty_master
) == -1 /* Clear slave's lock flag */
1163 || !(slave_name
= ptsname (pty_master
))) /* Get slave's name */
1168 strcpy (pty_name
, slave_name
);
1173 /* {{{ System V version of pty_open_slave */
1175 static int pty_open_slave (const char *pty_name
)
1177 int pty_slave
= open (pty_name
, O_RDWR
);
1179 if (pty_slave
== -1)
1181 perror ("open (pty_name, O_RDWR)");
1185 #if !defined(__osf__) && !defined(linux) && !defined(__linux__)
1186 #if defined (I_FIND) && defined (I_PUSH)
1187 if (!ioctl (pty_slave
, I_FIND
, "ptem"))
1188 if (ioctl (pty_slave
, I_PUSH
, "ptem") == -1)
1190 fprintf (stderr
, "ioctl (pty_slave, I_PUSH, \"ptem\") failed\n");
1195 if (!ioctl (pty_slave
, I_FIND
, "ldterm"))
1196 if (ioctl (pty_slave
, I_PUSH
, "ldterm") == -1)
1198 fprintf (stderr
, "ioctl (pty_slave, I_PUSH, \"ldterm\") failed\n");
1203 #if !defined(sgi) && !defined(__sgi)
1204 if (!ioctl (pty_slave
, I_FIND
, "ttcompat"))
1205 if (ioctl (pty_slave
, I_PUSH
, "ttcompat") == -1)
1207 fprintf (stderr
, "ioctl (pty_slave, I_PUSH, \"ttcompat\") failed\n");
1211 #endif /* sgi || __sgi */
1212 #endif /* I_FIND && I_PUSH */
1213 #endif /* __osf__ || linux || __linux__ */
1220 #else /* !HAVE_SCO && !HAVE_GRANTPT */
1222 /* {{{ BSD version of pty_open_master */
1224 static int pty_open_master (char *pty_name
)
1229 strcpy (pty_name
, "/dev/ptyXX");
1230 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
; ++ptr1
)
1232 pty_name
[8] = *ptr1
;
1233 for (ptr2
= "0123456789abcdef"; *ptr2
; ++ptr2
)
1235 pty_name
[9] = *ptr2
;
1237 /* Try to open master */
1238 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1239 if (errno
== ENOENT
) /* Different from EIO */
1240 return -1; /* Out of pty devices */
1242 continue; /* Try next pty device */
1244 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1245 if (access (pty_name
, 6)){
1253 return -1; /* Ran out of pty devices */
1257 /* {{{ BSD version of pty_open_slave */
1259 static int pty_open_slave (const char *pty_name
)
1262 struct group
*group_info
= getgrnam ("tty");
1264 if (group_info
!= NULL
)
1266 /* The following two calls will only succeed if we are root */
1267 /* [Commented out while permissions problem is investigated] */
1268 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1269 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1271 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1272 perror ("open (pty_name, O_RDWR)");
1278 #endif /* !HAVE_SCO && !HAVE_GRANTPT */
1282 #endif /* HAVE_SUBSHELL_SUPPORT */
1284 /* {{{ Emacs local variables */
1287 Cause emacs to enter folding mode for this file: