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.
21 #ifdef HAVE_SUBSHELL_SUPPORT
24 # define _GNU_SOURCE 1
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_IOCTL_H
36 # include <sys/ioctl.h>
44 # include <stropts.h> /* For I_PUSH */
45 #endif /* HAVE_STROPTS_H */
48 #include "tty.h" /* LINES */
49 #include "panel.h" /* current_panel */
50 #include "wtools.h" /* query_dialog() */
51 #include "main.h" /* do_update_prompt() */
52 #include "cons.saver.h" /* handle_console() */
53 #include "key.h" /* XCTRL */
57 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
61 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
64 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
65 static char tcsh_fifo
[128];
68 static void init_raw_mode (void);
69 static int feed_subshell (int how
, int fail_on_error
);
70 static void synchronize (void);
71 static int pty_open_master (char *pty_name
);
72 static int pty_open_slave (const char *pty_name
);
73 static int resize_tty (int fd
);
76 # define STDIN_FILENO 0
80 # define STDOUT_FILENO 1
84 # define STDERR_FILENO 2
87 /* If using a subshell for evaluating commands this is true */
89 #ifdef SUBSHELL_OPTIONAL
95 /* File descriptors of the pseudoterminal used by the subshell */
97 static int subshell_pty_slave
= -1;
99 /* The key for switching back to MC from the subshell */
100 static const char subshell_switch_key
= XCTRL('o') & 255;
102 /* State of the subshell:
103 * INACTIVE: the default state; awaiting a command
104 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
105 * RUNNING_COMMAND: return to MC when the current command finishes */
106 enum subshell_state_enum subshell_state
;
108 /* Holds the latest prompt captured from the subshell */
109 char *subshell_prompt
= NULL
;
111 /* Initial length of the buffer for the subshell's prompt */
112 #define INITIAL_PROMPT_SIZE 10
114 /* Used by the child process to indicate failure to start the subshell */
115 #define FORK_FAILURE 69 /* Arbitrary */
117 /* Initial length of the buffer for all I/O with the subshell */
118 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
121 enum {READ
=0, WRITE
=1};
123 static char *pty_buffer
; /* For reading/writing on the subshell's pty */
124 static int pty_buffer_size
; /* The buffer grows as needed */
125 static int subshell_pipe
[2]; /* To pass CWD info from the subshell to MC */
126 static pid_t subshell_pid
= 1; /* The subshell's process ID */
127 static char subshell_cwd
[MC_MAXPATHLEN
+1]; /* One extra char for final '\n' */
129 /* Subshell type (gleaned from the SHELL environment variable, if available) */
130 static enum {BASH
, TCSH
, ZSH
} subshell_type
;
132 /* Flag to indicate whether the subshell is ready for next command */
133 static int subshell_ready
;
135 /* The following two flags can be changed by the SIGCHLD handler. This is */
136 /* OK, because the `int' type is updated atomically on all known machines */
137 static volatile int subshell_alive
, subshell_stopped
;
139 /* We store the terminal's initial mode here so that we can configure
140 the pty similarly, and also so we can restore the real terminal to
141 sanity if we have to exit abruptly */
142 static struct termios shell_mode
;
144 /* This is a transparent mode for the terminal where MC is running on */
145 /* It is used when the shell is active, so that the control signals */
146 /* are delivered to the shell pty */
147 static struct termios raw_mode
;
149 /* This counter indicates how many characters of prompt we have read */
150 /* FIXME: try to figure out why this had to become global */
151 static int prompt_pos
;
155 * Write all data, even if the write() call is interrupted.
158 write_all (int fd
, const void *buf
, size_t count
)
163 ret
= write (fd
, (const unsigned char *) buf
+ written
, count
);
165 if (errno
== EINTR
) {
168 return written
> 0 ? written
: ret
;
178 * Prepare child process to running the shell and run it.
180 * Modifies the global variables (in the child process only):
186 init_subshell_child (const char *pty_name
)
188 const char *init_file
= NULL
;
191 #endif /* HAVE_GETSID */
193 setsid (); /* Get a fresh terminal session */
195 /* Make sure that it has become our controlling terminal */
197 /* Redundant on Linux and probably most systems, but just in case: */
200 ioctl (subshell_pty_slave
, TIOCSCTTY
, 0);
203 /* Configure its terminal modes and window size */
205 /* Set up the pty with the same termios flags as our own tty, plus */
206 /* TOSTOP, which keeps background processes from writing to the pty */
208 shell_mode
.c_lflag
|= TOSTOP
; /* So background writers get SIGTTOU */
209 if (tcsetattr (subshell_pty_slave
, TCSANOW
, &shell_mode
)) {
210 fprintf (stderr
, "Cannot set pty terminal modes: %s\r\n",
211 unix_error_string (errno
));
212 _exit (FORK_FAILURE
);
215 /* Set the pty's size (80x25 by default on Linux) according to the */
216 /* size of the real terminal as calculated by ncurses, if possible */
217 resize_tty (subshell_pty_slave
);
219 /* Set up the subshell's environment and init file name */
221 /* It simplifies things to change to our home directory here, */
222 /* and the user's startup file may do a `cd' command anyway */
223 chdir (home_dir
); /* FIXME? What about when we re-run the subshell? */
226 /* Set MC_SID to prevent running one mc from another */
229 char sid_str
[BUF_SMALL
];
230 g_snprintf (sid_str
, sizeof (sid_str
), "MC_SID=%ld",
232 putenv (g_strdup (sid_str
));
234 #endif /* HAVE_GETSID */
236 switch (subshell_type
) {
238 init_file
= ".mc/bashrc";
239 if (access (init_file
, R_OK
) == -1)
240 init_file
= ".bashrc";
242 /* Make MC's special commands not show up in bash's history */
243 putenv ("HISTCONTROL=ignorespace");
245 /* Allow alternative readline settings for MC */
246 if (access (".mc/inputrc", R_OK
) == 0)
247 putenv ("INPUTRC=.mc/inputrc");
251 /* TODO: Find a way to pass initfile to TCSH and ZSH */
257 fprintf (stderr
, __FILE__
": unimplemented subshell type %d\r\n",
259 _exit (FORK_FAILURE
);
262 /* Attach all our standard file descriptors to the pty */
264 /* This is done just before the fork, because stderr must still */
265 /* be connected to the real tty during the above error messages; */
266 /* otherwise the user will never see them. */
268 dup2 (subshell_pty_slave
, STDIN_FILENO
);
269 dup2 (subshell_pty_slave
, STDOUT_FILENO
);
270 dup2 (subshell_pty_slave
, STDERR_FILENO
);
272 close (subshell_pipe
[READ
]);
273 close (subshell_pty_slave
); /* These may be FD_CLOEXEC, but just in case... */
274 /* Close master side of pty. This is important; apart from */
275 /* freeing up the descriptor for use in the subshell, it also */
276 /* means that when MC exits, the subshell will get a SIGHUP and */
277 /* exit too, because there will be no more descriptors pointing */
278 /* at the master side of the pty and so it will disappear. */
279 close (subshell_pty
);
281 /* Execute the subshell at last */
283 switch (subshell_type
) {
285 execl (shell
, "bash", "-rcfile", init_file
, (char *) NULL
);
289 execl (shell
, "tcsh", (char *) NULL
);
293 /* Use -g to exclude cmds beginning with space from history
294 * and -Z to use the line editor on non-interactive term */
295 execl (shell
, "zsh", "-Z", "-g", (char *) NULL
);
300 /* If we get this far, everything failed miserably */
301 _exit (FORK_FAILURE
);
307 * Check MC_SID to prevent running one mc from another.
309 * 0 if no parent mc in our session was found,
310 * 1 if parent mc was found and the user wants to continue,
311 * 2 if parent mc was found and the user wants to quit mc.
316 pid_t my_sid
, old_sid
;
320 sid_str
= getenv ("MC_SID");
324 old_sid
= (pid_t
) strtol (sid_str
, NULL
, 0);
332 /* The parent mc is in a different session, it's OK */
333 if (old_sid
!= my_sid
)
336 r
= query_dialog (_("Warning"),
337 _("GNU Midnight Commander is already\n"
338 "running on this terminal.\n"
339 "Subshell support will be disabled."), D_ERROR
, 2,
340 _("&OK"), _("&Quit"));
347 #endif /* HAVE_GETSID */
351 * Fork the subshell, and set up many, many things.
353 * Possibly modifies the global variables:
354 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
355 * use_subshell - Is set to FALSE if we can't run the subshell
356 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
362 /* This must be remembered across calls to init_subshell() */
363 static char pty_name
[BUF_SMALL
];
364 char precmd
[BUF_SMALL
];
367 switch (check_sid ()) {
369 use_subshell
= FALSE
;
372 use_subshell
= FALSE
;
373 midnight_shutdown
= 1;
376 #endif /* HAVE_GETSID */
378 /* Take the current (hopefully pristine) tty mode and make */
379 /* a raw mode based on it now, before we do anything else with it */
382 if (subshell_pty
== 0) { /* First time through */
383 /* Find out what type of shell we have */
385 if (strstr (shell
, "/zsh") || getenv ("ZSH_VERSION"))
387 else if (strstr (shell
, "/tcsh"))
388 subshell_type
= TCSH
;
389 else if (strstr (shell
, "/bash") || getenv ("BASH"))
390 subshell_type
= BASH
;
392 use_subshell
= FALSE
;
396 /* Open a pty for talking to the subshell */
398 /* FIXME: We may need to open a fresh pty each time on SVR4 */
400 subshell_pty
= pty_open_master (pty_name
);
401 if (subshell_pty
== -1) {
402 fprintf (stderr
, "Cannot open master side of pty: %s\r\n",
403 unix_error_string (errno
));
404 use_subshell
= FALSE
;
407 subshell_pty_slave
= pty_open_slave (pty_name
);
408 if (subshell_pty_slave
== -1) {
409 fprintf (stderr
, "Cannot open slave side of pty %s: %s\r\n",
410 pty_name
, unix_error_string (errno
));
411 use_subshell
= FALSE
;
415 /* Initialise the pty's I/O buffer */
417 pty_buffer_size
= INITIAL_PTY_BUFFER_SIZE
;
418 pty_buffer
= g_malloc (pty_buffer_size
);
420 /* Create a pipe for receiving the subshell's CWD */
422 if (subshell_type
== TCSH
) {
423 g_snprintf (tcsh_fifo
, sizeof (tcsh_fifo
), "%s/mc.pipe.%d",
424 mc_tmpdir (), (int) getpid ());
425 if (mkfifo (tcsh_fifo
, 0600) == -1) {
426 fprintf (stderr
, "mkfifo(%s) failed: %s\r\n", tcsh_fifo
,
427 unix_error_string (errno
));
428 use_subshell
= FALSE
;
432 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
434 if ((subshell_pipe
[READ
] = open (tcsh_fifo
, O_RDWR
)) == -1
435 || (subshell_pipe
[WRITE
] =
436 open (tcsh_fifo
, O_RDWR
)) == -1) {
437 fprintf (stderr
, _("Cannot open named pipe %s\n"), tcsh_fifo
);
438 perror (__FILE__
": open");
439 use_subshell
= FALSE
;
442 } else /* subshell_type is BASH or ZSH */ if (pipe (subshell_pipe
)) {
443 perror (__FILE__
": couldn't create pipe");
444 use_subshell
= FALSE
;
449 /* Fork the subshell */
451 subshell_alive
= TRUE
;
452 subshell_stopped
= FALSE
;
453 subshell_pid
= fork ();
455 if (subshell_pid
== -1) {
456 fprintf (stderr
, "Cannot spawn the subshell process: %s\r\n",
457 unix_error_string (errno
));
458 /* We exit here because, if the process table is full, the */
459 /* other method of running user commands won't work either */
463 if (subshell_pid
== 0) { /* We are in the child process */
464 init_subshell_child (pty_name
);
467 /* Set up `precmd' or equivalent for reading the subshell's CWD */
469 switch (subshell_type
) {
471 g_snprintf (precmd
, sizeof (precmd
),
472 " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
473 subshell_pipe
[WRITE
]);
477 g_snprintf (precmd
, sizeof (precmd
),
478 " precmd(){ pwd>&%d;kill -STOP $$ }\n",
479 subshell_pipe
[WRITE
]);
483 g_snprintf (precmd
, sizeof (precmd
),
484 "set echo_style=both;"
485 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
489 write_all (subshell_pty
, precmd
, strlen (precmd
));
491 /* Wait until the subshell has started up and processed the command */
493 subshell_state
= RUNNING_COMMAND
;
494 enable_interrupt_key ();
495 if (!feed_subshell (QUIETLY
, TRUE
)) {
496 use_subshell
= FALSE
;
498 disable_interrupt_key ();
500 use_subshell
= FALSE
; /* Subshell died instantly, so don't use it */
504 static void init_raw_mode ()
506 static int initialized
= 0;
508 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
509 /* original settings. However, here we need to make this tty very raw, */
510 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
511 /* pty. So, instead of changing the code for execute(), pre_exec(), */
512 /* etc, we just set up the modes we need here, before each command. */
514 if (initialized
== 0) /* First time: initialise `raw_mode' */
516 tcgetattr (STDOUT_FILENO
, &raw_mode
);
517 raw_mode
.c_lflag
&= ~ICANON
; /* Disable line-editing chars, etc. */
518 raw_mode
.c_lflag
&= ~ISIG
; /* Disable intr, quit & suspend chars */
519 raw_mode
.c_lflag
&= ~ECHO
; /* Disable input echoing */
520 raw_mode
.c_iflag
&= ~IXON
; /* Pass ^S/^Q to subshell undisturbed */
521 raw_mode
.c_iflag
&= ~ICRNL
; /* Don't translate CRs into LFs */
522 raw_mode
.c_oflag
&= ~OPOST
; /* Don't postprocess output */
523 raw_mode
.c_cc
[VTIME
] = 0; /* IE: wait forever, and return as */
524 raw_mode
.c_cc
[VMIN
] = 1; /* soon as a character is available */
530 int invoke_subshell (const char *command
, int how
, char **new_dir
)
532 /* Make the MC terminal transparent */
533 tcsetattr (STDOUT_FILENO
, TCSANOW
, &raw_mode
);
535 /* Make the subshell change to MC's working directory */
537 do_subshell_chdir (current_panel
->cwd
, TRUE
, 1);
539 if (command
== NULL
) /* The user has done "C-o" from MC */
541 if (subshell_state
== INACTIVE
)
543 subshell_state
= ACTIVE
;
544 /* FIXME: possibly take out this hack; the user can
545 re-play it by hitting C-hyphen a few times! */
546 write_all (subshell_pty
, " \b", 2); /* Hack to make prompt reappear */
549 else /* MC has passed us a user command */
552 write_all (subshell_pty
, " ", 1);
553 /* FIXME: if command is long (>8KB ?) we go comma */
554 write_all (subshell_pty
, command
, strlen (command
));
555 write_all (subshell_pty
, "\n", 1);
556 subshell_state
= RUNNING_COMMAND
;
557 subshell_ready
= FALSE
;
560 feed_subshell (how
, FALSE
);
562 if (new_dir
&& subshell_alive
&& strcmp (subshell_cwd
, current_panel
->cwd
))
563 *new_dir
= subshell_cwd
; /* Make MC change to the subshell's CWD */
565 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
566 while (!subshell_alive
&& !quit
&& use_subshell
)
576 read_subshell_prompt (void)
578 static int prompt_size
= INITIAL_PROMPT_SIZE
;
579 int bytes
= 0, i
, rc
= 0;
580 struct timeval timeleft
= { 0, 0 };
584 FD_SET (subshell_pty
, &tmp
);
586 if (subshell_prompt
== NULL
) { /* First time through */
587 subshell_prompt
= g_malloc (prompt_size
);
588 *subshell_prompt
= '\0';
592 while (subshell_alive
594 select (subshell_pty
+ 1, &tmp
, NULL
, NULL
, &timeleft
))) {
595 /* Check for `select' errors */
600 fprintf (stderr
, "select (FD_SETSIZE, &tmp...): %s\r\n",
601 unix_error_string (errno
));
606 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
608 /* Extract the prompt from the shell output */
610 for (i
= 0; i
< bytes
; ++i
)
611 if (pty_buffer
[i
] == '\n' || pty_buffer
[i
] == '\r') {
617 subshell_prompt
[prompt_pos
++] = pty_buffer
[i
];
618 if (prompt_pos
== prompt_size
)
620 g_realloc (subshell_prompt
, prompt_size
*= 2);
623 subshell_prompt
[prompt_pos
] = '\0';
625 if (rc
== 0 && bytes
== 0)
630 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
631 static int resize_tty (int fd
)
633 #if defined TIOCSWINSZ
634 struct winsize tty_size
;
636 tty_size
.ws_row
= LINES
;
637 tty_size
.ws_col
= COLS
;
638 tty_size
.ws_xpixel
= tty_size
.ws_ypixel
= 0;
640 return ioctl (fd
, TIOCSWINSZ
, &tty_size
);
646 /* Resize subshell_pty */
647 void resize_subshell (void)
649 if (use_subshell
== 0)
652 resize_tty (subshell_pty
);
658 int subshell_quit
= TRUE
;
660 if (subshell_state
!= INACTIVE
&& subshell_alive
)
662 !query_dialog (_("Warning"),
663 _(" The shell is still active. Quit anyway? "),
664 D_NORMAL
, 2, _("&Yes"), _("&No"));
667 if (subshell_type
== TCSH
) {
668 if (unlink (tcsh_fifo
) == -1)
669 fprintf (stderr
, "Cannot remove named pipe %s: %s\r\n",
670 tcsh_fifo
, unix_error_string (errno
));
673 g_free (subshell_prompt
);
675 subshell_prompt
= NULL
;
679 return subshell_quit
;
684 * Carefully quote directory name to allow entering any directory safely,
685 * no matter what weird characters it may contain in its name.
686 * NOTE: Treat directory name an untrusted data, don't allow it to cause
687 * executing any commands in the shell. Escape all control characters.
688 * Use following technique:
690 * printf(1) with format string containing a single conversion specifier,
691 * "b", and an argument which contains a copy of the string passed to
692 * subshell_name_quote() with all characters, except digits and letters,
693 * replaced by the backslash-escape sequence \0nnn, where "nnn" is the
694 * numeric value of the character converted to octal number.
696 * cd "`printf "%b" 'ABC\0nnnDEF\0nnnXYZ'`"
700 subshell_name_quote (const char *s
)
703 const char quote_cmd_start
[] = "\"`printf \"%b\" '";
704 const char quote_cmd_end
[] = "'`\"";
706 /* Factor 5 because we need \, 0 and 3 other digits per character. */
707 d
= ret
= g_malloc (1 + (5 * strlen (s
)) + (sizeof(quote_cmd_start
) - 1)
708 + (sizeof(quote_cmd_end
) - 1));
712 /* Prevent interpreting leading `-' as a switch for `cd' */
718 /* Copy the beginning of the command to the buffer */
719 strcpy (d
, quote_cmd_start
);
720 d
+= sizeof(quote_cmd_start
) - 1;
723 * Print every character except digits and letters as a backslash-escape
724 * sequence of the form \0nnn, where "nnn" is the numeric value of the
725 * character converted to octal number.
728 if (isalnum ((unsigned char) *s
)) {
729 *d
++ = (unsigned char) *s
;
731 sprintf (d
, "\\0%03o", (unsigned char) *s
);
736 strcpy (d
, quote_cmd_end
);
742 /* If it actually changed the directory it returns true */
744 do_subshell_chdir (const char *directory
, int do_update
, int reset_prompt
)
747 (subshell_state
== INACTIVE
748 && strcmp (subshell_cwd
, current_panel
->cwd
))) {
749 /* We have to repaint the subshell prompt if we read it from
750 * the main program. Please note that in the code after this
751 * if, the cd command that is sent will make the subshell
752 * repaint the prompt, so we don't have to paint it. */
758 /* The initial space keeps this out of the command history (in bash
759 because we set "HISTCONTROL=ignorespace") */
760 write_all (subshell_pty
, " cd ", 4);
762 char *temp
= subshell_name_quote (directory
);
764 write_all (subshell_pty
, temp
, strlen (temp
));
767 /* Should not happen unless the directory name is so long
768 that we don't have memory to quote it. */
769 write_all (subshell_pty
, ".", 1);
772 write_all (subshell_pty
, "/", 1);
774 write_all (subshell_pty
, "\n", 1);
776 subshell_state
= RUNNING_COMMAND
;
777 feed_subshell (QUIETLY
, FALSE
);
779 if (subshell_alive
) {
780 int bPathNotEq
= strcmp (subshell_cwd
, current_panel
->cwd
);
782 if (bPathNotEq
&& subshell_type
== TCSH
) {
783 char rp_subshell_cwd
[PATH_MAX
];
784 char rp_current_panel_cwd
[PATH_MAX
];
786 char *p_subshell_cwd
=
787 mc_realpath (subshell_cwd
, rp_subshell_cwd
);
788 char *p_current_panel_cwd
=
789 mc_realpath (current_panel
->cwd
, rp_current_panel_cwd
);
791 if (p_subshell_cwd
== NULL
)
792 p_subshell_cwd
= subshell_cwd
;
793 if (p_current_panel_cwd
== NULL
)
794 p_current_panel_cwd
= current_panel
->cwd
;
795 bPathNotEq
= strcmp (p_subshell_cwd
, p_current_panel_cwd
);
798 if (bPathNotEq
&& strcmp (current_panel
->cwd
, ".")) {
799 char *cwd
= strip_password (g_strdup (current_panel
->cwd
), 1);
800 fprintf (stderr
, _("Warning: Cannot change to %s.\n"), cwd
);
807 update_prompt
= FALSE
;
808 /* Make sure that MC never stores the CWD in a silly format */
809 /* like /usr////lib/../bin, or the strcmp() above will fail */
814 subshell_get_console_attributes (void)
816 /* Get our current terminal modes */
818 if (tcgetattr (STDOUT_FILENO
, &shell_mode
)) {
819 fprintf (stderr
, "Cannot get terminal settings: %s\r\n",
820 unix_error_string (errno
));
821 use_subshell
= FALSE
;
827 /* Figure out whether the subshell has stopped, exited or been killed */
828 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
830 sigchld_handler (int sig
)
837 pid
= waitpid (subshell_pid
, &status
, WUNTRACED
| WNOHANG
);
839 if (pid
== subshell_pid
) {
840 /* Figure out what has happened to the subshell */
842 if (WIFSTOPPED (status
)) {
843 if (WSTOPSIG (status
) == SIGSTOP
) {
844 /* The subshell has received a SIGSTOP signal */
845 subshell_stopped
= TRUE
;
847 /* The user has suspended the subshell. Revive it */
848 kill (subshell_pid
, SIGCONT
);
851 /* The subshell has either exited normally or been killed */
852 subshell_alive
= FALSE
;
853 delete_select_channel (subshell_pty
);
854 if (WIFEXITED (status
) && WEXITSTATUS (status
) != FORK_FAILURE
)
855 quit
|= SUBSHELL_EXIT
; /* Exited normally */
859 pid
= waitpid (cons_saver_pid
, &status
, WUNTRACED
| WNOHANG
);
861 if (pid
== cons_saver_pid
) {
863 if (WIFSTOPPED (status
))
864 /* Someone has stopped cons.saver - restart it */
867 /* cons.saver has died - disable confole saving */
868 handle_console (CONSOLE_DONE
);
873 #endif /* __linux__ */
875 /* If we got here, some other child exited; ignore it */
879 /* Feed the subshell our keyboard input until it says it's finished */
881 feed_subshell (int how
, int fail_on_error
)
883 fd_set read_set
; /* For `select' */
885 int bytes
; /* For the return value from `read' */
886 int i
; /* Loop counter */
888 struct timeval wtime
; /* Maximum time we wait for the subshell */
889 struct timeval
*wptr
;
891 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
894 wptr
= fail_on_error
? &wtime
: NULL
;
900 /* Prepare the file-descriptor set and call `select' */
903 FD_SET (subshell_pty
, &read_set
);
904 FD_SET (subshell_pipe
[READ
], &read_set
);
905 maxfdp
= max (subshell_pty
, subshell_pipe
[READ
]);
906 if (how
== VISIBLY
) {
907 FD_SET (STDIN_FILENO
, &read_set
);
908 maxfdp
= max (maxfdp
, STDIN_FILENO
);
911 if (select (maxfdp
+ 1, &read_set
, NULL
, NULL
, wptr
) == -1) {
913 /* Despite using SA_RESTART, we still have to check for this */
915 continue; /* try all over again */
916 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
917 fprintf (stderr
, "select (FD_SETSIZE, &read_set...): %s\r\n",
918 unix_error_string (errno
));
922 if (FD_ISSET (subshell_pty
, &read_set
))
923 /* Read from the subshell, write to stdout */
925 /* This loop improves performance by reducing context switches
926 by a factor of 20 or so... unfortunately, it also hangs MC
927 randomly, because of an apparent Linux bug. Investigate. */
928 /* for (i=0; i<5; ++i) * FIXME -- experimental */
930 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
932 /* The subshell has died */
933 if (bytes
== -1 && errno
== EIO
&& !subshell_alive
)
937 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
938 fprintf (stderr
, "read (subshell_pty...): %s\r\n",
939 unix_error_string (errno
));
944 write_all (STDOUT_FILENO
, pty_buffer
, bytes
);
947 else if (FD_ISSET (subshell_pipe
[READ
], &read_set
))
948 /* Read the subshell's CWD and capture its prompt */
952 read (subshell_pipe
[READ
], subshell_cwd
,
955 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
956 fprintf (stderr
, "read (subshell_pipe[READ]...): %s\r\n",
957 unix_error_string (errno
));
961 subshell_cwd
[bytes
- 1] = 0; /* Squash the final '\n' */
965 subshell_ready
= TRUE
;
966 if (subshell_state
== RUNNING_COMMAND
) {
967 subshell_state
= INACTIVE
;
972 else if (FD_ISSET (STDIN_FILENO
, &read_set
))
973 /* Read from stdin, write to the subshell */
975 bytes
= read (STDIN_FILENO
, pty_buffer
, pty_buffer_size
);
977 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
979 "read (STDIN_FILENO, pty_buffer...): %s\r\n",
980 unix_error_string (errno
));
984 for (i
= 0; i
< bytes
; ++i
)
985 if (pty_buffer
[i
] == subshell_switch_key
) {
986 write_all (subshell_pty
, pty_buffer
, i
);
988 subshell_state
= INACTIVE
;
992 write_all (subshell_pty
, pty_buffer
, bytes
);
993 subshell_ready
= FALSE
;
1001 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1002 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1003 static void synchronize (void)
1005 sigset_t sigchld_mask
, old_mask
;
1007 sigemptyset (&sigchld_mask
);
1008 sigaddset (&sigchld_mask
, SIGCHLD
);
1009 sigprocmask (SIG_BLOCK
, &sigchld_mask
, &old_mask
);
1012 * SIGCHLD should not be blocked, but we unblock it just in case.
1013 * This is known to be useful for cygwin 1.3.12 and older.
1015 sigdelset (&old_mask
, SIGCHLD
);
1017 /* Wait until the subshell has stopped */
1018 while (subshell_alive
&& !subshell_stopped
)
1019 sigsuspend (&old_mask
);
1021 if (subshell_state
!= ACTIVE
) {
1022 /* Discard all remaining data from stdin to the subshell */
1023 tcflush (subshell_pty_slave
, TCIFLUSH
);
1026 subshell_stopped
= FALSE
;
1027 kill (subshell_pid
, SIGCONT
);
1029 sigprocmask (SIG_SETMASK
, &old_mask
, NULL
);
1030 /* We can't do any better without modifying the shell(s) */
1033 /* pty opening functions */
1037 /* System V version of pty_open_master */
1039 static int pty_open_master (char *pty_name
)
1044 #ifdef HAVE_POSIX_OPENPT
1045 pty_master
= posix_openpt(O_RDWR
);
1047 /* getpt () is a GNU extension (glibc 2.1.x) */
1048 pty_master
= getpt ();
1050 strcpy (pty_name
, "/dev/ptc");
1051 pty_master
= open (pty_name
, O_RDWR
);
1053 strcpy (pty_name
, "/dev/ptmx");
1054 pty_master
= open (pty_name
, O_RDWR
);
1057 if (pty_master
== -1)
1060 if (grantpt (pty_master
) == -1 /* Grant access to slave */
1061 || unlockpt (pty_master
) == -1 /* Clear slave's lock flag */
1062 || !(slave_name
= ptsname (pty_master
))) /* Get slave's name */
1067 strcpy (pty_name
, slave_name
);
1071 /* System V version of pty_open_slave */
1073 pty_open_slave (const char *pty_name
)
1075 int pty_slave
= open (pty_name
, O_RDWR
);
1077 if (pty_slave
== -1) {
1078 fprintf (stderr
, "open (%s, O_RDWR): %s\r\n", pty_name
,
1079 unix_error_string (errno
));
1082 #if !defined(__osf__) && !defined(__linux__)
1083 #if defined (I_FIND) && defined (I_PUSH)
1084 if (!ioctl (pty_slave
, I_FIND
, "ptem"))
1085 if (ioctl (pty_slave
, I_PUSH
, "ptem") == -1) {
1086 fprintf (stderr
, "ioctl (%d, I_PUSH, \"ptem\") failed: %s\r\n",
1087 pty_slave
, unix_error_string (errno
));
1092 if (!ioctl (pty_slave
, I_FIND
, "ldterm"))
1093 if (ioctl (pty_slave
, I_PUSH
, "ldterm") == -1) {
1095 "ioctl (%d, I_PUSH, \"ldterm\") failed: %s\r\n",
1096 pty_slave
, unix_error_string (errno
));
1100 #if !defined(sgi) && !defined(__sgi)
1101 if (!ioctl (pty_slave
, I_FIND
, "ttcompat"))
1102 if (ioctl (pty_slave
, I_PUSH
, "ttcompat") == -1) {
1104 "ioctl (%d, I_PUSH, \"ttcompat\") failed: %s\r\n",
1105 pty_slave
, unix_error_string (errno
));
1109 #endif /* sgi || __sgi */
1110 #endif /* I_FIND && I_PUSH */
1111 #endif /* __osf__ || __linux__ */
1113 fcntl(pty_slave
, F_SETFD
, FD_CLOEXEC
);
1117 #else /* !HAVE_GRANTPT */
1119 /* BSD version of pty_open_master */
1120 static int pty_open_master (char *pty_name
)
1123 const char *ptr1
, *ptr2
;
1125 strcpy (pty_name
, "/dev/ptyXX");
1126 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
; ++ptr1
)
1128 pty_name
[8] = *ptr1
;
1129 for (ptr2
= "0123456789abcdef"; *ptr2
; ++ptr2
)
1131 pty_name
[9] = *ptr2
;
1133 /* Try to open master */
1134 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1135 if (errno
== ENOENT
) /* Different from EIO */
1136 return -1; /* Out of pty devices */
1138 continue; /* Try next pty device */
1140 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1141 if (access (pty_name
, 6)){
1149 return -1; /* Ran out of pty devices */
1152 /* BSD version of pty_open_slave */
1154 pty_open_slave (const char *pty_name
)
1157 struct group
*group_info
= getgrnam ("tty");
1159 if (group_info
!= NULL
) {
1160 /* The following two calls will only succeed if we are root */
1161 /* [Commented out while permissions problem is investigated] */
1162 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1163 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1165 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1166 fprintf (stderr
, "open (pty_name, O_RDWR): %s\r\n", pty_name
);
1167 fcntl(pty_slave
, F_SETFD
, FD_CLOEXEC
);
1171 #endif /* !HAVE_GRANTPT */
1172 #endif /* HAVE_SUBSHELL_SUPPORT */