Remove references to the archaic "linux" preprocessor definition.
[midnight-commander.git] / src / subshell.c
blob498aa411bad47225770051526b539bde09ca8c0c
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.
20 /* }}} */
22 #include <config.h>
23 #ifdef HAVE_SUBSHELL_SUPPORT
25 /* {{{ Declarations */
27 #ifndef _GNU_SOURCE
28 # define _GNU_SOURCE 1
29 #endif
31 #include <stdio.h>
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) */
38 #endif
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 */
42 #include <ctype.h> /* isalnum() */
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h> /* For pipe, fork, setsid, access etc */
46 #endif
48 #ifdef HAVE_STROPTS_H
49 # include <stropts.h> /* For I_PUSH */
50 #endif /* HAVE_STROPTS_H */
52 #include "global.h"
53 #include "tty.h" /* LINES */
54 #include "panel.h" /* cpanel */
55 #include "wtools.h" /* query_dialog() */
56 #include "main.h" /* update_prompt() */
57 #include "cons.saver.h" /* handle_console() */
58 #include "key.h" /* XCTRL */
59 #include "subshell.h"
61 #ifndef WEXITSTATUS
62 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
63 #endif
65 #ifndef WIFEXITED
66 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
67 #endif
69 /* tcsh closes all non-standard file descriptors, so we have to use a pipe */
70 static char tcsh_fifo[128];
72 /* Local functions */
73 static void init_raw_mode (void);
74 static int feed_subshell (int how, int fail_on_error);
75 static void synchronize (void);
76 static int pty_open_master (char *pty_name);
77 static int pty_open_slave (const char *pty_name);
78 static int resize_tty (int fd);
80 /* }}} */
81 /* {{{ Definitions */
83 #ifndef STDIN_FILENO
84 # define STDIN_FILENO 0
85 #endif
87 #ifndef STDOUT_FILENO
88 # define STDOUT_FILENO 1
89 #endif
91 #ifndef STDERR_FILENO
92 # define STDERR_FILENO 2
93 #endif
95 /* If using a subshell for evaluating commands this is true */
96 int use_subshell =
97 #ifdef SUBSHELL_OPTIONAL
98 FALSE;
99 #else
100 TRUE;
101 #endif
103 /* File descriptor of the pseudoterminal used by the subshell */
104 int subshell_pty = 0;
106 /* The key for switching back to MC from the subshell */
107 static const char subshell_switch_key = XCTRL('o') & 255;
109 /* State of the subshell:
110 * INACTIVE: the default state; awaiting a command
111 * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
112 * RUNNING_COMMAND: return to MC when the current command finishes */
113 enum subshell_state_enum subshell_state;
115 /* Holds the latest prompt captured from the subshell */
116 char *subshell_prompt = NULL;
118 /* Initial length of the buffer for the subshell's prompt */
119 #define INITIAL_PROMPT_SIZE 10
121 /* Used by the child process to indicate failure to start the subshell */
122 #define FORK_FAILURE 69 /* Arbitrary */
124 /* Initial length of the buffer for all I/O with the subshell */
125 #define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
127 /* For pipes */
128 enum {READ=0, WRITE=1};
131 /* Local variables */
133 static char *pty_buffer; /* For reading/writing on the subshell's pty */
134 static int pty_buffer_size; /* The buffer grows as needed */
135 static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
136 static pid_t subshell_pid = 1; /* The subshell's process ID */
137 static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
139 /* Subshell type (gleaned from the SHELL environment variable, if available) */
140 static enum {BASH, TCSH, ZSH} subshell_type;
142 /* Flag to indicate whether the subshell is ready for next command */
143 static int subshell_ready;
145 /* The following two flags can be changed by the SIGCHLD handler. This is */
146 /* OK, because the `int' type is updated atomically on all known machines */
147 static volatile int subshell_alive, subshell_stopped;
149 /* We store the terminal's initial mode here so that we can configure
150 the pty similarly, and also so we can restore the real terminal to
151 sanity if we have to exit abruptly */
152 static struct termios shell_mode;
154 /* This is a transparent mode for the terminal where MC is running on */
155 /* It is used when the shell is active, so that the control signals */
156 /* are delivered to the shell pty */
157 static struct termios raw_mode;
159 /* This counter indicates how many characters of prompt we have read */
160 /* FIXME: try to figure out why this had to become global */
161 static int prompt_pos;
163 /* }}} */
165 #ifdef HAVE_GRANTPT
166 # define SYNC_PTY_SIDES
167 #else
168 # define SYNC_PTY_SIDES
169 #endif
171 #undef SYNC_PTY_SIDES
173 #ifdef SYNC_PTY_SIDES
174 /* Handler for SIGUSR1 (used below), does nothing but accept the signal */
175 static void sigusr1_handler (int sig)
178 #endif
181 * Prepare child process to running the shell and run it.
183 * Modifies the global variables (in the child process only):
184 * shell_mode
186 * Returns: never.
188 static void init_subshell_child (const char *pty_name)
190 int pty_slave;
191 char *init_file = NULL;
193 setsid (); /* Get a fresh terminal session */
195 /* {{{ Open the slave side of the pty: again */
196 pty_slave = pty_open_slave (pty_name);
198 /* This must be done before closing the master side of the pty, */
199 /* or it will fail on certain idiotic systems, such as Solaris. */
201 /* Close master side of pty. This is important; apart from */
202 /* freeing up the descriptor for use in the subshell, it also */
203 /* means that when MC exits, the subshell will get a SIGHUP and */
204 /* exit too, because there will be no more descriptors pointing */
205 /* at the master side of the pty and so it will disappear. */
207 close (subshell_pty);
209 #ifdef SYNC_PTY_SIDES
210 /* Give our parent process (MC) the go-ahead */
211 kill (getppid (), SIGUSR1);
212 #endif
214 /* }}} */
215 /* {{{ Make sure that it has become our controlling terminal */
217 /* Redundant on Linux and probably most systems, but just in case: */
219 #ifdef TIOCSCTTY
220 ioctl (pty_slave, TIOCSCTTY, 0);
221 #endif
223 /* }}} */
224 /* {{{ Configure its terminal modes and window size */
226 /* Set up the pty with the same termios flags as our own tty, plus */
227 /* TOSTOP, which keeps background processes from writing to the pty */
229 shell_mode.c_lflag |= TOSTOP; /* So background writers get SIGTTOU */
230 if (tcsetattr (pty_slave, TCSANOW, &shell_mode))
232 perror (__FILE__": couldn't set pty terminal modes");
233 _exit (FORK_FAILURE);
236 /* Set the pty's size (80x25 by default on Linux) according to the */
237 /* size of the real terminal as calculated by ncurses, if possible */
238 resize_tty (pty_slave);
240 /* }}} */
241 /* {{{ Set up the subshell's environment and init file name */
243 /* It simplifies things to change to our home directory here, */
244 /* and the user's startup file may do a `cd' command anyway */
245 chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
247 switch (subshell_type)
249 case BASH:
250 init_file = ".mc/bashrc";
251 if (access (init_file, R_OK) == -1)
252 init_file = ".bashrc";
254 /* Make MC's special commands not show up in bash's history */
255 putenv ("HISTCONTROL=ignorespace");
257 /* Allow alternative readline settings for MC */
258 if (access (".mc/inputrc", R_OK) == 0)
259 putenv ("INPUTRC=.mc/inputrc");
261 break;
263 case TCSH:
264 init_file = ".mc/tcshrc";
265 if (access (init_file, R_OK) == -1)
266 init_file += 3;
267 break;
269 case ZSH:
270 break;
272 default:
273 fprintf (stderr, __FILE__": unimplemented subshell type %d\n",
274 subshell_type);
275 _exit (FORK_FAILURE);
278 /* }}} */
279 /* {{{ Attach all our standard file descriptors to the pty */
281 /* This is done just before the fork, because stderr must still */
282 /* be connected to the real tty during the above error messages; */
283 /* otherwise the user will never see them. */
285 dup2 (pty_slave, STDIN_FILENO);
286 dup2 (pty_slave, STDOUT_FILENO);
287 dup2 (pty_slave, STDERR_FILENO);
289 /* }}} */
290 /* {{{ Execute the subshell at last */
292 close (subshell_pipe[READ]);
293 close (pty_slave); /* These may be FD_CLOEXEC, but just in case... */
295 switch (subshell_type)
297 case BASH:
298 execl (shell, "bash", "-rcfile", init_file, NULL);
299 break;
301 case TCSH:
302 execl (shell, "tcsh", NULL); /* What's the -rcfile equivalent? */
303 break;
305 case ZSH:
306 /* change from "+Z" to "-Z" by Michael Bramer
307 * (Debian-mc-maintainer) <grisu@debian.org> from a patch from
308 * Radovan Garabik <garabik@center.fmph.uniba.sk>
310 execl (shell, "zsh", "-Z", NULL);
312 break;
315 /* If we get this far, everything failed miserably */
316 _exit (FORK_FAILURE);
318 /* }}} */
321 /* {{{ init_subshell */
324 * Fork the subshell, and set up many, many things.
326 * Possibly modifies the global variables:
327 * subshell_type, subshell_alive, subshell_stopped, subshell_pid
328 * use_subshell - Is set to FALSE if we can't run the subshell
329 * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
332 void init_subshell (void)
334 /* {{{ Local variables */
336 /* This must be remembered across calls to init_subshell() */
337 static char pty_name[BUF_SMALL];
338 int pty_slave = -1;
341 #ifdef SYNC_PTY_SIDES
342 /* Used to wait for a SIGUSR1 signal from the subprocess */
343 sigset_t sigusr1_mask, old_mask;
344 #endif
346 /* }}} */
348 /* Take the current (hopefully pristine) tty mode and make */
349 /* a raw mode based on it now, before we do anything else with it */
350 init_raw_mode ();
352 if (subshell_pty == 0) /* First time through */
354 /* {{{ Find out what type of shell we have */
356 if (strstr (shell, "/zsh"))
357 subshell_type = ZSH;
358 else if (strstr (shell, "/tcsh"))
359 subshell_type = TCSH;
360 else if (strstr (shell, "/bash") || getenv ("BASH"))
361 subshell_type = BASH;
362 else
364 use_subshell = FALSE;
365 return;
368 /* }}} */
369 /* {{{ Open a pty for talking to the subshell */
371 /* FIXME: We may need to open a fresh pty each time on SVR4 */
373 subshell_pty = pty_open_master (pty_name);
374 if (subshell_pty == -1)
376 fputs (__FILE__": couldn't open master side of pty\n", stderr);
377 perror ("pty_open_master");
378 use_subshell = FALSE;
379 return;
381 pty_slave = pty_open_slave (pty_name);
382 if (pty_slave == -1)
384 fprintf (stderr, "couldn't open slave side of pty (%s)\n\r",
385 pty_name);
386 use_subshell = FALSE;
387 return;
391 /* }}} */
392 /* {{{ Initialise the pty's I/O buffer */
394 pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
395 pty_buffer = (char *) g_malloc (pty_buffer_size);
397 /* }}} */
398 /* {{{ Create a pipe for receiving the subshell's CWD */
400 if (subshell_type == TCSH)
402 g_snprintf (tcsh_fifo, sizeof (tcsh_fifo), "%s/mc.pipe.%d",
403 mc_tmpdir(), getpid ());
404 if (mkfifo (tcsh_fifo, 0600) == -1)
406 perror (__FILE__": mkfifo");
407 use_subshell = FALSE;
408 return;
411 /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
413 if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1 ||
414 (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
416 fprintf (stderr, _("Cannot open named pipe %s\n"), tcsh_fifo);
417 perror (__FILE__": open");
418 use_subshell = FALSE;
419 return;
422 else /* subshell_type is BASH or ZSH */
423 if (pipe (subshell_pipe))
425 perror (__FILE__": couldn't create pipe");
426 use_subshell = FALSE;
427 return;
430 /* }}} */
433 /* {{{ Define a handler for the sigusr1 signal */
435 #ifdef SYNC_PTY_SIDES
436 sigemptyset (&sigusr1_mask);
437 sigaddset (&sigusr1_mask, SIGUSR1);
438 sigprocmask (SIG_BLOCK, &sigusr1_mask, &old_mask);
439 signal (SIGUSR1, sigusr1_handler);
440 #endif
442 /* }}} */
443 /* {{{ Fork the subshell */
445 subshell_alive = TRUE;
446 subshell_stopped = FALSE;
447 subshell_pid = fork ();
449 if (subshell_pid == -1)
451 perror (__FILE__": couldn't spawn the subshell process");
452 /* We exit here because, if the process table is full, the */
453 /* other method of running user commands won't work either */
454 exit (1);
457 /* }}} */
459 if (subshell_pid == 0) /* We are in the child process */
461 init_subshell_child (pty_name);
464 /* pty_slave is only opened when called the first time */
465 if (pty_slave != -1) {
466 close(pty_slave);
469 #ifdef SYNC_PTY_SIDES
470 sigsuspend (&old_mask);
471 signal (SIGUSR1, SIG_DFL);
472 sigprocmask (SIG_SETMASK, &old_mask, NULL);
473 /* ...before installing our handler for SIGCHLD. */
474 #endif
476 #if 0
477 /* {{{ Install our handler for SIGCHLD */
479 init_sigchld ();
481 /* We could have received the SIGCHLD signal for the subshell
482 * before installing the init_sigchld */
483 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
484 if (pid == subshell_pid){
485 use_subshell = FALSE;
486 return;
489 /* }}} */
490 #endif
492 /* {{{ Set up `precmd' or equivalent for reading the subshell's CWD */
494 switch (subshell_type)
496 char precmd[BUF_SMALL];
498 case BASH:
499 g_snprintf (precmd, sizeof (precmd), " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
500 subshell_pipe[WRITE]);
501 goto write_it;
503 case ZSH:
504 g_snprintf (precmd, sizeof (precmd), "precmd(){ pwd>&%d;kill -STOP $$ }\n",
505 subshell_pipe[WRITE]);
506 goto write_it;
508 case TCSH:
509 g_snprintf (precmd, sizeof (precmd),
510 "set echo_style=both;"
511 "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n",
512 tcsh_fifo);
514 write_it:
515 write (subshell_pty, precmd, strlen (precmd));
518 /* }}} */
519 /* {{{ Wait until the subshell has started up and processed the command */
521 subshell_state = RUNNING_COMMAND;
522 enable_interrupt_key ();
523 if (!feed_subshell (QUIETLY, TRUE)){
524 use_subshell = FALSE;
526 disable_interrupt_key ();
527 if (!subshell_alive)
528 use_subshell = FALSE; /* Subshell died instantly, so don't use it */
530 /* }}} */
533 /* }}} */
535 static void init_raw_mode ()
537 static int initialized = 0;
539 /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
540 /* original settings. However, here we need to make this tty very raw, */
541 /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
542 /* pty. So, instead of changing the code for execute(), pre_exec(), */
543 /* etc, we just set up the modes we need here, before each command. */
545 if (initialized == 0) /* First time: initialise `raw_mode' */
547 tcgetattr (STDOUT_FILENO, &raw_mode);
548 raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
549 raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
550 raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
551 raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
552 raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
553 raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
554 raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
555 raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
556 initialized = 1;
560 /* {{{ invoke_subshell */
562 int invoke_subshell (const char *command, int how, char **new_dir)
564 /* {{{ Make the MC terminal transparent */
566 tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
568 /* }}} */
570 /* Make the subshell change to MC's working directory */
571 if (new_dir)
572 do_subshell_chdir (cpanel->cwd, TRUE, 1);
574 if (command == NULL) /* The user has done "C-o" from MC */
576 if (subshell_state == INACTIVE)
578 subshell_state = ACTIVE;
579 /* FIXME: possibly take out this hack; the user can
580 re-play it by hitting C-hyphen a few times! */
581 write (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
584 else /* MC has passed us a user command */
586 if (how == QUIETLY)
587 write (subshell_pty, " ", 1);
588 /* FIXME: if command is long (>8KB ?) we go comma */
589 write (subshell_pty, command, strlen (command));
590 write (subshell_pty, "\n", 1);
591 subshell_state = RUNNING_COMMAND;
592 subshell_ready = FALSE;
595 feed_subshell (how, FALSE);
597 if (new_dir && subshell_alive && strcmp (subshell_cwd, cpanel->cwd))
598 *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
600 /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
601 while (!subshell_alive && !quit && use_subshell)
602 init_subshell ();
604 prompt_pos = 0;
606 return quit;
609 /* }}} */
610 /* {{{ read_subshell_prompt */
612 int read_subshell_prompt (void)
614 /* {{{ Local variables */
616 static int prompt_size = INITIAL_PROMPT_SIZE;
617 int bytes = 0, i, rc = 0;
618 struct timeval timeleft = {0, 0};
620 fd_set tmp;
621 FD_ZERO (&tmp);
622 FD_SET (subshell_pty, &tmp);
624 /* }}} */
626 if (subshell_prompt == NULL) /* First time through */
628 subshell_prompt = (char *) g_malloc (prompt_size);
629 *subshell_prompt = '\0';
630 prompt_pos = 0;
633 while (subshell_alive &&
634 (rc = select (subshell_pty + 1, &tmp, NULL, NULL, &timeleft)))
636 /* {{{ Check for `select' errors */
638 if (rc == -1) {
639 if (errno == EINTR)
640 continue;
641 else {
642 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
643 perror ("\n"__FILE__": select (FD_SETSIZE, &tmp...)");
644 exit (1);
648 /* }}} */
650 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
652 /* {{{ Extract the prompt from the shell output */
654 for (i=0; i<bytes; ++i)
655 if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r'){
656 prompt_pos = 0;
657 } else {
658 if (!pty_buffer [i])
659 continue;
661 subshell_prompt[prompt_pos++] = pty_buffer[i];
662 if (prompt_pos == prompt_size)
663 subshell_prompt = (char *) g_realloc (subshell_prompt,
664 prompt_size *= 2);
667 subshell_prompt[prompt_pos] = '\0';
669 /* }}} */
671 if (rc == 0 && bytes == 0)
672 return FALSE;
673 return TRUE;
676 /* Resize given terminal using TIOCSWINSZ, return ioctl() result */
677 static int resize_tty (int fd)
679 #if defined TIOCSWINSZ && !defined SCO_FLAVOR
680 struct winsize tty_size;
682 tty_size.ws_row = LINES;
683 tty_size.ws_col = COLS;
684 tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
686 return ioctl (fd, TIOCSWINSZ, &tty_size);
687 #else
688 return 0;
689 #endif
692 /* Resize subshell_pty */
693 void resize_subshell (void)
695 resize_tty (subshell_pty);
698 int exit_subshell (void)
700 int quit = TRUE;
702 if (subshell_state != INACTIVE && subshell_alive)
703 quit = !query_dialog (_("Warning"), _(" The shell is still active. Quit anyway? "),
704 0, 2, _("&Yes"), _("&No"));
706 if (quit && subshell_type == TCSH)
708 if (unlink (tcsh_fifo) == -1)
709 perror (__FILE__": couldn't remove named pipe /tmp/mc.pipe.NNN");
712 g_free (subshell_prompt);
713 subshell_prompt = NULL;
715 return quit;
718 /* }}} */
721 * Carefully quote directory name to allow entering any directory safely,
722 * no matter what weird characters it may contain in its name.
723 * NOTE: Treat directory name an untrusted data, don't allow it to cause
724 * executing any commands in the shell. Escape all control characters.
725 * Use following technique:
727 * for bash - echo with `-e', 3-digit octal numbers:
728 * cd "`echo -e '\ooo...\ooo'`"
730 * for zsh - echo with `-e', 4-digit octal numbers:
731 * cd "`echo '\oooo...\oooo'`"
733 * for tcsh - echo without `-e', 4-digit octal numbers:
734 * cd "`echo '\oooo...\oooo'`"
736 static char *
737 subshell_name_quote (const char *s)
739 char *ret, *d;
740 const char echo_cmd[] = "\"`echo '";
741 const char echo_e_cmd[] = "\"`echo -e '";
742 const char common_end[] = "'`\"";
743 const char *cmd_start;
744 int len;
747 * Factor 5 because we need \, 0 and 3 other digits per character
748 * in the worst case (tcsh and zsh).
750 d = ret = g_malloc (5 * strlen (s) + 16);
751 if (!d)
752 return NULL;
754 /* Prevent interpreting leading `-' as a switch for `cd' */
755 if (*s == '-') {
756 *d++ = '.';
757 *d++ = '/';
760 /* echo in tcsh doesn't understand the "-e" option */
761 if (subshell_type == TCSH)
762 cmd_start = echo_cmd;
763 else
764 cmd_start = echo_e_cmd;
766 /* Copy the beginning of the command to the buffer */
767 len = strlen (cmd_start);
768 memcpy (d, cmd_start, len);
769 d += len;
772 * Print every character in octal format with the leading backslash.
773 * tcsh and zsh may require 4-digit octals, bash < 2.05b doesn't like them.
775 if (subshell_type == BASH) {
776 for (; *s; s++) {
777 /* Must quote numbers, so that they are not glued to octals */
778 if (isalpha ((unsigned char) *s)) {
779 sprintf (d, "%c", (unsigned char) *s);
780 d += 1;
781 } else {
782 sprintf (d, "\\%03o", (unsigned char) *s);
783 d += 4;
786 } else {
787 for (; *s; s++) {
788 if (isalnum ((unsigned char) *s)) {
789 sprintf (d, "%c", (unsigned char) *s);
790 d += 1;
791 } else {
792 sprintf (d, "\\0%03o", (unsigned char) *s);
793 d += 5;
798 memcpy (d, common_end, sizeof (common_end));
800 return ret;
805 /* {{{ do_subshell_chdir */
806 /* If it actually changed the directory it returns true */
807 void do_subshell_chdir (const char *directory, int do_update, int reset_prompt)
809 if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, cpanel->cwd))){
810 /* We have to repaint the subshell prompt if we read it from
811 * the main program. Please note that in the code after this
812 * if, the cd command that is sent will make the subshell
813 * repaint the prompt, so we don't have to paint it. */
814 if (do_update)
815 do_update_prompt ();
816 return;
819 /* The initial space keeps this out of the command history (in bash
820 because we set "HISTCONTROL=ignorespace") */
821 write (subshell_pty, " cd ", 4);
822 if (*directory) {
823 char *temp;
824 temp = subshell_name_quote (directory);
825 if (temp) {
826 write (subshell_pty, temp, strlen (temp));
827 g_free (temp);
828 } else {
829 /* Should not happen unless the directory name is so long
830 that we don't have memory to quote it. */
831 write (subshell_pty, ".", 1);
833 } else {
834 write (subshell_pty, "/", 1);
836 write (subshell_pty, "\n", 1);
838 subshell_state = RUNNING_COMMAND;
839 feed_subshell (QUIETLY, FALSE);
841 if (subshell_alive && strcmp (subshell_cwd, cpanel->cwd) && strcmp (cpanel->cwd, "."))
842 fprintf (stderr, _("Warning: Cannot change to %s.\n"), cpanel->cwd);
844 if (reset_prompt)
845 prompt_pos = 0;
846 update_prompt = FALSE;
847 /* Make sure that MC never stores the CWD in a silly format */
848 /* like /usr////lib/../bin, or the strcmp() above will fail */
851 /* }}} */
852 /* {{{ subshell_get_console_attributes */
854 void subshell_get_console_attributes (void)
856 /* {{{ Get our current terminal modes */
858 if (tcgetattr (STDOUT_FILENO, &shell_mode))
860 perror (__FILE__": couldn't get terminal settings");
861 use_subshell = FALSE;
862 return;
865 /* }}} */
868 /* }}} */
869 /* {{{ sigchld_handler */
871 /* Figure out whether the subshell has stopped, exited or been killed */
872 /* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
874 void
875 sigchld_handler (int sig)
877 int status;
878 pid_t pid;
880 pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
882 if (pid == subshell_pid) {
883 /* Figure out what has happened to the subshell */
885 if (WIFSTOPPED (status)) {
886 if (WSTOPSIG (status) == SIGSTOP) {
887 /* The subshell has received a SIGSTOP signal */
888 subshell_stopped = TRUE;
889 } else {
890 /* The user has suspended the subshell. Revive it */
891 kill (subshell_pid, SIGCONT);
893 } else {
894 /* The subshell has either exited normally or been killed */
895 subshell_alive = FALSE;
896 delete_select_channel (subshell_pty);
897 if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
898 quit |= SUBSHELL_EXIT; /* Exited normally */
901 #ifdef __linux__
902 pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
904 if (pid == cons_saver_pid) {
906 if (WIFSTOPPED (status))
907 /* Someone has stopped cons.saver - restart it */
908 kill (pid, SIGCONT);
909 else {
910 /* cons.saver has died - disable confole saving */
911 handle_console (CONSOLE_DONE);
912 console_flag = 0;
916 #endif /* __linux__ */
918 /* If we got here, some other child exited; ignore it */
919 #ifdef __EMX__ /* Need to report */
920 pid = wait (&status);
921 #endif
924 /* }}} */
926 /* {{{ feed_subshell */
928 /* Feed the subshell our keyboard input until it says it's finished */
930 static int feed_subshell (int how, int fail_on_error)
932 /* {{{ Local variables */
933 fd_set read_set; /* For `select' */
934 int maxfdp;
935 int bytes; /* For the return value from `read' */
936 int i; /* Loop counter */
938 struct timeval wtime; /* Maximum time we wait for the subshell */
939 struct timeval *wptr;
940 /* }}} */
942 /* we wait up to 10 seconds if fail_on_error, forever otherwise */
943 wtime.tv_sec = 10;
944 wtime.tv_usec = 0;
945 wptr = fail_on_error ? &wtime : NULL;
947 while (1) {
948 if (!subshell_alive)
949 return FALSE;
951 /* {{{ Prepare the file-descriptor set and call `select' */
953 FD_ZERO (&read_set);
954 FD_SET (subshell_pty, &read_set);
955 FD_SET (subshell_pipe[READ], &read_set);
956 maxfdp = max (subshell_pty, subshell_pipe[READ]);
957 if (how == VISIBLY) {
958 FD_SET (STDIN_FILENO, &read_set);
959 maxfdp = max (maxfdp, STDIN_FILENO);
962 if (select (maxfdp + 1, &read_set, NULL, NULL, wptr) == -1){
964 /* Despite using SA_RESTART, we still have to check for this */
965 if (errno == EINTR)
966 continue; /* try all over again */
967 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
968 perror ("\n"__FILE__": select (FD_SETSIZE, &read_set...)");
969 exit (1);
971 /* }}} */
973 if (FD_ISSET (subshell_pty, &read_set))
974 /* {{{ Read from the subshell, write to stdout */
976 /* This loop improves performance by reducing context switches
977 by a factor of 20 or so... unfortunately, it also hangs MC
978 randomly, because of an apparent Linux bug. Investigate. */
979 /* for (i=0; i<5; ++i) * FIXME -- experimental */
981 bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
983 /* The subshell has died */
984 if (bytes == -1 && errno == EIO && !subshell_alive)
985 return FALSE;
987 if (bytes <= 0)
989 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
990 perror ("\n"__FILE__": read (subshell_pty...)");
991 exit (1);
994 if (how == VISIBLY)
995 write (STDOUT_FILENO, pty_buffer, bytes);
998 /* }}} */
1000 else if (FD_ISSET (subshell_pipe[READ], &read_set))
1001 /* {{{ Read the subshell's CWD and capture its prompt */
1004 bytes = read (subshell_pipe[READ], subshell_cwd, MC_MAXPATHLEN+1);
1005 if (bytes <= 0)
1007 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1008 perror ("\n"__FILE__": read (subshell_pipe[READ]...)");
1009 exit (1);
1012 subshell_cwd[bytes-1] = 0; /* Squash the final '\n' */
1014 synchronize ();
1016 subshell_ready = TRUE;
1017 if (subshell_state == RUNNING_COMMAND)
1019 subshell_state = INACTIVE;
1020 return 1;
1024 /* }}} */
1026 else if (FD_ISSET (STDIN_FILENO, &read_set))
1027 /* {{{ Read from stdin, write to the subshell */
1030 bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
1031 if (bytes <= 0)
1033 tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
1034 perror ("\n"__FILE__": read (STDIN_FILENO, pty_buffer...)");
1035 exit (1);
1038 for (i=0; i<bytes; ++i)
1039 if (pty_buffer[i] == subshell_switch_key)
1041 write (subshell_pty, pty_buffer, i);
1042 if (subshell_ready)
1043 subshell_state = INACTIVE;
1044 return TRUE;
1047 write (subshell_pty, pty_buffer, bytes);
1048 subshell_ready = FALSE;
1049 } else {
1050 return FALSE;
1053 /* }}} */
1057 /* }}} */
1058 /* {{{ synchronize */
1060 /* Wait until the subshell dies or stops. If it stops, make it resume. */
1061 /* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
1063 static void synchronize (void)
1065 sigset_t sigchld_mask, old_mask;
1067 sigemptyset (&sigchld_mask);
1068 sigaddset (&sigchld_mask, SIGCHLD);
1069 sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
1072 * SIGCHLD should not be blocked, but we unblock it just in case.
1073 * This is known to be useful for cygwin 1.3.12 and older.
1075 sigdelset (&old_mask, SIGCHLD);
1077 /* Wait until the subshell has stopped */
1078 while (subshell_alive && !subshell_stopped)
1079 sigsuspend (&old_mask);
1081 /* Discard all remaining data from stdin to the subshell */
1082 tcflush (subshell_pty, TCOFLUSH);
1084 subshell_stopped = FALSE;
1085 kill (subshell_pid, SIGCONT);
1087 sigprocmask (SIG_SETMASK, &old_mask, NULL);
1088 /* We can't do any better without modifying the shell(s) */
1091 /* }}} */
1092 /* {{{ pty opening functions */
1094 #ifdef SCO_FLAVOR
1096 /* {{{ SCO version of pty_open_master */
1098 static int pty_open_master (char *pty_name)
1100 int pty_master;
1101 int num;
1102 char *ptr;
1104 strcpy (pty_name, "/dev/ptyp");
1105 ptr = pty_name+9;
1106 for (num=0;;num++)
1108 g_snprintf(ptr, 9, "%d",num); /* surpriiise ... SCO lacks itoa() */
1109 /* Try to open master */
1110 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1111 if (errno == ENOENT) /* Different from EIO */
1112 return -1; /* Out of pty devices */
1113 else
1114 continue; /* Try next pty device */
1116 pty_name [5] = 't'; /* Change "pty" to "tty" */
1117 if (access (pty_name, 6)){
1118 close (pty_master);
1119 pty_name [5] = 'p';
1120 continue;
1122 return pty_master;
1124 return -1; /* Ran out of pty devices */
1127 /* }}} */
1128 /* {{{ SCO version of pty_open_slave */
1130 static int pty_open_slave (const char *pty_name)
1132 int pty_slave;
1133 struct group *group_info = getgrnam ("terminal");
1135 if (group_info != NULL)
1137 /* The following two calls will only succeed if we are root */
1138 /* [Commented out while permissions problem is investigated] */
1139 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1140 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1142 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1143 perror ("open (pty_name, O_RDWR)");
1144 return pty_slave;
1147 /* }}} */
1149 #elif HAVE_GRANTPT /* !HAVE_SCO */
1151 /* {{{ System V version of pty_open_master */
1153 static int pty_open_master (char *pty_name)
1155 char *slave_name;
1156 int pty_master;
1159 #ifdef HAVE_GETPT
1160 /* getpt () is a GNU extension (glibc 2.1.x) */
1161 pty_master = getpt ();
1162 #elif IS_AIX
1163 strcpy (pty_name, "/dev/ptc");
1164 pty_master = open (pty_name, O_RDWR);
1165 #else
1166 strcpy (pty_name, "/dev/ptmx");
1167 pty_master = open (pty_name, O_RDWR);
1168 #endif
1169 if (pty_master == -1)
1170 return -1;
1172 if (grantpt (pty_master) == -1 /* Grant access to slave */
1173 || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
1174 || !(slave_name = ptsname (pty_master))) /* Get slave's name */
1176 close (pty_master);
1177 return -1;
1179 strcpy (pty_name, slave_name);
1180 return pty_master;
1183 /* }}} */
1184 /* {{{ System V version of pty_open_slave */
1186 static int pty_open_slave (const char *pty_name)
1188 int pty_slave = open (pty_name, O_RDWR);
1190 if (pty_slave == -1)
1192 perror ("open (pty_name, O_RDWR)");
1193 return -1;
1196 #if !defined(__osf__) && !defined(__linux__)
1197 #if defined (I_FIND) && defined (I_PUSH)
1198 if (!ioctl (pty_slave, I_FIND, "ptem"))
1199 if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
1201 fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ptem\") failed\n");
1202 close (pty_slave);
1203 return -1;
1206 if (!ioctl (pty_slave, I_FIND, "ldterm"))
1207 if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
1209 fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ldterm\") failed\n");
1210 close (pty_slave);
1211 return -1;
1214 #if !defined(sgi) && !defined(__sgi)
1215 if (!ioctl (pty_slave, I_FIND, "ttcompat"))
1216 if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
1218 fprintf (stderr, "ioctl (pty_slave, I_PUSH, \"ttcompat\") failed\n");
1219 close (pty_slave);
1220 return -1;
1222 #endif /* sgi || __sgi */
1223 #endif /* I_FIND && I_PUSH */
1224 #endif /* __osf__ || __linux__ */
1226 return pty_slave;
1229 /* }}} */
1231 #else /* !HAVE_SCO && !HAVE_GRANTPT */
1233 /* {{{ BSD version of pty_open_master */
1235 static int pty_open_master (char *pty_name)
1237 int pty_master;
1238 char *ptr1, *ptr2;
1240 strcpy (pty_name, "/dev/ptyXX");
1241 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
1243 pty_name [8] = *ptr1;
1244 for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
1246 pty_name [9] = *ptr2;
1248 /* Try to open master */
1249 if ((pty_master = open (pty_name, O_RDWR)) == -1) {
1250 if (errno == ENOENT) /* Different from EIO */
1251 return -1; /* Out of pty devices */
1252 else
1253 continue; /* Try next pty device */
1255 pty_name [5] = 't'; /* Change "pty" to "tty" */
1256 if (access (pty_name, 6)){
1257 close (pty_master);
1258 pty_name [5] = 'p';
1259 continue;
1261 return pty_master;
1264 return -1; /* Ran out of pty devices */
1267 /* }}} */
1268 /* {{{ BSD version of pty_open_slave */
1270 static int pty_open_slave (const char *pty_name)
1272 int pty_slave;
1273 struct group *group_info = getgrnam ("tty");
1275 if (group_info != NULL)
1277 /* The following two calls will only succeed if we are root */
1278 /* [Commented out while permissions problem is investigated] */
1279 /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
1280 /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
1282 if ((pty_slave = open (pty_name, O_RDWR)) == -1)
1283 perror ("open (pty_name, O_RDWR)");
1284 return pty_slave;
1287 /* }}} */
1289 #endif /* !HAVE_SCO && !HAVE_GRANTPT */
1291 /* }}} */
1293 #endif /* HAVE_SUBSHELL_SUPPORT */
1295 /* {{{ Emacs local variables */
1298 Cause emacs to enter folding mode for this file:
1299 Local variables:
1300 end:
1303 /* }}} */