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.
7 * See the LICENSE file for redistribution information.
13 static const char sccsid[] = "@(#)ex_shell.c 10.38 (Berkeley) 8/19/96";
16 #include <sys/param.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
29 #include "../common/common.h"
31 static const char *sigmsg __P((int));
34 * ex_shell -- :sh[ell]
35 * Invoke the program named in the SHELL environment variable
36 * with the argument -i.
38 * PUBLIC: int ex_shell __P((SCR *, EXCMD *));
48 /* We'll need a shell. */
49 if (opts_empty(sp, O_SHELL, 0))
54 * Assumes all shells use -i.
56 (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
58 /* Restore the window name. */
59 (void)sp->gp->scr_rename(sp, NULL, 0);
61 /* If we're still in a vi screen, move out explicitly. */
62 rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE));
64 /* Set the window name. */
65 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
69 * Historically, vi didn't require a continue message after the
70 * return of the shell. Match it.
72 F_SET(sp, SC_EX_WAIT_NO);
79 * Run a separate process.
81 * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
84 ex_exec_proc(sp, cmdp, cmd, msg, need_newline)
97 /* We'll need a shell. */
98 if (opts_empty(sp, O_SHELL, 0))
102 if (F_ISSET(sp, SC_VI)) {
103 if (gp->scr_screen(sp, SC_EX)) {
104 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
107 (void)gp->scr_attr(sp, SA_ALTERNATE, 0);
108 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
111 /* Put out additional newline, message. */
113 (void)ex_puts(sp, "\n");
115 (void)ex_puts(sp, msg);
116 (void)ex_puts(sp, "\n");
120 switch (pid = vfork()) {
121 case -1: /* Error. */
122 msgq(sp, M_SYSERR, "vfork");
124 case 0: /* Utility. */
125 if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
126 name = O_STR(sp, O_SHELL);
129 execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
130 msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
133 default: /* Parent. */
134 return (proc_wait(sp, (long)pid, cmd, 0, 0));
141 * Wait for one of the processes.
144 * The pid_t type varies in size from a short to a long depending on the
145 * system. It has to be cast into something or the standard promotion
146 * rules get you. I'm using a long based on the belief that nobody is
147 * going to make it unsigned and it's unlikely to be a quad.
149 * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int));
152 proc_wait(sp, pid, cmd, silent, okpipe)
162 /* Wait for the utility, ignoring interruptions. */
165 if (waitpid((pid_t)pid, &pstat, 0) != -1)
167 if (errno != EINTR) {
168 msgq(sp, M_SYSERR, "waitpid");
174 * Display the utility's exit status. Ignore SIGPIPE from the
175 * parent-writer, as that only means that the utility chose to
176 * exit before reading all of its input.
178 if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
179 for (; isblank(*cmd); ++cmd);
180 p = msg_print(sp, cmd, &nf);
182 msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
183 MIN(len, 20), p, len > 20 ? " ..." : "",
184 sigmsg(WTERMSIG(pstat)),
185 WCOREDUMP(pstat) ? "; core dumped" : "");
187 FREE_SPACE(sp, p, 0);
191 if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
193 * Remain silent for "normal" errors when doing shell file
194 * name expansions, they almost certainly indicate nothing
195 * more than a failure to match.
197 * Remain silent for vi read filter errors. It's historic
201 for (; isblank(*cmd); ++cmd);
202 p = msg_print(sp, cmd, &nf);
204 msgq(sp, M_ERR, "%.*s%s: exited with status %d",
205 MIN(len, 20), p, len > 20 ? " ..." : "",
208 FREE_SPACE(sp, p, 0);
217 * The sys_siglist[] table in the C library has this information, but there's
218 * no portable way to get to it. (Believe me, I tried.)
220 typedef struct _sigs {
221 int number; /* signal number */
222 char *message; /* related message */
225 SIGS const sigs[] = {
227 SIGABRT, "Abort trap",
230 SIGALRM, "Alarm clock",
236 SIGCLD, "Child exited or stopped",
239 SIGCHLD, "Child exited",
242 SIGCONT, "Continued",
245 SIGDANGER, "System crash imminent",
251 SIGFPE, "Floating point exception",
254 SIGGRANT, "HFT monitor mode granted",
260 SIGILL, "Illegal instruction",
263 SIGINFO, "Information request",
269 SIGIO, "I/O possible",
278 SIGLOST, "Record lock",
281 SIGMIGRATE, "Migrate process to another CPU",
284 SIGMSG, "HFT input data pending",
287 SIGPIPE, "Broken pipe",
290 SIGPOLL, "I/O possible",
293 SIGPRE, "Programming error",
296 SIGPROF, "Profiling timer expired",
299 SIGPWR, "Power failure imminent",
302 SIGRETRACT, "HFT monitor mode retracted",
308 SIGSAK, "Secure Attention Key",
311 SIGSEGV, "Segmentation fault",
314 SIGSOUND, "HFT sound sequence completed",
317 SIGSTOP, "Suspended (signal)",
320 SIGSYS, "Bad system call",
323 SIGTERM, "Terminated",
326 SIGTRAP, "Trace/BPT trap",
329 SIGTSTP, "Suspended",
332 SIGTTIN, "Stopped (tty input)",
335 SIGTTOU, "Stopped (tty output)",
338 SIGURG, "Urgent I/O condition",
341 SIGUSR1, "User defined signal 1",
344 SIGUSR2, "User defined signal 2",
347 SIGVTALRM, "Virtual timer expired",
350 SIGWINCH, "Window size changes",
353 SIGXCPU, "Cputime limit exceeded",
356 SIGXFSZ, "Filesize limit exceeded",
362 * Return a pointer to a message describing a signal.
373 sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp)
374 if (sigp->number == signo)
375 return (sigp->message);
376 (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo);