only clean out gs when last window goes
[nvi.git] / ex / ex_shell.c
blobcef0222aeea063e1dff860f14ebd92458006ed7a
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.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: ex_shell.c,v 10.38 1996/08/19 21:52:54 bostic Exp $ (Berkeley) $Date: 1996/08/19 21:52:54 $";
14 #endif /* not lint */
16 #include <sys/param.h>
17 #include <sys/queue.h>
18 #include <sys/wait.h>
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>
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 *));
40 int
41 ex_shell(sp, cmdp)
42 SCR *sp;
43 EXCMD *cmdp;
45 int rval;
46 char buf[MAXPATHLEN];
48 /* We'll need a shell. */
49 if (opts_empty(sp, O_SHELL, 0))
50 return (1);
53 * XXX
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);
68 * !!!
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);
74 return (rval);
78 * ex_exec_proc --
79 * Run a separate process.
81 * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
83 int
84 ex_exec_proc(sp, cmdp, cmd, msg, need_newline)
85 SCR *sp;
86 EXCMD *cmdp;
87 char *cmd;
88 const char *msg;
89 int need_newline;
91 GS *gp;
92 const char *name;
93 pid_t pid;
95 gp = sp->gp;
97 /* We'll need a shell. */
98 if (opts_empty(sp, O_SHELL, 0))
99 return (1);
101 /* Enter ex mode. */
102 if (F_ISSET(sp, SC_VI)) {
103 if (gp->scr_screen(sp, SC_EX)) {
104 ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
105 return (1);
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. */
112 if (need_newline)
113 (void)ex_puts(sp, "\n");
114 if (msg != NULL) {
115 (void)ex_puts(sp, msg);
116 (void)ex_puts(sp, "\n");
118 (void)ex_fflush(sp);
120 switch (pid = vfork()) {
121 case -1: /* Error. */
122 msgq(sp, M_SYSERR, "vfork");
123 return (1);
124 case 0: /* Utility. */
125 if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
126 name = O_STR(sp, O_SHELL);
127 else
128 ++name;
129 execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
130 msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
131 _exit(127);
132 /* NOTREACHED */
133 default: /* Parent. */
134 return (proc_wait(sp, (long)pid, cmd, 0, 0));
136 /* NOTREACHED */
140 * proc_wait --
141 * Wait for one of the processes.
143 * !!!
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)
153 SCR *sp;
154 long pid;
155 const char *cmd;
156 int silent, okpipe;
158 size_t len;
159 int nf, pstat;
160 char *p;
162 /* Wait for the utility, ignoring interruptions. */
163 for (;;) {
164 errno = 0;
165 if (waitpid((pid_t)pid, &pstat, 0) != -1)
166 break;
167 if (errno != EINTR) {
168 msgq(sp, M_SYSERR, "waitpid");
169 return (1);
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);
181 len = strlen(p);
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" : "");
186 if (nf)
187 FREE_SPACE(sp, p, 0);
188 return (1);
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
198 * practice.
200 if (!silent) {
201 for (; isblank(*cmd); ++cmd);
202 p = msg_print(sp, cmd, &nf);
203 len = strlen(p);
204 msgq(sp, M_ERR, "%.*s%s: exited with status %d",
205 MIN(len, 20), p, len > 20 ? " ..." : "",
206 WEXITSTATUS(pstat));
207 if (nf)
208 FREE_SPACE(sp, p, 0);
210 return (1);
212 return (0);
216 * XXX
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 */
223 } SIGS;
225 SIGS const sigs[] = {
226 #ifdef SIGABRT
227 SIGABRT, "Abort trap",
228 #endif
229 #ifdef SIGALRM
230 SIGALRM, "Alarm clock",
231 #endif
232 #ifdef SIGBUS
233 SIGBUS, "Bus error",
234 #endif
235 #ifdef SIGCLD
236 SIGCLD, "Child exited or stopped",
237 #endif
238 #ifdef SIGCHLD
239 SIGCHLD, "Child exited",
240 #endif
241 #ifdef SIGCONT
242 SIGCONT, "Continued",
243 #endif
244 #ifdef SIGDANGER
245 SIGDANGER, "System crash imminent",
246 #endif
247 #ifdef SIGEMT
248 SIGEMT, "EMT trap",
249 #endif
250 #ifdef SIGFPE
251 SIGFPE, "Floating point exception",
252 #endif
253 #ifdef SIGGRANT
254 SIGGRANT, "HFT monitor mode granted",
255 #endif
256 #ifdef SIGHUP
257 SIGHUP, "Hangup",
258 #endif
259 #ifdef SIGILL
260 SIGILL, "Illegal instruction",
261 #endif
262 #ifdef SIGINFO
263 SIGINFO, "Information request",
264 #endif
265 #ifdef SIGINT
266 SIGINT, "Interrupt",
267 #endif
268 #ifdef SIGIO
269 SIGIO, "I/O possible",
270 #endif
271 #ifdef SIGIOT
272 SIGIOT, "IOT trap",
273 #endif
274 #ifdef SIGKILL
275 SIGKILL, "Killed",
276 #endif
277 #ifdef SIGLOST
278 SIGLOST, "Record lock",
279 #endif
280 #ifdef SIGMIGRATE
281 SIGMIGRATE, "Migrate process to another CPU",
282 #endif
283 #ifdef SIGMSG
284 SIGMSG, "HFT input data pending",
285 #endif
286 #ifdef SIGPIPE
287 SIGPIPE, "Broken pipe",
288 #endif
289 #ifdef SIGPOLL
290 SIGPOLL, "I/O possible",
291 #endif
292 #ifdef SIGPRE
293 SIGPRE, "Programming error",
294 #endif
295 #ifdef SIGPROF
296 SIGPROF, "Profiling timer expired",
297 #endif
298 #ifdef SIGPWR
299 SIGPWR, "Power failure imminent",
300 #endif
301 #ifdef SIGRETRACT
302 SIGRETRACT, "HFT monitor mode retracted",
303 #endif
304 #ifdef SIGQUIT
305 SIGQUIT, "Quit",
306 #endif
307 #ifdef SIGSAK
308 SIGSAK, "Secure Attention Key",
309 #endif
310 #ifdef SIGSEGV
311 SIGSEGV, "Segmentation fault",
312 #endif
313 #ifdef SIGSOUND
314 SIGSOUND, "HFT sound sequence completed",
315 #endif
316 #ifdef SIGSTOP
317 SIGSTOP, "Suspended (signal)",
318 #endif
319 #ifdef SIGSYS
320 SIGSYS, "Bad system call",
321 #endif
322 #ifdef SIGTERM
323 SIGTERM, "Terminated",
324 #endif
325 #ifdef SIGTRAP
326 SIGTRAP, "Trace/BPT trap",
327 #endif
328 #ifdef SIGTSTP
329 SIGTSTP, "Suspended",
330 #endif
331 #ifdef SIGTTIN
332 SIGTTIN, "Stopped (tty input)",
333 #endif
334 #ifdef SIGTTOU
335 SIGTTOU, "Stopped (tty output)",
336 #endif
337 #ifdef SIGURG
338 SIGURG, "Urgent I/O condition",
339 #endif
340 #ifdef SIGUSR1
341 SIGUSR1, "User defined signal 1",
342 #endif
343 #ifdef SIGUSR2
344 SIGUSR2, "User defined signal 2",
345 #endif
346 #ifdef SIGVTALRM
347 SIGVTALRM, "Virtual timer expired",
348 #endif
349 #ifdef SIGWINCH
350 SIGWINCH, "Window size changes",
351 #endif
352 #ifdef SIGXCPU
353 SIGXCPU, "Cputime limit exceeded",
354 #endif
355 #ifdef SIGXFSZ
356 SIGXFSZ, "Filesize limit exceeded",
357 #endif
361 * sigmsg --
362 * Return a pointer to a message describing a signal.
364 static const char *
365 sigmsg(signo)
366 int signo;
368 static char buf[40];
369 const SIGS *sigp;
370 int n;
372 for (n = 0,
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);
377 return (buf);