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