Home | History | Annotate | Line # | Download | only in ex
ex_shell.c revision 1.2
      1  1.2  christos /*	$NetBSD: ex_shell.c,v 1.2 2013/11/22 15:52:05 christos Exp $ */
      2  1.1  christos /*-
      3  1.1  christos  * Copyright (c) 1992, 1993, 1994
      4  1.1  christos  *	The Regents of the University of California.  All rights reserved.
      5  1.1  christos  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  1.1  christos  *	Keith Bostic.  All rights reserved.
      7  1.1  christos  *
      8  1.1  christos  * See the LICENSE file for redistribution information.
      9  1.1  christos  */
     10  1.1  christos 
     11  1.1  christos #include "config.h"
     12  1.1  christos 
     13  1.1  christos #ifndef lint
     14  1.1  christos static const char sccsid[] = "Id: ex_shell.c,v 10.42 2003/11/05 17:11:54 skimo Exp  (Berkeley) Date: 2003/11/05 17:11:54 ";
     15  1.1  christos #endif /* not lint */
     16  1.1  christos 
     17  1.1  christos #include <sys/param.h>
     18  1.1  christos #include <sys/queue.h>
     19  1.1  christos #include <sys/wait.h>
     20  1.1  christos 
     21  1.1  christos #include <bitstring.h>
     22  1.2  christos #include <ctype.h>
     23  1.1  christos #include <errno.h>
     24  1.1  christos #include <limits.h>
     25  1.1  christos #include <signal.h>
     26  1.1  christos #include <stdio.h>
     27  1.1  christos #include <stdlib.h>
     28  1.1  christos #include <string.h>
     29  1.1  christos #include <unistd.h>
     30  1.1  christos 
     31  1.1  christos #include "../common/common.h"
     32  1.1  christos 
     33  1.1  christos static const char *sigmsg __P((int));
     34  1.1  christos 
     35  1.1  christos /*
     36  1.1  christos  * ex_shell -- :sh[ell]
     37  1.1  christos  *	Invoke the program named in the SHELL environment variable
     38  1.1  christos  *	with the argument -i.
     39  1.1  christos  *
     40  1.1  christos  * PUBLIC: int ex_shell __P((SCR *, EXCMD *));
     41  1.1  christos  */
     42  1.1  christos int
     43  1.1  christos ex_shell(SCR *sp, EXCMD *cmdp)
     44  1.1  christos {
     45  1.1  christos 	int rval;
     46  1.1  christos 	char buf[MAXPATHLEN];
     47  1.1  christos 
     48  1.1  christos 	/* We'll need a shell. */
     49  1.1  christos 	if (opts_empty(sp, O_SHELL, 0))
     50  1.1  christos 		return (1);
     51  1.1  christos 
     52  1.1  christos 	/*
     53  1.1  christos 	 * XXX
     54  1.1  christos 	 * Assumes all shells use -i.
     55  1.1  christos 	 */
     56  1.1  christos 	(void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
     57  1.1  christos 
     58  1.1  christos 	/* Restore the window name. */
     59  1.1  christos 	(void)sp->gp->scr_rename(sp, NULL, 0);
     60  1.1  christos 
     61  1.1  christos 	/* If we're still in a vi screen, move out explicitly. */
     62  1.1  christos 	rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE));
     63  1.1  christos 
     64  1.1  christos 	/* Set the window name. */
     65  1.1  christos 	(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
     66  1.1  christos 
     67  1.1  christos 	/*
     68  1.1  christos 	 * !!!
     69  1.1  christos 	 * Historically, vi didn't require a continue message after the
     70  1.1  christos 	 * return of the shell.  Match it.
     71  1.1  christos 	 */
     72  1.1  christos 	F_SET(sp, SC_EX_WAIT_NO);
     73  1.1  christos 
     74  1.1  christos 	return (rval);
     75  1.1  christos }
     76  1.1  christos 
     77  1.1  christos /*
     78  1.1  christos  * ex_exec_proc --
     79  1.1  christos  *	Run a separate process.
     80  1.1  christos  *
     81  1.2  christos  * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, const char *, const char *, int));
     82  1.1  christos  */
     83  1.1  christos int
     84  1.2  christos ex_exec_proc(SCR *sp, EXCMD *cmdp, const char *cmd, const char *msg, int need_newline)
     85  1.1  christos {
     86  1.1  christos 	GS *gp;
     87  1.1  christos 	const char *name;
     88  1.1  christos 	pid_t pid;
     89  1.1  christos 
     90  1.1  christos 	gp = sp->gp;
     91  1.1  christos 
     92  1.1  christos 	/* We'll need a shell. */
     93  1.1  christos 	if (opts_empty(sp, O_SHELL, 0))
     94  1.1  christos 		return (1);
     95  1.1  christos 
     96  1.1  christos 	/* Enter ex mode. */
     97  1.1  christos 	if (F_ISSET(sp, SC_VI)) {
     98  1.1  christos 		if (gp->scr_screen(sp, SC_EX)) {
     99  1.1  christos 			ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON);
    100  1.1  christos 			return (1);
    101  1.1  christos 		}
    102  1.1  christos 		(void)gp->scr_attr(sp, SA_ALTERNATE, 0);
    103  1.1  christos 		F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
    104  1.1  christos 	}
    105  1.1  christos 
    106  1.1  christos 	/* Put out additional newline, message. */
    107  1.1  christos 	if (need_newline)
    108  1.1  christos 		(void)ex_puts(sp, "\n");
    109  1.1  christos 	if (msg != NULL) {
    110  1.1  christos 		(void)ex_puts(sp, msg);
    111  1.1  christos 		(void)ex_puts(sp, "\n");
    112  1.1  christos 	}
    113  1.1  christos 	(void)ex_fflush(sp);
    114  1.1  christos 
    115  1.1  christos 	switch (pid = vfork()) {
    116  1.1  christos 	case -1:			/* Error. */
    117  1.1  christos 		msgq(sp, M_SYSERR, "vfork");
    118  1.1  christos 		return (1);
    119  1.1  christos 	case 0:				/* Utility. */
    120  1.1  christos 		if (gp->scr_child)
    121  1.1  christos 			gp->scr_child(sp);
    122  1.1  christos 		if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
    123  1.1  christos 			name = O_STR(sp, O_SHELL);
    124  1.1  christos 		else
    125  1.1  christos 			++name;
    126  1.1  christos 		execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL);
    127  1.1  christos 		msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
    128  1.1  christos 		_exit(127);
    129  1.1  christos 		/* NOTREACHED */
    130  1.1  christos 	default:			/* Parent. */
    131  1.1  christos 		return (proc_wait(sp, (long)pid, cmd, 0, 0));
    132  1.1  christos 	}
    133  1.1  christos 	/* NOTREACHED */
    134  1.1  christos }
    135  1.1  christos 
    136  1.1  christos /*
    137  1.1  christos  * proc_wait --
    138  1.1  christos  *	Wait for one of the processes.
    139  1.1  christos  *
    140  1.1  christos  * !!!
    141  1.1  christos  * The pid_t type varies in size from a short to a long depending on the
    142  1.1  christos  * system.  It has to be cast into something or the standard promotion
    143  1.1  christos  * rules get you.  I'm using a long based on the belief that nobody is
    144  1.1  christos  * going to make it unsigned and it's unlikely to be a quad.
    145  1.1  christos  *
    146  1.1  christos  * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int));
    147  1.1  christos  */
    148  1.1  christos int
    149  1.1  christos proc_wait(SCR *sp, long int pid, const char *cmd, int silent, int okpipe)
    150  1.1  christos {
    151  1.1  christos 	size_t len;
    152  1.1  christos 	int nf, pstat;
    153  1.1  christos 	char *p;
    154  1.1  christos 
    155  1.1  christos 	/* Wait for the utility, ignoring interruptions. */
    156  1.1  christos 	for (;;) {
    157  1.1  christos 		errno = 0;
    158  1.1  christos 		if (waitpid((pid_t)pid, &pstat, 0) != -1)
    159  1.1  christos 			break;
    160  1.1  christos 		if (errno != EINTR) {
    161  1.1  christos 			msgq(sp, M_SYSERR, "waitpid");
    162  1.1  christos 			return (1);
    163  1.1  christos 		}
    164  1.1  christos 	}
    165  1.1  christos 
    166  1.1  christos 	/*
    167  1.1  christos 	 * Display the utility's exit status.  Ignore SIGPIPE from the
    168  1.1  christos 	 * parent-writer, as that only means that the utility chose to
    169  1.1  christos 	 * exit before reading all of its input.
    170  1.1  christos 	 */
    171  1.1  christos 	if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
    172  1.2  christos 		for (; isblank((unsigned char)*cmd); ++cmd);
    173  1.1  christos 		p = msg_print(sp, cmd, &nf);
    174  1.1  christos 		len = strlen(p);
    175  1.1  christos 		msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
    176  1.2  christos 		    (int)MIN(len, 20), p, len > 20 ? " ..." : "",
    177  1.1  christos 		    sigmsg(WTERMSIG(pstat)),
    178  1.1  christos 		    WCOREDUMP(pstat) ? "; core dumped" : "");
    179  1.1  christos 		if (nf)
    180  1.1  christos 			FREE_SPACE(sp, p, 0);
    181  1.1  christos 		return (1);
    182  1.1  christos 	}
    183  1.1  christos 
    184  1.1  christos 	if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
    185  1.1  christos 		/*
    186  1.1  christos 		 * Remain silent for "normal" errors when doing shell file
    187  1.1  christos 		 * name expansions, they almost certainly indicate nothing
    188  1.1  christos 		 * more than a failure to match.
    189  1.1  christos 		 *
    190  1.1  christos 		 * Remain silent for vi read filter errors.  It's historic
    191  1.1  christos 		 * practice.
    192  1.1  christos 		 */
    193  1.1  christos 		if (!silent) {
    194  1.2  christos 			for (; isblank((unsigned char)*cmd); ++cmd);
    195  1.1  christos 			p = msg_print(sp, cmd, &nf);
    196  1.1  christos 			len = strlen(p);
    197  1.1  christos 			msgq(sp, M_ERR, "%.*s%s: exited with status %d",
    198  1.2  christos 			    (int)MIN(len, 20), p, len > 20 ? " ..." : "",
    199  1.1  christos 			    WEXITSTATUS(pstat));
    200  1.1  christos 			if (nf)
    201  1.1  christos 				FREE_SPACE(sp, p, 0);
    202  1.1  christos 		}
    203  1.1  christos 		return (1);
    204  1.1  christos 	}
    205  1.1  christos 	return (0);
    206  1.1  christos }
    207  1.1  christos 
    208  1.1  christos /*
    209  1.1  christos  * XXX
    210  1.1  christos  * The sys_siglist[] table in the C library has this information, but there's
    211  1.1  christos  * no portable way to get to it.  (Believe me, I tried.)
    212  1.1  christos  */
    213  1.1  christos typedef struct _sigs {
    214  1.1  christos 	int	 number;		/* signal number */
    215  1.2  christos 	const char *message;		/* related message */
    216  1.1  christos } SIGS;
    217  1.1  christos 
    218  1.1  christos SIGS const sigs[] = {
    219  1.1  christos #ifdef SIGABRT
    220  1.2  christos 	{ SIGABRT,	"Abort trap" },
    221  1.1  christos #endif
    222  1.1  christos #ifdef SIGALRM
    223  1.2  christos 	{ SIGALRM,	"Alarm clock" },
    224  1.1  christos #endif
    225  1.1  christos #ifdef SIGBUS
    226  1.2  christos 	{ SIGBUS,		"Bus error" },
    227  1.1  christos #endif
    228  1.1  christos #ifdef SIGCLD
    229  1.2  christos 	{ SIGCLD,		"Child exited or stopped" },
    230  1.1  christos #endif
    231  1.1  christos #ifdef SIGCHLD
    232  1.2  christos 	{ SIGCHLD,	"Child exited" },
    233  1.1  christos #endif
    234  1.1  christos #ifdef SIGCONT
    235  1.2  christos 	{ SIGCONT,	"Continued" },
    236  1.1  christos #endif
    237  1.1  christos #ifdef SIGDANGER
    238  1.2  christos 	{ SIGDANGER,	"System crash imminent" },
    239  1.1  christos #endif
    240  1.1  christos #ifdef SIGEMT
    241  1.2  christos 	{ SIGEMT,		"EMT trap" },
    242  1.1  christos #endif
    243  1.1  christos #ifdef SIGFPE
    244  1.2  christos 	{ SIGFPE,		"Floating point exception" },
    245  1.1  christos #endif
    246  1.1  christos #ifdef SIGGRANT
    247  1.2  christos 	{ SIGGRANT,	"HFT monitor mode granted" },
    248  1.1  christos #endif
    249  1.1  christos #ifdef SIGHUP
    250  1.2  christos 	{ SIGHUP,		"Hangup" },
    251  1.1  christos #endif
    252  1.1  christos #ifdef SIGILL
    253  1.2  christos 	{ SIGILL,		"Illegal instruction" },
    254  1.1  christos #endif
    255  1.1  christos #ifdef SIGINFO
    256  1.2  christos 	{ SIGINFO,	"Information request" },
    257  1.1  christos #endif
    258  1.1  christos #ifdef SIGINT
    259  1.2  christos 	{ SIGINT,		"Interrupt" },
    260  1.1  christos #endif
    261  1.1  christos #ifdef SIGIO
    262  1.2  christos 	{ SIGIO,		"I/O possible" },
    263  1.1  christos #endif
    264  1.1  christos #ifdef SIGIOT
    265  1.2  christos 	{ SIGIOT,		"IOT trap" },
    266  1.1  christos #endif
    267  1.1  christos #ifdef SIGKILL
    268  1.2  christos 	{ SIGKILL,	"Killed" },
    269  1.1  christos #endif
    270  1.1  christos #ifdef SIGLOST
    271  1.2  christos 	{ SIGLOST,	"Record lock" },
    272  1.1  christos #endif
    273  1.1  christos #ifdef SIGMIGRATE
    274  1.2  christos 	{ SIGMIGRATE,	"Migrate process to another CPU" },
    275  1.1  christos #endif
    276  1.1  christos #ifdef SIGMSG
    277  1.2  christos 	{ SIGMSG,		"HFT input data pending" },
    278  1.1  christos #endif
    279  1.1  christos #ifdef SIGPIPE
    280  1.2  christos 	{ SIGPIPE,	"Broken pipe" },
    281  1.1  christos #endif
    282  1.1  christos #ifdef SIGPOLL
    283  1.2  christos 	{ SIGPOLL,	"I/O possible" },
    284  1.1  christos #endif
    285  1.1  christos #ifdef SIGPRE
    286  1.2  christos 	{ SIGPRE,		"Programming error" },
    287  1.1  christos #endif
    288  1.1  christos #ifdef SIGPROF
    289  1.2  christos 	{ SIGPROF,	"Profiling timer expired" },
    290  1.1  christos #endif
    291  1.1  christos #ifdef SIGPWR
    292  1.2  christos 	{ SIGPWR,		"Power failure imminent" },
    293  1.1  christos #endif
    294  1.1  christos #ifdef SIGRETRACT
    295  1.2  christos 	{ SIGRETRACT,	"HFT monitor mode retracted" },
    296  1.1  christos #endif
    297  1.1  christos #ifdef SIGQUIT
    298  1.2  christos 	{ SIGQUIT,	"Quit" },
    299  1.1  christos #endif
    300  1.1  christos #ifdef SIGSAK
    301  1.2  christos 	{ SIGSAK,		"Secure Attention Key" },
    302  1.1  christos #endif
    303  1.1  christos #ifdef SIGSEGV
    304  1.2  christos 	{ SIGSEGV,	"Segmentation fault" },
    305  1.1  christos #endif
    306  1.1  christos #ifdef SIGSOUND
    307  1.2  christos 	{ SIGSOUND,	"HFT sound sequence completed" },
    308  1.1  christos #endif
    309  1.1  christos #ifdef SIGSTOP
    310  1.2  christos 	{ SIGSTOP,	"Suspended (signal)" },
    311  1.1  christos #endif
    312  1.1  christos #ifdef SIGSYS
    313  1.2  christos 	{ SIGSYS,		"Bad system call" },
    314  1.1  christos #endif
    315  1.1  christos #ifdef SIGTERM
    316  1.2  christos 	{ SIGTERM,	"Terminated" },
    317  1.1  christos #endif
    318  1.1  christos #ifdef SIGTRAP
    319  1.2  christos 	{ SIGTRAP,	"Trace/BPT trap" },
    320  1.1  christos #endif
    321  1.1  christos #ifdef SIGTSTP
    322  1.2  christos 	{ SIGTSTP,	"Suspended" },
    323  1.1  christos #endif
    324  1.1  christos #ifdef SIGTTIN
    325  1.2  christos 	{ SIGTTIN,	"Stopped (tty input)" },
    326  1.1  christos #endif
    327  1.1  christos #ifdef SIGTTOU
    328  1.2  christos 	{ SIGTTOU,	"Stopped (tty output)" },
    329  1.1  christos #endif
    330  1.1  christos #ifdef SIGURG
    331  1.2  christos 	{ SIGURG,		"Urgent I/O condition" },
    332  1.1  christos #endif
    333  1.1  christos #ifdef SIGUSR1
    334  1.2  christos 	{ SIGUSR1,	"User defined signal 1" },
    335  1.1  christos #endif
    336  1.1  christos #ifdef SIGUSR2
    337  1.2  christos 	{ SIGUSR2,	"User defined signal 2" },
    338  1.1  christos #endif
    339  1.1  christos #ifdef SIGVTALRM
    340  1.2  christos 	{ SIGVTALRM,	"Virtual timer expired" },
    341  1.1  christos #endif
    342  1.1  christos #ifdef SIGWINCH
    343  1.2  christos 	{ SIGWINCH,	"Window size changes" },
    344  1.1  christos #endif
    345  1.1  christos #ifdef SIGXCPU
    346  1.2  christos 	{ SIGXCPU,	"Cputime limit exceeded" },
    347  1.1  christos #endif
    348  1.1  christos #ifdef SIGXFSZ
    349  1.2  christos 	{ SIGXFSZ,	"Filesize limit exceeded" },
    350  1.1  christos #endif
    351  1.1  christos };
    352  1.1  christos 
    353  1.1  christos /*
    354  1.1  christos  * sigmsg --
    355  1.1  christos  * 	Return a pointer to a message describing a signal.
    356  1.1  christos  */
    357  1.1  christos static const char *
    358  1.1  christos sigmsg(int signo)
    359  1.1  christos {
    360  1.1  christos 	static char buf[40];
    361  1.1  christos 	const SIGS *sigp;
    362  1.2  christos 	size_t n;
    363  1.1  christos 
    364  1.1  christos 	for (n = 0,
    365  1.1  christos 	    sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp)
    366  1.1  christos 		if (sigp->number == signo)
    367  1.1  christos 			return (sigp->message);
    368  1.1  christos 	(void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo);
    369  1.1  christos 	return (buf);
    370  1.1  christos }
    371