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 <fcntl.h> /* For open(), etc. */
40 #include <string.h> /* strstr(), strcpy(), etc. */
41 #include <signal.h> /* sigaction(), sigprocmask(), etc. */
42 #include <sys/stat.h> /* Required by dir.h & panel.h below */
45 # include <unistd.h> /* For pipe, fork, setsid, access etc */
49 # include <stropts.h> /* For I_PUSH */
50 #endif /* HAVE_STROPTS_H */
52 #include "global.h" /* For home_dir */
54 #include "dir.h" /* Required by panel.h below */
55 #include "util.h" /* Required by panel.h */
56 #include "panel.h" /* For WPanel and current_panel */
57 #include "dialog.h" /* For query_dialog() */
58 #include "main.h" /* For cpanel, quit & init_sigchld() */
59 #include "cons.saver.h" /* For handle_console(), etc. */
60 #include "key.h" /* XCTRL and ALT macros */
64 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
68 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
72 static void init_raw_mode (void);
73 static int feed_subshell (int how
, int fail_on_error
);
74 static void synchronize (void);
75 static int pty_open_master (char *pty_name
);
76 static int pty_open_slave (const char *pty_name
);
77 static int resize_tty (int fd
);
83 # define STDIN_FILENO 0
87 # define STDOUT_FILENO 1
91 # define STDERR_FILENO 2
94 /* If using a subshell for evaluating commands this is true */
96 #ifdef SUBSHELL_OPTIONAL
102 /* File descriptor of the pseudoterminal used by the subshell */
103 int subshell_pty
= 0;
105 /* The key for switching back to MC from the subshell */
106 char subshell_switch_key
= XCTRL('o');
108 /* State of the subshell:
109 * INACTIVE: the default state; awaiting a command
110 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
111 * RUNNING_COMMAND: return to MC when the current command finishes */
112 enum subshell_state_enum subshell_state
;
114 /* Holds the latest prompt captured from the subshell */
115 char *subshell_prompt
= NULL
;
117 /* Initial length of the buffer for the subshell's prompt */
118 #define INITIAL_PROMPT_SIZE 10
120 /* Used by the child process to indicate failure to start the subshell */
121 #define FORK_FAILURE 69 /* Arbitrary */
123 /* Initial length of the buffer for all I/O with the subshell */
124 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
127 enum {READ
=0, WRITE
=1};
130 /* Local variables */
132 static char *pty_buffer
; /* For reading/writing on the subshell's pty */
133 static int pty_buffer_size
; /* The buffer grows as needed */
134 static int subshell_pipe
[2]; /* To pass CWD info from the subshell to MC */
135 static pid_t subshell_pid
= 1; /* The subshell's process ID */
136 static char subshell_cwd
[MC_MAXPATHLEN
+1]; /* One extra char for final '\n' */
138 /* Subshell type (gleaned from the SHELL environment variable, if available) */
139 static enum {BASH
, TCSH
, ZSH
} subshell_type
;
141 /* Flag to indicate whether the subshell is ready for next command */
142 static int subshell_ready
;
144 /* The following two flags can be changed by the SIGCHLD handler. This is */
145 /* OK, because the `int' type is updated atomically on all known machines */
146 static volatile int subshell_alive
, subshell_stopped
;
148 /* We store the terminal's initial mode here so that we can configure
149 the pty similarly, and also so we can restore the real terminal to
150 sanity if we have to exit abruptly */
151 static struct termios shell_mode
;
153 /* This is a transparent mode for the terminal where MC is running on */
154 /* It is used when the shell is active, so that the control signals */
155 /* are delivered to the shell pty */
156 static struct termios raw_mode
;
158 /* This counter indicates how many characters of prompt we have read */
159 /* FIXME: try to figure out why this had to become global */
160 static int prompt_pos
;
165 # define SYNC_PTY_SIDES
167 # define SYNC_PTY_SIDES
170 #undef SYNC_PTY_SIDES
172 #ifdef SYNC_PTY_SIDES
173 /* Handler for SIGUSR1 (used below), does nothing but accept the signal */
174 static void sigusr1_handler (int sig
)
180 * Prepare child process to running the shell and run it.
182 * Modifies the global variables (in the child process only):
187 static void init_subshell_child (const char *pty_name
)
190 char *init_file
= NULL
;
192 setsid (); /* Get a fresh terminal session */
194 /* {{{ Open the slave side of the pty: again */
195 pty_slave
= pty_open_slave (pty_name
);
197 /* This must be done before closing the master side of the pty, */
198 /* or it will fail on certain idiotic systems, such as Solaris. */
200 /* Close master side of pty. This is important; apart from */
201 /* freeing up the descriptor for use in the subshell, it also */
202 /* means that when MC exits, the subshell will get a SIGHUP and */
203 /* exit too, because there will be no more descriptors pointing */
204 /* at the master side of the pty and so it will disappear. */
206 close (subshell_pty
);
208 #ifdef SYNC_PTY_SIDES
209 /* Give our parent process (MC) the go-ahead */
210 kill (getppid (), SIGUSR1
);
214 /* {{{ Make sure that it has become our controlling terminal */
216 /* Redundant on Linux and probably most systems, but just in case: */
219 ioctl (pty_slave
, TIOCSCTTY
, 0);
223 /* {{{ Configure its terminal modes and window size */
225 /* Set up the pty with the same termios flags as our own tty, plus */
226 /* TOSTOP, which keeps background processes from writing to the pty */
228 shell_mode
.c_lflag
|= TOSTOP
; /* So background writers get SIGTTOU */
229 if (tcsetattr (pty_slave
, TCSANOW
, &shell_mode
))
231 perror (__FILE__
": couldn't set pty terminal modes");
232 _exit (FORK_FAILURE
);
235 /* Set the pty's size (80x25 by default on Linux) according to the */
236 /* size of the real terminal as calculated by ncurses, if possible */
237 resize_tty (pty_slave
);
240 /* {{{ Set up the subshell's environment and init file name */
242 /* It simplifies things to change to our home directory here, */
243 /* and the user's startup file may do a `cd' command anyway */
244 chdir (home_dir
); /* FIXME? What about when we re-run the subshell? */
246 switch (subshell_type
)
249 init_file
= ".mc/bashrc";
250 if (access (init_file
, R_OK
) == -1)
251 init_file
= ".bashrc";
253 /* Make MC's special commands not show up in bash's history */
254 putenv ("HISTCONTROL=ignorespace");
256 /* Allow alternative readline settings for MC */
257 if (access (".mc/inputrc", R_OK
) == 0)
258 putenv ("INPUTRC=.mc/inputrc");
263 init_file
= ".mc/tcshrc";
264 if (access (init_file
, R_OK
) == -1)
272 fprintf (stderr
, __FILE__
": unimplemented subshell type %d\n",
274 _exit (FORK_FAILURE
);
278 /* {{{ Attach all our standard file descriptors to the pty */
280 /* This is done just before the fork, because stderr must still */
281 /* be connected to the real tty during the above error messages; */
282 /* otherwise the user will never see them. */
284 dup2 (pty_slave
, STDIN_FILENO
);
285 dup2 (pty_slave
, STDOUT_FILENO
);
286 dup2 (pty_slave
, STDERR_FILENO
);
289 /* {{{ Execute the subshell at last */
291 close (subshell_pipe
[READ
]);
292 close (pty_slave
); /* These may be FD_CLOEXEC, but just in case... */
294 switch (subshell_type
)
297 execl (shell
, "bash", "-rcfile", init_file
, NULL
);
301 execl (shell
, "tcsh", NULL
); /* What's the -rcfile equivalent? */
305 /* change from "+Z" to "-Z" by Michael Bramer
306 * (Debian-mc-maintainer) <grisu@debian.org> from a patch from
307 * Radovan Garabik <garabik@center.fmph.uniba.sk>
309 execl (shell
, "zsh", "-Z", NULL
);
314 /* If we get this far, everything failed miserably */
315 _exit (FORK_FAILURE
);
320 /* {{{ init_subshell */
323 * Fork the subshell, and set up many, many things.
325 * Possibly modifies the global variables:
326 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
327 * use_subshell - Is set to FALSE if we can't run the subshell
328 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
331 void init_subshell (void)
333 /* {{{ Local variables */
335 /* This must be remembered across calls to init_subshell() */
336 static char pty_name
[BUF_SMALL
];
339 /* Braindead tcsh can't redirect output to a file descriptor? */
340 char tcsh_fifo
[sizeof "/tmp/mc.pipe.1234567890"];
343 #ifdef SYNC_PTY_SIDES
344 /* Used to wait for a SIGUSR1 signal from the subprocess */
345 sigset_t sigusr1_mask
, old_mask
;
350 /* Take the current (hopefully pristine) tty mode and make */
351 /* a raw mode based on it now, before we do anything else with it */
354 if (subshell_pty
== 0) /* First time through */
356 /* {{{ Find out what type of shell we have */
358 if (strstr (shell
, "/zsh"))
360 else if (strstr (shell
, "/tcsh"))
361 subshell_type
= TCSH
;
362 else if (strstr (shell
, "/bash") || getenv ("BASH"))
363 subshell_type
= BASH
;
366 use_subshell
= FALSE
;
371 /* {{{ Open a pty for talking to the subshell */
373 /* FIXME: We may need to open a fresh pty each time on SVR4 */
375 subshell_pty
= pty_open_master (pty_name
);
376 if (subshell_pty
== -1)
378 fputs (__FILE__
": couldn't open master side of pty\n", stderr
);
379 perror ("pty_open_master");
380 use_subshell
= FALSE
;
383 pty_slave
= pty_open_slave (pty_name
);
386 fprintf (stderr
, "couldn't open slave side of pty (%s)\n\r",
388 use_subshell
= FALSE
;
394 /* {{{ Initialise the pty's I/O buffer */
396 pty_buffer_size
= INITIAL_PTY_BUFFER_SIZE
;
397 pty_buffer
= (char *) g_malloc (pty_buffer_size
);
400 /* {{{ Create a pipe for receiving the subshell's CWD */
402 if (subshell_type
== TCSH
)
404 g_snprintf (tcsh_fifo
, sizeof (tcsh_fifo
), "/tmp/mc.pipe.%d", getpid ());
405 if (mkfifo (tcsh_fifo
, 0600) == -1)
407 perror (__FILE__
": mkfifo");
408 use_subshell
= FALSE
;
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 /* We abuse of pty_buffer here, but it doesn't matter at this stage */
708 g_snprintf (pty_buffer
, pty_buffer_size
, "/tmp/mc.pipe.%d", getpid ());
709 if (unlink (pty_buffer
) == -1)
710 perror (__FILE__
": couldn't remove named pipe /tmp/mc.pipe.NNN");
713 g_free (subshell_prompt
);
714 subshell_prompt
= NULL
;
722 * Carefully quote directory name to allow entering any directory safely,
723 * no matter what weird characters it may contain in its name.
724 * NOTE: Treat directory name an untrusted data, don't allow it to cause
725 * executing any commands in the shell. Escape all control characters.
726 * Use following technique:
728 * for bash - echo with `-e', 3-digit octal numbers:
729 * cd "`echo -e '\ooo...\ooo'`"
731 * for zsh and tcsh - echo without `-e', 4-digit octal numbers:
732 * cd "`echo '\oooo...\oooo'`"
735 subshell_name_quote (const char *s
)
738 const char bash_start
[] = "\"`echo -e '";
739 const char nonbash_start
[] = "\"`echo '";
740 const char common_end
[] = "'`\"";
743 * Factor 5 because we need \, 0 and 3 other digits per character
744 * in the worst case (tcsh and zsh).
746 d
= ret
= g_malloc (5 * strlen (s
) + 16);
748 /* Prevent interpreting leading `-' as a switch for `cd' */
755 * Print every character in octal format with the leading backslash.
756 * tcsh and zsh require leading 0, bash doesn't like 4-digit octals
757 * and requires `-e' for echo.
759 if (subshell_type
== BASH
) {
760 memcpy (d
, bash_start
, sizeof (bash_start
) - 1);
761 d
+= sizeof (bash_start
) - 1;
763 sprintf(d
, "\\%03o", (unsigned char) *s
);
767 memcpy (d
, nonbash_start
, sizeof (nonbash_start
) - 1);
768 d
+= sizeof (nonbash_start
) - 1;
770 sprintf(d
, "\\0%03o", (unsigned char) *s
);
775 memcpy (d
, common_end
, sizeof (common_end
));
782 /* {{{ do_subshell_chdir */
783 /* If it actually changed the directory it returns true */
784 void do_subshell_chdir (const char *directory
, int do_update
, int reset_prompt
)
786 if (!(subshell_state
== INACTIVE
&& strcmp (subshell_cwd
, cpanel
->cwd
))){
787 /* We have to repaint the subshell prompt if we read it from
788 * the main program. Please note that in the code after this
789 * if, the cd command that is sent will make the subshell
790 * repaint the prompt, so we don't have to paint it. */
796 /* The initial space keeps this out of the command history (in bash
797 because we set "HISTCONTROL=ignorespace") */
798 write (subshell_pty
, " cd ", 4);
801 temp
= subshell_name_quote (directory
);
802 write (subshell_pty
, temp
, strlen (temp
));
805 write (subshell_pty
, "/", 1);
807 write (subshell_pty
, "\n", 1);
809 subshell_state
= RUNNING_COMMAND
;
810 feed_subshell (QUIETLY
, FALSE
);
812 if (subshell_alive
&& strcmp (subshell_cwd
, cpanel
->cwd
) && strcmp (cpanel
->cwd
, "."))
813 fprintf (stderr
, _("Warning: Couldn't change to %s.\n"), cpanel
->cwd
);
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 /* {{{ subshell_get_console_attributes */
825 void subshell_get_console_attributes (void)
827 /* {{{ Get our current terminal modes */
829 if (tcgetattr (STDOUT_FILENO
, &shell_mode
))
831 perror (__FILE__
": couldn't get terminal settings");
832 use_subshell
= FALSE
;
840 /* {{{ sigchld_handler */
842 /* Figure out whether the subshell has stopped, exited or been killed */
843 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
845 void sigchld_handler (int sig
)
850 pid
= waitpid (subshell_pid
, &status
, WUNTRACED
| WNOHANG
);
852 if (pid
== subshell_pid
) {
853 /* {{{ Figure out what has happened to the subshell */
855 if (WIFSTOPPED (status
))
857 if (WSTOPSIG (status
) == SIGSTOP
) {
858 /* The subshell has received a SIGSTOP signal */
859 subshell_stopped
= TRUE
;
861 /* The user has suspended the subshell. Revive it */
862 kill (subshell_pid
, SIGCONT
);
865 else /* The subshell has either exited normally or been killed */
867 subshell_alive
= FALSE
;
868 delete_select_channel (subshell_pty
);
869 if (WIFEXITED (status
) && WEXITSTATUS (status
) != FORK_FAILURE
)
870 quit
|= SUBSHELL_EXIT
; /* Exited normally */
876 #if defined(linux) || defined(__linux__)
877 pid
= waitpid (cons_saver_pid
, &status
, WUNTRACED
| WNOHANG
);
879 if (pid
== cons_saver_pid
) {
881 if (WIFSTOPPED (status
))
882 /* Someone has stopped cons.saver - restart it */
886 /* cons.saver has died - disable confole saving */
887 handle_console (CONSOLE_DONE
);
892 #endif /* linux || __linux__ */
893 /* If we get here, some other child exited; ignore it */
894 # ifdef __EMX__ /* Need to report */
901 /* {{{ feed_subshell */
903 /* Feed the subshell our keyboard input until it says it's finished */
905 static int feed_subshell (int how
, int fail_on_error
)
907 /* {{{ Local variables */
908 fd_set read_set
; /* For `select' */
910 int bytes
; /* For the return value from `read' */
911 int i
; /* Loop counter */
913 struct timeval wtime
; /* Maximum time we wait for the subshell */
914 struct timeval
*wptr
;
917 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
920 wptr
= fail_on_error
? &wtime
: NULL
;
926 /* {{{ Prepare the file-descriptor set and call `select' */
929 FD_SET (subshell_pty
, &read_set
);
930 FD_SET (subshell_pipe
[READ
], &read_set
);
931 maxfdp
= max (subshell_pty
, subshell_pipe
[READ
]);
932 if (how
== VISIBLY
) {
933 FD_SET (STDIN_FILENO
, &read_set
);
934 maxfdp
= max (maxfdp
, STDIN_FILENO
);
937 if (select (maxfdp
+ 1, &read_set
, NULL
, NULL
, wptr
) == -1){
939 /* Despite using SA_RESTART, we still have to check for this */
941 continue; /* try all over again */
942 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
943 perror ("\n"__FILE__
": select (FD_SETSIZE, &read_set...)");
948 if (FD_ISSET (subshell_pty
, &read_set
))
949 /* {{{ Read from the subshell, write to stdout */
951 /* This loop improves performance by reducing context switches
952 by a factor of 20 or so... unfortunately, it also hangs MC
953 randomly, because of an apparent Linux bug. Investigate. */
954 /* for (i=0; i<5; ++i) * FIXME -- experimental */
956 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
958 /* The subshell has died */
959 if (bytes
== -1 && errno
== EIO
&& !subshell_alive
)
964 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
965 perror ("\n"__FILE__
": read (subshell_pty...)");
970 write (STDOUT_FILENO
, pty_buffer
, bytes
);
975 else if (FD_ISSET (subshell_pipe
[READ
], &read_set
))
976 /* {{{ Read the subshell's CWD and capture its prompt */
979 bytes
= read (subshell_pipe
[READ
], subshell_cwd
, MC_MAXPATHLEN
+1);
982 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
983 perror ("\n"__FILE__
": read (subshell_pipe[READ]...)");
987 subshell_cwd
[bytes
-1] = 0; /* Squash the final '\n' */
991 subshell_ready
= TRUE
;
992 if (subshell_state
== RUNNING_COMMAND
)
994 subshell_state
= INACTIVE
;
1001 else if (FD_ISSET (STDIN_FILENO
, &read_set
))
1002 /* {{{ Read from stdin, write to the subshell */
1005 bytes
= read (STDIN_FILENO
, pty_buffer
, pty_buffer_size
);
1008 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1009 perror ("\n"__FILE__
": read (STDIN_FILENO, pty_buffer...)");
1013 for (i
=0; i
<bytes
; ++i
)
1014 if (pty_buffer
[i
] == subshell_switch_key
)
1016 write (subshell_pty
, pty_buffer
, i
);
1018 subshell_state
= INACTIVE
;
1022 write (subshell_pty
, pty_buffer
, bytes
);
1023 subshell_ready
= FALSE
;
1033 /* {{{ synchronize */
1035 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1036 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1038 static void synchronize (void)
1040 sigset_t sigchld_mask
, old_mask
;
1042 sigemptyset (&sigchld_mask
);
1043 sigaddset (&sigchld_mask
, SIGCHLD
);
1044 sigprocmask (SIG_BLOCK
, &sigchld_mask
, &old_mask
);
1047 * SIGCHLD should not be blocked, but we unblock it just in case.
1048 * This is known to be useful for cygwin 1.3.12 and older.
1050 sigdelset (&old_mask
, SIGCHLD
);
1052 /* Wait until the subshell has stopped */
1053 while (subshell_alive
&& !subshell_stopped
)
1054 sigsuspend (&old_mask
);
1056 /* Discard all remaining data from stdin to the subshell */
1057 tcflush (subshell_pty
, TCOFLUSH
);
1059 subshell_stopped
= FALSE
;
1060 kill (subshell_pid
, SIGCONT
);
1062 sigprocmask (SIG_SETMASK
, &old_mask
, NULL
);
1063 /* We can't do any better without modifying the shell(s) */
1067 /* {{{ pty opening functions */
1071 /* {{{ SCO version of pty_open_master */
1073 static int pty_open_master (char *pty_name
)
1079 strcpy (pty_name
, "/dev/ptyp");
1083 g_snprintf(ptr
, 9, "%d",num
); /* surpriiise ... SCO lacks itoa() */
1084 /* Try to open master */
1085 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1086 if (errno
== ENOENT
) /* Different from EIO */
1087 return -1; /* Out of pty devices */
1089 continue; /* Try next pty device */
1091 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1092 if (access (pty_name
, 6)){
1099 return -1; /* Ran out of pty devices */
1103 /* {{{ SCO version of pty_open_slave */
1105 static int pty_open_slave (const char *pty_name
)
1108 struct group
*group_info
= getgrnam ("terminal");
1110 if (group_info
!= NULL
)
1112 /* The following two calls will only succeed if we are root */
1113 /* [Commented out while permissions problem is investigated] */
1114 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1115 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1117 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1118 perror ("open (pty_name, O_RDWR)");
1124 #elif HAVE_GRANTPT /* !HAVE_SCO */
1126 /* {{{ System V version of pty_open_master */
1128 static int pty_open_master (char *pty_name
)
1135 /* getpt () is a GNU extension (glibc 2.1.x) */
1136 pty_master
= getpt ();
1138 strcpy (pty_name
, "/dev/ptmx");
1139 pty_master
= open (pty_name
, O_RDWR
);
1141 if (pty_master
== -1)
1144 if (grantpt (pty_master
) == -1 /* Grant access to slave */
1145 || unlockpt (pty_master
) == -1 /* Clear slave's lock flag */
1146 || !(slave_name
= ptsname (pty_master
))) /* Get slave's name */
1151 strcpy (pty_name
, slave_name
);
1156 /* {{{ System V version of pty_open_slave */
1158 static int pty_open_slave (const char *pty_name
)
1160 int pty_slave
= open (pty_name
, O_RDWR
);
1162 if (pty_slave
== -1)
1164 perror ("open (pty_name, O_RDWR)");
1168 #if !defined(__osf__) && !defined(linux) && !defined(__linux__)
1169 #if defined (I_FIND) && defined (I_PUSH)
1170 if (!ioctl (pty_slave
, I_FIND
, "ptem"))
1171 if (ioctl (pty_slave
, I_PUSH
, "ptem") == -1)
1173 fprintf (stderr
, "ioctl (pty_slave, I_PUSH, \"ptem\") failed\n");
1178 if (!ioctl (pty_slave
, I_FIND
, "ldterm"))
1179 if (ioctl (pty_slave
, I_PUSH
, "ldterm") == -1)
1181 fprintf (stderr
, "ioctl (pty_slave, I_PUSH, \"ldterm\") failed\n");
1186 #if !defined(sgi) && !defined(__sgi)
1187 if (!ioctl (pty_slave
, I_FIND
, "ttcompat"))
1188 if (ioctl (pty_slave
, I_PUSH
, "ttcompat") == -1)
1190 fprintf (stderr
, "ioctl (pty_slave, I_PUSH, \"ttcompat\") failed\n");
1194 #endif /* sgi || __sgi */
1195 #endif /* I_FIND && I_PUSH */
1196 #endif /* __osf__ || linux || __linux__ */
1203 #else /* !HAVE_SCO && !HAVE_GRANTPT */
1205 /* {{{ BSD version of pty_open_master */
1207 static int pty_open_master (char *pty_name
)
1212 strcpy (pty_name
, "/dev/ptyXX");
1213 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
; ++ptr1
)
1215 pty_name
[8] = *ptr1
;
1216 for (ptr2
= "0123456789abcdef"; *ptr2
; ++ptr2
)
1218 pty_name
[9] = *ptr2
;
1220 /* Try to open master */
1221 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1222 if (errno
== ENOENT
) /* Different from EIO */
1223 return -1; /* Out of pty devices */
1225 continue; /* Try next pty device */
1227 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1228 if (access (pty_name
, 6)){
1236 return -1; /* Ran out of pty devices */
1240 /* {{{ BSD version of pty_open_slave */
1242 static int pty_open_slave (const char *pty_name
)
1245 struct group
*group_info
= getgrnam ("tty");
1247 if (group_info
!= NULL
)
1249 /* The following two calls will only succeed if we are root */
1250 /* [Commented out while permissions problem is investigated] */
1251 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1252 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1254 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1255 perror ("open (pty_name, O_RDWR)");
1261 #endif /* !HAVE_SCO && !HAVE_GRANTPT */
1265 #endif /* HAVE_SUBSHELL_SUPPORT */
1267 /* {{{ Emacs local variables */
1270 Cause emacs to enter folding mode for this file: