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 */
53 # include <unix.h> /* exec*() from <process.h> */
56 #include "global.h" /* For home_dir */
58 #include "dir.h" /* Required by panel.h below */
59 #include "util.h" /* Required by panel.h */
60 #include "panel.h" /* For WPanel and current_panel */
61 #include "dialog.h" /* For query_dialog() */
62 #include "main.h" /* For cpanel, quit & init_sigchld() */
63 #include "cons.saver.h" /* For handle_console(), etc. */
64 #include "key.h" /* XCTRL and ALT macros */
68 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
72 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
76 static void init_raw_mode (void);
77 static int feed_subshell (int how
, int fail_on_error
);
78 static void synchronize (void);
79 static int pty_open_master (char *pty_name
);
80 static int pty_open_slave (const char *pty_name
);
86 # define STDIN_FILENO 0
90 # define STDOUT_FILENO 1
94 # define STDERR_FILENO 2
97 /* If using a subshell for evaluating commands this is true */
99 #ifdef SUBSHELL_OPTIONAL
105 /* File descriptor of the pseudoterminal used by the subshell */
106 int subshell_pty
= 0;
108 /* If true, the child forked in init_subshell will wait in a loop to be attached by gdb */
109 int debug_subshell
= 0;
111 /* The key for switching back to MC from the subshell */
112 char subshell_switch_key
= XCTRL('o');
114 /* State of the subshell:
115 * INACTIVE: the default state; awaiting a command
116 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
117 * RUNNING_COMMAND: return to MC when the current command finishes */
118 enum subshell_state_enum subshell_state
;
120 /* Holds the latest prompt captured from the subshell */
121 char *subshell_prompt
= NULL
;
123 /* Initial length of the buffer for the subshell's prompt */
124 #define INITIAL_PROMPT_SIZE 10
126 /* Used by the child process to indicate failure to start the subshell */
127 #define FORK_FAILURE 69 /* Arbitrary */
129 /* Initial length of the buffer for all I/O with the subshell */
130 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
133 enum {READ
=0, WRITE
=1};
136 /* Local variables */
138 static char *pty_buffer
; /* For reading/writing on the subshell's pty */
139 static int pty_buffer_size
; /* The buffer grows as needed */
140 static int subshell_pipe
[2]; /* To pass CWD info from the subshell to MC */
141 static pid_t subshell_pid
= 1; /* The subshell's process ID */
142 static char subshell_cwd
[MC_MAXPATHLEN
+1]; /* One extra char for final '\n' */
144 /* Subshell type (gleaned from the SHELL environment variable, if available) */
145 static enum {BASH
, TCSH
, ZSH
} subshell_type
;
147 /* Flag to indicate whether the subshell is ready for next command */
148 static int subshell_ready
;
150 /* The following two flags can be changed by the SIGCHLD handler. This is */
151 /* OK, because the `int' type is updated atomically on all known machines */
152 static volatile int subshell_alive
, subshell_stopped
;
154 /* We store the terminal's initial mode here so that we can configure
155 the pty similarly, and also so we can restore the real terminal to
156 sanity if we have to exit abruptly */
157 static struct termios shell_mode
;
159 /* This is a transparent mode for the terminal where MC is running on */
160 /* It is used when the shell is active, so that the control signals */
161 /* are delivered to the shell pty */
162 static struct termios raw_mode
;
164 /* This counter indicates how many characters of prompt we have read */
165 /* FIXME: try to figure out why this had to become global */
166 static int prompt_pos
;
171 # define SYNC_PTY_SIDES
173 # define SYNC_PTY_SIDES
176 #undef SYNC_PTY_SIDES
178 #ifdef SYNC_PTY_SIDES
179 /* Handler for SIGUSR1 (used below), does nothing but accept the signal */
180 static void sigusr1_handler (int sig
)
186 * Prepare child process to running the shell and run it.
188 * Modifies the global variables (in the child process only):
193 static void init_subshell_child (const char *pty_name
)
196 char *init_file
= NULL
;
198 setsid (); /* Get a fresh terminal session */
200 /* {{{ Open the slave side of the pty: again */
201 pty_slave
= pty_open_slave (pty_name
);
203 /* This must be done before closing the master side of the pty, */
204 /* or it will fail on certain idiotic systems, such as Solaris. */
206 /* Close master side of pty. This is important; apart from */
207 /* freeing up the descriptor for use in the subshell, it also */
208 /* means that when MC exits, the subshell will get a SIGHUP and */
209 /* exit too, because there will be no more descriptors pointing */
210 /* at the master side of the pty and so it will disappear. */
212 close (subshell_pty
);
214 #ifdef SYNC_PTY_SIDES
215 /* Give our parent process (MC) the go-ahead */
216 kill (getppid (), SIGUSR1
);
220 /* {{{ Make sure that it has become our controlling terminal */
222 /* Redundant on Linux and probably most systems, but just in case: */
225 ioctl (pty_slave
, TIOCSCTTY
, 0);
229 /* {{{ Configure its terminal modes and window size */
231 /* Set up the pty with the same termios flags as our own tty, plus */
232 /* TOSTOP, which keeps background processes from writing to the pty */
234 shell_mode
.c_lflag
|= TOSTOP
; /* So background writers get SIGTTOU */
235 if (tcsetattr (pty_slave
, TCSANOW
, &shell_mode
))
237 perror (__FILE__
": couldn't set pty terminal modes");
238 _exit (FORK_FAILURE
);
241 /* Set the pty's size (80x25 by default on Linux) according to the */
242 /* size of the real terminal as calculated by ncurses, if possible */
243 #if defined TIOCSWINSZ && !defined SCO_FLAVOR
245 struct winsize tty_size
;
246 tty_size
.ws_row
= LINES
;
247 tty_size
.ws_col
= COLS
;
248 tty_size
.ws_xpixel
= tty_size
.ws_ypixel
= 0;
250 if (ioctl (pty_slave
, TIOCSWINSZ
, &tty_size
))
251 perror (__FILE__
": couldn't set pty size");
256 /* {{{ Set up the subshell's environment and init file name */
258 /* It simplifies things to change to our home directory here, */
259 /* and the user's startup file may do a `cd' command anyway */
260 chdir (home_dir
); /* FIXME? What about when we re-run the subshell? */
262 switch (subshell_type
)
265 init_file
= ".mc/bashrc";
266 if (access (init_file
, R_OK
) == -1)
267 init_file
= ".bashrc";
269 /* Make MC's special commands not show up in bash's history */
270 putenv ("HISTCONTROL=ignorespace");
272 /* Allow alternative readline settings for MC */
273 if (access (".mc/inputrc", R_OK
) == 0)
274 putenv ("INPUTRC=.mc/inputrc");
279 init_file
= ".mc/tcshrc";
280 if (access (init_file
, R_OK
) == -1)
288 fprintf (stderr
, __FILE__
": unimplemented subshell type %d\n",
290 _exit (FORK_FAILURE
);
294 /* {{{ Attach all our standard file descriptors to the pty */
296 /* This is done just before the fork, because stderr must still */
297 /* be connected to the real tty during the above error messages; */
298 /* otherwise the user will never see them. */
300 dup2 (pty_slave
, STDIN_FILENO
);
301 dup2 (pty_slave
, STDOUT_FILENO
);
302 dup2 (pty_slave
, STDERR_FILENO
);
305 /* {{{ Execute the subshell at last */
307 close (subshell_pipe
[READ
]);
308 close (pty_slave
); /* These may be FD_CLOEXEC, but just in case... */
310 switch (subshell_type
)
313 execl (shell
, "bash", "-rcfile", init_file
, NULL
);
317 execl (shell
, "tcsh", NULL
); /* What's the -rcfile equivalent? */
321 /* change from "+Z" to "-Z" by Michael Bramer
322 * (Debian-mc-maintainer) <grisu@debian.org> from a patch from
323 * Radovan Garabik <garabik@center.fmph.uniba.sk>
325 execl (shell
, "zsh", "-Z", NULL
);
330 /* If we get this far, everything failed miserably */
331 _exit (FORK_FAILURE
);
336 /* {{{ init_subshell */
339 * Fork the subshell, and set up many, many things.
341 * Possibly modifies the global variables:
342 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
343 * use_subshell - Is set to FALSE if we can't run the subshell
344 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
347 void init_subshell (void)
349 /* {{{ Local variables */
351 /* This must be remembered across calls to init_subshell() */
352 static char pty_name
[BUF_SMALL
];
355 /* Braindead tcsh can't redirect output to a file descriptor? */
356 char tcsh_fifo
[sizeof "/tmp/mc.pipe.1234567890"];
359 #ifdef SYNC_PTY_SIDES
360 /* Used to wait for a SIGUSR1 signal from the subprocess */
361 sigset_t sigusr1_mask
, old_mask
;
366 /* Take the current (hopefully pristine) tty mode and make */
367 /* a raw mode based on it now, before we do anything else with it */
370 if (subshell_pty
== 0) /* First time through */
372 /* {{{ Find out what type of shell we have */
374 if (strstr (shell
, "/zsh"))
376 else if (strstr (shell
, "/tcsh"))
377 subshell_type
= TCSH
;
378 else if (strstr (shell
, "/bash") || getenv ("BASH"))
379 subshell_type
= BASH
;
382 use_subshell
= FALSE
;
387 /* {{{ Open a pty for talking to the subshell */
389 /* FIXME: We may need to open a fresh pty each time on SVR4 */
391 subshell_pty
= pty_open_master (pty_name
);
392 if (subshell_pty
== -1)
394 fputs (__FILE__
": couldn't open master side of pty\n", stderr
);
395 perror ("pty_open_master");
396 use_subshell
= FALSE
;
399 pty_slave
= pty_open_slave (pty_name
);
402 fprintf (stderr
, "couldn't open slave side of pty (%s)\n\r",
404 use_subshell
= FALSE
;
410 /* {{{ Initialise the pty's I/O buffer */
412 pty_buffer_size
= INITIAL_PTY_BUFFER_SIZE
;
413 pty_buffer
= (char *) g_malloc (pty_buffer_size
);
416 /* {{{ Create a pipe for receiving the subshell's CWD */
418 if (subshell_type
== TCSH
)
420 g_snprintf (tcsh_fifo
, sizeof (tcsh_fifo
), "/tmp/mc.pipe.%d", getpid ());
421 if (mkfifo (tcsh_fifo
, 0600) == -1)
423 perror (__FILE__
": mkfifo");
424 use_subshell
= FALSE
;
428 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
430 if ((subshell_pipe
[READ
] = open (tcsh_fifo
, O_RDWR
)) == -1 ||
431 (subshell_pipe
[WRITE
] = open (tcsh_fifo
, O_RDWR
)) == -1)
433 fprintf (stderr
, _("Couldn't open named pipe %s\n"), tcsh_fifo
);
434 perror (__FILE__
": open");
435 use_subshell
= FALSE
;
439 else /* subshell_type is BASH or ZSH */
440 if (pipe (subshell_pipe
))
442 perror (__FILE__
": couldn't create pipe");
443 use_subshell
= FALSE
;
450 /* {{{ Define a handler for the sigusr1 signal */
452 #ifdef SYNC_PTY_SIDES
453 sigemptyset (&sigusr1_mask
);
454 sigaddset (&sigusr1_mask
, SIGUSR1
);
455 sigprocmask (SIG_BLOCK
, &sigusr1_mask
, &old_mask
);
456 signal (SIGUSR1
, sigusr1_handler
);
460 /* {{{ Fork the subshell */
462 subshell_alive
= TRUE
;
463 subshell_stopped
= FALSE
;
464 subshell_pid
= fork ();
466 if (subshell_pid
== -1)
468 perror (__FILE__
": couldn't spawn the subshell process");
469 /* We exit here because, if the process table is full, the */
470 /* other method of running user commands won't work either */
476 if (subshell_pid
== 0) /* We are in the child process */
478 init_subshell_child (pty_name
);
481 /* pty_slave is only opened when called the first time */
482 if (pty_slave
!= -1) {
486 #ifdef SYNC_PTY_SIDES
487 sigsuspend (&old_mask
);
488 signal (SIGUSR1
, SIG_DFL
);
489 sigprocmask (SIG_SETMASK
, &old_mask
, NULL
);
490 /* ...before installing our handler for SIGCHLD. */
494 /* {{{ Install our handler for SIGCHLD */
498 /* We could have received the SIGCHLD signal for the subshell
499 * before installing the init_sigchld */
500 pid
= waitpid (subshell_pid
, &status
, WUNTRACED
| WNOHANG
);
501 if (pid
== subshell_pid
){
502 use_subshell
= FALSE
;
509 /* {{{ Set up `precmd' or equivalent for reading the subshell's CWD */
511 switch (subshell_type
)
513 char precmd
[BUF_SMALL
];
516 g_snprintf (precmd
, sizeof (precmd
), " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
517 subshell_pipe
[WRITE
]);
521 g_snprintf (precmd
, sizeof (precmd
), "precmd(){ pwd>&%d;kill -STOP $$ }\n",
522 subshell_pipe
[WRITE
]);
526 g_snprintf (precmd
, sizeof (precmd
),
527 "set echo_style=both;"
528 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
532 write (subshell_pty
, precmd
, strlen (precmd
));
536 /* {{{ Wait until the subshell has started up and processed the command */
538 subshell_state
= RUNNING_COMMAND
;
539 enable_interrupt_key ();
540 if (!feed_subshell (QUIETLY
, TRUE
)){
541 use_subshell
= FALSE
;
543 disable_interrupt_key ();
545 use_subshell
= FALSE
; /* Subshell died instantly, so don't use it */
552 static void init_raw_mode ()
554 static int initialized
= 0;
556 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
557 /* original settings. However, here we need to make this tty very raw, */
558 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
559 /* pty. So, instead of changing the code for execute(), pre_exec(), */
560 /* etc, we just set up the modes we need here, before each command. */
562 if (initialized
== 0) /* First time: initialise `raw_mode' */
564 tcgetattr (STDOUT_FILENO
, &raw_mode
);
565 raw_mode
.c_lflag
&= ~ICANON
; /* Disable line-editing chars, etc. */
566 raw_mode
.c_lflag
&= ~ISIG
; /* Disable intr, quit & suspend chars */
567 raw_mode
.c_lflag
&= ~ECHO
; /* Disable input echoing */
568 raw_mode
.c_iflag
&= ~IXON
; /* Pass ^S/^Q to subshell undisturbed */
569 raw_mode
.c_iflag
&= ~ICRNL
; /* Don't translate CRs into LFs */
570 raw_mode
.c_oflag
&= ~OPOST
; /* Don't postprocess output */
571 raw_mode
.c_cc
[VTIME
] = 0; /* IE: wait forever, and return as */
572 raw_mode
.c_cc
[VMIN
] = 1; /* soon as a character is available */
577 /* {{{ invoke_subshell */
579 int invoke_subshell (const char *command
, int how
, char **new_dir
)
581 /* {{{ Make the MC terminal transparent */
583 tcsetattr (STDOUT_FILENO
, TCSANOW
, &raw_mode
);
587 /* Make the subshell change to MC's working directory */
589 do_subshell_chdir (cpanel
->cwd
, TRUE
, 1);
591 if (command
== NULL
) /* The user has done "C-o" from MC */
593 if (subshell_state
== INACTIVE
)
595 subshell_state
= ACTIVE
;
596 /* FIXME: possibly take out this hack; the user can
597 re-play it by hitting C-hyphen a few times! */
598 write (subshell_pty
, " \b", 2); /* Hack to make prompt reappear */
601 else /* MC has passed us a user command */
604 write (subshell_pty
, " ", 1);
605 /* FIXME: if command is long (>8KB ?) we go comma */
606 write (subshell_pty
, command
, strlen (command
));
607 write (subshell_pty
, "\n", 1);
608 subshell_state
= RUNNING_COMMAND
;
609 subshell_ready
= FALSE
;
612 feed_subshell (how
, FALSE
);
614 if (new_dir
&& subshell_alive
&& strcmp (subshell_cwd
, cpanel
->cwd
))
615 *new_dir
= subshell_cwd
; /* Make MC change to the subshell's CWD */
617 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
618 while (!subshell_alive
&& !quit
&& use_subshell
)
627 /* {{{ read_subshell_prompt */
629 int read_subshell_prompt (int how
)
631 /* {{{ Local variables */
633 int clear_now
= FALSE
;
634 static int prompt_size
= INITIAL_PROMPT_SIZE
;
635 int bytes
= 0, i
, rc
= 0;
636 struct timeval timeleft
= {0, 0};
640 FD_SET (subshell_pty
, &tmp
);
644 if (subshell_prompt
== NULL
) /* First time through */
646 subshell_prompt
= (char *) g_malloc (prompt_size
);
647 *subshell_prompt
= '\0';
651 while (subshell_alive
&&
652 (rc
= select (FD_SETSIZE
, &tmp
, NULL
, NULL
, &timeleft
)))
654 /* {{{ Check for `select' errors */
660 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
661 perror ("\n"__FILE__
": select (FD_SETSIZE, &tmp...)");
668 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
670 write (STDOUT_FILENO
, pty_buffer
, bytes
);
672 /* {{{ Extract the prompt from the shell output */
674 for (i
=0; i
<bytes
; ++i
)
675 if (pty_buffer
[i
] == '\n' || pty_buffer
[i
] == '\r'){
683 subshell_prompt
[prompt_pos
++] = pty_buffer
[i
];
684 if (prompt_pos
== prompt_size
)
685 subshell_prompt
= (char *) g_realloc (subshell_prompt
,
689 /* Sometimes we get an empty new line and then nothing,
690 * we better just keep the old prompt instead. */
692 subshell_prompt
[prompt_pos
] = '\0';
696 if (rc
== 0 && bytes
== 0)
702 /* {{{ resize_subshell */
704 void resize_subshell (void)
706 #if defined TIOCSWINSZ && !defined SCO_FLAVOR
707 struct winsize tty_size
;
709 tty_size
.ws_row
= LINES
;
710 tty_size
.ws_col
= COLS
;
711 tty_size
.ws_xpixel
= tty_size
.ws_ypixel
= 0;
713 if (ioctl (subshell_pty
, TIOCSWINSZ
, &tty_size
))
714 perror (__FILE__
": couldn't set pty size");
719 /* {{{ exit_subshell */
721 int exit_subshell (void)
725 if (subshell_state
!= INACTIVE
&& subshell_alive
)
726 quit
= !query_dialog (_(" Warning "), _(" The shell is still active. Quit anyway? "),
727 0, 2, _("&Yes"), _("&No"));
729 #if AIX_TCSH_CODE_BELOW_IS_IT_FIXED
733 if (subshell_type
== TCSH
)
734 g_snprintf (pty_buffer
, pty_buffer_size
, " echo -n Jobs:>/tmp/mc.pipe.%d;jobs>/tmp/"
735 "mc.pipe.%d;kill -STOP $$\n", getpid (), getpid ());
737 g_snprintf (pty_buffer
, pty_buffer_size
, " echo -n Jobs:>&%d;jobs>&%d;kill -STOP $$\n",
738 subshell_pipe
[WRITE
], subshell_pipe
[WRITE
]);
739 write (subshell_pty
, pty_buffer
, strlen (pty_buffer
));
741 #ifndef HAVE_GRANTPT /* FIXME */
742 if (subshell_type
== ZSH
)
743 /* Here we have to drain the shell output, because zsh does a */
744 /* tcsetattr(SHTTY, TCSADRAIN...) which will block if we don't */
745 read (subshell_pty
, pty_buffer
, pty_buffer_size
);
748 /* TCSH + AIX hang here, fix this before removing the ifdef above */
749 if (read (subshell_pipe
[READ
], pty_buffer
, pty_buffer_size
) == 5)
752 quit
= !query_dialog (_(" Warning "), _(" There are stopped jobs.")
753 _(" Quit anyway? "), 0, 2, _("&Yes"), _("&No"));
756 subshell_state
= RUNNING_COMMAND
;
757 feed_subshell (QUIETLY
, FALSE
); /* Drain the shell output (again) */
761 if (quit
&& subshell_type
== TCSH
)
763 /* We abuse of pty_buffer here, but it doesn't matter at this stage */
764 g_snprintf (pty_buffer
, pty_buffer_size
, "/tmp/mc.pipe.%d", getpid ());
765 if (unlink (pty_buffer
) == -1)
766 perror (__FILE__
": couldn't remove named pipe /tmp/mc.pipe.NNN");
775 * Carefully quote directory name to allow entering any directory safely,
776 * no matter what weird characters it may contain in its name.
777 * NOTE: Treat directory name an untrusted data, don't allow it to cause
778 * executing any commands in the shell. Escape all control characters.
779 * Use following technique:
781 * for bash - echo with `-e', 3-digit octal numbers:
782 * cd "`echo -e '\ooo...\ooo'`"
784 * for zsh and tcsh - echo without `-e', 4-digit octal numbers:
785 * cd "`echo '\oooo...\oooo'`"
788 subshell_name_quote (const char *s
)
791 const char bash_start
[] = "\"`echo -e '";
792 const char nonbash_start
[] = "\"`echo '";
793 const char common_end
[] = "'`\"";
796 * Factor 5 because we need \, 0 and 3 other digits per character
797 * in the worst case (tcsh and zsh).
799 d
= ret
= g_malloc (5 * strlen (s
) + 16);
801 /* Prevent interpreting leading `-' as a switch for `cd' */
808 * Print every character in octal format with the leading backslash.
809 * tcsh and zsh require leading 0, bash doesn't like 4-digit octals
810 * and requires `-e' for echo.
812 if (subshell_type
== BASH
) {
813 memcpy (d
, bash_start
, sizeof (bash_start
) - 1);
814 d
+= sizeof (bash_start
) - 1;
816 sprintf(d
, "\\%03o", (unsigned char) *s
);
820 memcpy (d
, nonbash_start
, sizeof (nonbash_start
) - 1);
821 d
+= sizeof (nonbash_start
) - 1;
823 sprintf(d
, "\\0%03o", (unsigned char) *s
);
828 memcpy (d
, common_end
, sizeof (common_end
));
835 /* {{{ do_subshell_chdir */
836 /* If it actually changed the directory it returns true */
837 void do_subshell_chdir (const char *directory
, int do_update
, int reset_prompt
)
839 if (!(subshell_state
== INACTIVE
&& strcmp (subshell_cwd
, cpanel
->cwd
))){
840 /* We have to repaint the subshell prompt if we read it from
841 * the main program. Please note that in the code after this
842 * if, the cd command that is sent will make the subshell
843 * repaint the prompt, so we don't have to paint it. */
849 /* The initial space keeps this out of the command history (in bash
850 because we set "HISTCONTROL=ignorespace") */
851 write (subshell_pty
, " cd ", 4);
854 temp
= subshell_name_quote (directory
);
855 write (subshell_pty
, temp
, strlen (temp
));
858 write (subshell_pty
, "/", 1);
860 write (subshell_pty
, "\n", 1);
862 subshell_state
= RUNNING_COMMAND
;
863 feed_subshell (QUIETLY
, FALSE
);
865 if (subshell_alive
&& strcmp (subshell_cwd
, cpanel
->cwd
) && strcmp (cpanel
->cwd
, "."))
866 fprintf (stderr
, _("Warning: Couldn't change to %s.\n"), cpanel
->cwd
);
870 update_prompt
= FALSE
;
871 /* Make sure that MC never stores the CWD in a silly format */
872 /* like /usr////lib/../bin, or the strcmp() above will fail */
876 /* {{{ subshell_get_console_attributes */
878 void subshell_get_console_attributes (void)
880 /* {{{ Get our current terminal modes */
882 if (tcgetattr (STDOUT_FILENO
, &shell_mode
))
884 perror (__FILE__
": couldn't get terminal settings");
885 use_subshell
= FALSE
;
893 /* {{{ sigchld_handler */
895 /* Figure out whether the subshell has stopped, exited or been killed */
896 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
898 void sigchld_handler (int sig
)
903 pid
= waitpid (subshell_pid
, &status
, WUNTRACED
| WNOHANG
);
905 if (pid
== subshell_pid
) {
906 /* {{{ Figure out what has happened to the subshell */
909 if (WIFSTOPPED (status
))
911 if (WSTOPSIG (status
) == SIGTSTP
)
912 /* The user has suspended the subshell. Revive it */
913 kill (subshell_pid
, SIGCONT
);
915 /* The subshell has received a SIGSTOP signal */
916 subshell_stopped
= TRUE
;
918 else /* The subshell has either exited normally or been killed */
921 subshell_alive
= FALSE
;
922 if (WIFEXITED (status
) && WEXITSTATUS (status
) != FORK_FAILURE
)
923 quit
|= SUBSHELL_EXIT
; /* Exited normally */
929 #if defined(linux) || defined(__linux__)
930 pid
= waitpid (cons_saver_pid
, &status
, WUNTRACED
| WNOHANG
);
932 if (pid
== cons_saver_pid
) {
935 if (WIFSTOPPED (status
))
936 /* Someone has stopped cons.saver - restart it */
941 /* cons.saver has died - disable confole saving */
942 handle_console (CONSOLE_DONE
);
947 #endif /* linux || __linux__ */
948 /* If we get here, some other child exited; ignore it */
949 # ifdef __EMX__ /* Need to report */
956 /* {{{ feed_subshell */
958 /* Feed the subshell our keyboard input until it says it's finished */
960 static int feed_subshell (int how
, int fail_on_error
)
962 /* {{{ Local variables */
963 fd_set read_set
; /* For `select' */
964 int bytes
; /* For the return value from `read' */
965 int i
; /* Loop counter */
967 struct timeval wtime
; /* Maximum time we wait for the subshell */
968 struct timeval
*wptr
;
971 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
974 wptr
= fail_on_error
? &wtime
: NULL
;
980 /* {{{ Prepare the file-descriptor set and call `select' */
983 FD_SET (subshell_pty
, &read_set
);
984 FD_SET (subshell_pipe
[READ
], &read_set
);
986 FD_SET (STDIN_FILENO
, &read_set
);
988 if (select (FD_SETSIZE
, &read_set
, NULL
, NULL
, wptr
) == -1){
990 /* Despite using SA_RESTART, we still have to check for this */
992 continue; /* try all over again */
993 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
994 perror ("\n"__FILE__
": select (FD_SETSIZE, &read_set...)");
999 if (FD_ISSET (subshell_pty
, &read_set
))
1000 /* {{{ Read from the subshell, write to stdout */
1002 /* This loop improves performance by reducing context switches
1003 by a factor of 20 or so... unfortunately, it also hangs MC
1004 randomly, because of an apparent Linux bug. Investigate. */
1005 /* for (i=0; i<5; ++i) * FIXME -- experimental */
1007 bytes
= read (subshell_pty
, pty_buffer
, pty_buffer_size
);
1008 /* Patch from viro@math.psu.edu
1009 * add by MichaelBramer (Debian MC-Maintainer */
1010 if (bytes
== -1 && errno
== EIO
&& !subshell_alive
)
1015 /* end from the patch */
1017 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1018 perror ("\n"__FILE__
": read (subshell_pty...)");
1023 write (STDOUT_FILENO
, pty_buffer
, bytes
);
1028 else if (FD_ISSET (subshell_pipe
[READ
], &read_set
))
1029 /* {{{ Read the subshell's CWD and capture its prompt */
1032 bytes
= read (subshell_pipe
[READ
], subshell_cwd
, MC_MAXPATHLEN
+1);
1035 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1036 perror ("\n"__FILE__
": read (subshell_pipe[READ]...)");
1040 subshell_cwd
[bytes
-1] = 0; /* Squash the final '\n' */
1044 subshell_ready
= TRUE
;
1045 if (subshell_state
== RUNNING_COMMAND
)
1047 subshell_state
= INACTIVE
;
1054 else if (FD_ISSET (STDIN_FILENO
, &read_set
))
1055 /* {{{ Read from stdin, write to the subshell */
1058 bytes
= read (STDIN_FILENO
, pty_buffer
, pty_buffer_size
);
1061 tcsetattr (STDOUT_FILENO
, TCSANOW
, &shell_mode
);
1062 perror ("\n"__FILE__
": read (STDIN_FILENO, pty_buffer...)");
1066 for (i
=0; i
<bytes
; ++i
)
1067 if (pty_buffer
[i
] == subshell_switch_key
)
1069 write (subshell_pty
, pty_buffer
, i
);
1071 subshell_state
= INACTIVE
;
1075 write (subshell_pty
, pty_buffer
, bytes
);
1076 subshell_ready
= FALSE
;
1086 /* {{{ synchronize */
1088 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1089 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1091 static void synchronize (void)
1093 sigset_t sigchld_mask
, old_mask
;
1095 sigemptyset (&sigchld_mask
);
1096 sigaddset (&sigchld_mask
, SIGCHLD
);
1097 sigprocmask (SIG_BLOCK
, &sigchld_mask
, &old_mask
);
1099 /* Wait until the subshell has stopped */
1100 while (subshell_alive
&& !subshell_stopped
)
1101 sigsuspend (&old_mask
);
1102 subshell_stopped
= FALSE
;
1104 kill (subshell_pid
, SIGCONT
);
1107 sigprocmask (SIG_SETMASK
, &old_mask
, NULL
);
1108 /* We can't do any better without modifying the shell(s) */
1112 /* {{{ pty opening functions */
1116 /* {{{ SCO version of pty_open_master */
1118 static int pty_open_master (char *pty_name
)
1124 strcpy (pty_name
, "/dev/ptyp");
1128 g_snprintf(ptr
, 9, "%d",num
); /* surpriiise ... SCO lacks itoa() */
1129 /* Try to open master */
1130 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1131 if (errno
== ENOENT
) /* Different from EIO */
1132 return -1; /* Out of pty devices */
1134 continue; /* Try next pty device */
1136 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1137 if (access (pty_name
, 6)){
1144 return -1; /* Ran out of pty devices */
1148 /* {{{ SCO version of pty_open_slave */
1150 static int pty_open_slave (const char *pty_name
)
1153 struct group
*group_info
= getgrnam ("terminal");
1155 if (group_info
!= NULL
)
1157 /* The following two calls will only succeed if we are root */
1158 /* [Commented out while permissions problem is investigated] */
1159 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1160 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1162 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1163 perror ("open (pty_name, O_RDWR)");
1169 #elif HAVE_GRANTPT /* !HAVE_SCO */
1171 /* {{{ System V version of pty_open_master */
1173 static int pty_open_master (char *pty_name
)
1180 /* getpt () is a GNU extension (glibc 2.1.x) */
1181 pty_master
= getpt ();
1183 strcpy (pty_name
, "/dev/ptmx");
1184 pty_master
= open (pty_name
, O_RDWR
);
1186 if (pty_master
== -1)
1189 if (grantpt (pty_master
) == -1 /* Grant access to slave */
1190 || unlockpt (pty_master
) == -1 /* Clear slave's lock flag */
1191 || !(slave_name
= ptsname (pty_master
))) /* Get slave's name */
1196 strcpy (pty_name
, slave_name
);
1201 /* {{{ System V version of pty_open_slave */
1203 static int pty_open_slave (const char *pty_name
)
1205 int pty_slave
= open (pty_name
, O_RDWR
);
1207 if (pty_slave
== -1)
1209 perror ("open (pty_name, O_RDWR)");
1213 #if !defined(__osf__) && !defined(linux) && !defined(__linux__)
1214 #if defined (I_FIND) && defined (I_PUSH)
1215 if (!ioctl (pty_slave
, I_FIND
, "ptem"))
1216 if (ioctl (pty_slave
, I_PUSH
, "ptem") == -1)
1218 perror ("ioctl (pty_slave, I_PUSH, \"ptem\")");
1223 if (!ioctl (pty_slave
, I_FIND
, "ldterm"))
1224 if (ioctl (pty_slave
, I_PUSH
, "ldterm") == -1)
1226 perror ("ioctl (pty_slave, I_PUSH, \"ldterm\")");
1231 #if !defined(sgi) && !defined(__sgi)
1232 if (!ioctl (pty_slave
, I_FIND
, "ttcompat"))
1233 if (ioctl (pty_slave
, I_PUSH
, "ttcompat") == -1)
1235 perror ("ioctl (pty_slave, I_PUSH, \"ttcompat\")");
1239 #endif /* sgi || __sgi */
1240 #endif /* I_FIND && I_PUSH */
1241 #endif /* __osf__ || linux || __linux__ */
1248 #else /* !HAVE_SCO && !HAVE_GRANTPT */
1250 /* {{{ BSD version of pty_open_master */
1252 static int pty_open_master (char *pty_name
)
1257 strcpy (pty_name
, "/dev/ptyXX");
1258 for (ptr1
= "pqrstuvwxyzPQRST"; *ptr1
; ++ptr1
)
1260 pty_name
[8] = *ptr1
;
1261 for (ptr2
= "0123456789abcdef"; *ptr2
; ++ptr2
)
1263 pty_name
[9] = *ptr2
;
1265 /* Try to open master */
1266 if ((pty_master
= open (pty_name
, O_RDWR
)) == -1) {
1267 if (errno
== ENOENT
) /* Different from EIO */
1268 return -1; /* Out of pty devices */
1270 continue; /* Try next pty device */
1272 pty_name
[5] = 't'; /* Change "pty" to "tty" */
1273 if (access (pty_name
, 6)){
1281 return -1; /* Ran out of pty devices */
1285 /* {{{ BSD version of pty_open_slave */
1287 static int pty_open_slave (const char *pty_name
)
1290 struct group
*group_info
= getgrnam ("tty");
1292 if (group_info
!= NULL
)
1294 /* The following two calls will only succeed if we are root */
1295 /* [Commented out while permissions problem is investigated] */
1296 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1297 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1299 if ((pty_slave
= open (pty_name
, O_RDWR
)) == -1)
1300 perror ("open (pty_name, O_RDWR)");
1306 #endif /* !HAVE_SCO && !HAVE_GRANTPT */
1310 #endif /* HAVE_SUBSHELL_SUPPORT */
1312 /* {{{ Emacs local variables */
1315 Cause emacs to enter folding mode for this file: