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