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