align CHAR_T string in log
[nvi.git] / ex / ex_shell.c
blob8176fdd8e8774e21d50d627a3d2a473ab60bfe60
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.39 2000/07/11 15:10:59 skimo Exp $ (Berkeley) $Date: 2000/07/11 15:10:59 $";
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 (gp->scr_child)
126 gp->scr_child(sp);
127 if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
128 name = O_STR(sp, O_SHELL);
129 else
130 ++name;
131 execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL);
132 msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
133 _exit(127);
134 /* NOTREACHED */
135 default: /* Parent. */
136 return (proc_wait(sp, (long)pid, cmd, 0, 0));
138 /* NOTREACHED */
142 * proc_wait --
143 * Wait for one of the processes.
145 * !!!
146 * The pid_t type varies in size from a short to a long depending on the
147 * system. It has to be cast into something or the standard promotion
148 * rules get you. I'm using a long based on the belief that nobody is
149 * going to make it unsigned and it's unlikely to be a quad.
151 * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int));
154 proc_wait(sp, pid, cmd, silent, okpipe)
155 SCR *sp;
156 long pid;
157 const char *cmd;
158 int silent, okpipe;
160 size_t len;
161 int nf, pstat;
162 char *p;
164 /* Wait for the utility, ignoring interruptions. */
165 for (;;) {
166 errno = 0;
167 if (waitpid((pid_t)pid, &pstat, 0) != -1)
168 break;
169 if (errno != EINTR) {
170 msgq(sp, M_SYSERR, "waitpid");
171 return (1);
176 * Display the utility's exit status. Ignore SIGPIPE from the
177 * parent-writer, as that only means that the utility chose to
178 * exit before reading all of its input.
180 if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
181 for (; isblank(*cmd); ++cmd);
182 p = msg_print(sp, cmd, &nf);
183 len = strlen(p);
184 msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
185 MIN(len, 20), p, len > 20 ? " ..." : "",
186 sigmsg(WTERMSIG(pstat)),
187 WCOREDUMP(pstat) ? "; core dumped" : "");
188 if (nf)
189 FREE_SPACE(sp, p, 0);
190 return (1);
193 if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
195 * Remain silent for "normal" errors when doing shell file
196 * name expansions, they almost certainly indicate nothing
197 * more than a failure to match.
199 * Remain silent for vi read filter errors. It's historic
200 * practice.
202 if (!silent) {
203 for (; isblank(*cmd); ++cmd);
204 p = msg_print(sp, cmd, &nf);
205 len = strlen(p);
206 msgq(sp, M_ERR, "%.*s%s: exited with status %d",
207 MIN(len, 20), p, len > 20 ? " ..." : "",
208 WEXITSTATUS(pstat));
209 if (nf)
210 FREE_SPACE(sp, p, 0);
212 return (1);
214 return (0);
218 * XXX
219 * The sys_siglist[] table in the C library has this information, but there's
220 * no portable way to get to it. (Believe me, I tried.)
222 typedef struct _sigs {
223 int number; /* signal number */
224 char *message; /* related message */
225 } SIGS;
227 SIGS const sigs[] = {
228 #ifdef SIGABRT
229 SIGABRT, "Abort trap",
230 #endif
231 #ifdef SIGALRM
232 SIGALRM, "Alarm clock",
233 #endif
234 #ifdef SIGBUS
235 SIGBUS, "Bus error",
236 #endif
237 #ifdef SIGCLD
238 SIGCLD, "Child exited or stopped",
239 #endif
240 #ifdef SIGCHLD
241 SIGCHLD, "Child exited",
242 #endif
243 #ifdef SIGCONT
244 SIGCONT, "Continued",
245 #endif
246 #ifdef SIGDANGER
247 SIGDANGER, "System crash imminent",
248 #endif
249 #ifdef SIGEMT
250 SIGEMT, "EMT trap",
251 #endif
252 #ifdef SIGFPE
253 SIGFPE, "Floating point exception",
254 #endif
255 #ifdef SIGGRANT
256 SIGGRANT, "HFT monitor mode granted",
257 #endif
258 #ifdef SIGHUP
259 SIGHUP, "Hangup",
260 #endif
261 #ifdef SIGILL
262 SIGILL, "Illegal instruction",
263 #endif
264 #ifdef SIGINFO
265 SIGINFO, "Information request",
266 #endif
267 #ifdef SIGINT
268 SIGINT, "Interrupt",
269 #endif
270 #ifdef SIGIO
271 SIGIO, "I/O possible",
272 #endif
273 #ifdef SIGIOT
274 SIGIOT, "IOT trap",
275 #endif
276 #ifdef SIGKILL
277 SIGKILL, "Killed",
278 #endif
279 #ifdef SIGLOST
280 SIGLOST, "Record lock",
281 #endif
282 #ifdef SIGMIGRATE
283 SIGMIGRATE, "Migrate process to another CPU",
284 #endif
285 #ifdef SIGMSG
286 SIGMSG, "HFT input data pending",
287 #endif
288 #ifdef SIGPIPE
289 SIGPIPE, "Broken pipe",
290 #endif
291 #ifdef SIGPOLL
292 SIGPOLL, "I/O possible",
293 #endif
294 #ifdef SIGPRE
295 SIGPRE, "Programming error",
296 #endif
297 #ifdef SIGPROF
298 SIGPROF, "Profiling timer expired",
299 #endif
300 #ifdef SIGPWR
301 SIGPWR, "Power failure imminent",
302 #endif
303 #ifdef SIGRETRACT
304 SIGRETRACT, "HFT monitor mode retracted",
305 #endif
306 #ifdef SIGQUIT
307 SIGQUIT, "Quit",
308 #endif
309 #ifdef SIGSAK
310 SIGSAK, "Secure Attention Key",
311 #endif
312 #ifdef SIGSEGV
313 SIGSEGV, "Segmentation fault",
314 #endif
315 #ifdef SIGSOUND
316 SIGSOUND, "HFT sound sequence completed",
317 #endif
318 #ifdef SIGSTOP
319 SIGSTOP, "Suspended (signal)",
320 #endif
321 #ifdef SIGSYS
322 SIGSYS, "Bad system call",
323 #endif
324 #ifdef SIGTERM
325 SIGTERM, "Terminated",
326 #endif
327 #ifdef SIGTRAP
328 SIGTRAP, "Trace/BPT trap",
329 #endif
330 #ifdef SIGTSTP
331 SIGTSTP, "Suspended",
332 #endif
333 #ifdef SIGTTIN
334 SIGTTIN, "Stopped (tty input)",
335 #endif
336 #ifdef SIGTTOU
337 SIGTTOU, "Stopped (tty output)",
338 #endif
339 #ifdef SIGURG
340 SIGURG, "Urgent I/O condition",
341 #endif
342 #ifdef SIGUSR1
343 SIGUSR1, "User defined signal 1",
344 #endif
345 #ifdef SIGUSR2
346 SIGUSR2, "User defined signal 2",
347 #endif
348 #ifdef SIGVTALRM
349 SIGVTALRM, "Virtual timer expired",
350 #endif
351 #ifdef SIGWINCH
352 SIGWINCH, "Window size changes",
353 #endif
354 #ifdef SIGXCPU
355 SIGXCPU, "Cputime limit exceeded",
356 #endif
357 #ifdef SIGXFSZ
358 SIGXFSZ, "Filesize limit exceeded",
359 #endif
363 * sigmsg --
364 * Return a pointer to a message describing a signal.
366 static const char *
367 sigmsg(signo)
368 int signo;
370 static char buf[40];
371 const SIGS *sigp;
372 int n;
374 for (n = 0,
375 sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp)
376 if (sigp->number == signo)
377 return (sigp->message);
378 (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo);
379 return (buf);