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