1 /* $NetBSD: ex_shell.c,v 1.3 2014/01/26 21:43:45 christos Exp $ */
3 * Copyright (c) 1992, 1993, 1994
4 * The Regents of the University of California. All rights reserved.
5 * Copyright (c) 1992, 1993, 1994, 1995, 1996
6 * Keith Bostic. All rights reserved.
8 * See the LICENSE file for redistribution information.
13 #include <sys/cdefs.h>
16 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 ";
19 __RCSID("$NetBSD: ex_shell.c,v 1.3 2014/01/26 21:43:45 christos Exp $");
22 #include <sys/param.h>
23 #include <sys/queue.h>
26 #include <bitstring.h>
36 #include "../common/common.h"
38 static const char *sigmsg
__P((int));
41 * ex_shell -- :sh[ell]
42 * Invoke the program named in the SHELL environment variable
43 * with the argument -i.
45 * PUBLIC: int ex_shell __P((SCR *, EXCMD *));
48 ex_shell(SCR
*sp
, EXCMD
*cmdp
)
53 /* We'll need a shell. */
54 if (opts_empty(sp
, O_SHELL
, 0))
59 * Assumes all shells use -i.
61 (void)snprintf(buf
, sizeof(buf
), "%s -i", O_STR(sp
, O_SHELL
));
63 /* Restore the window name. */
64 (void)sp
->gp
->scr_rename(sp
, NULL
, 0);
66 /* If we're still in a vi screen, move out explicitly. */
67 rval
= ex_exec_proc(sp
, cmdp
, buf
, NULL
, !F_ISSET(sp
, SC_SCR_EXWROTE
));
69 /* Set the window name. */
70 (void)sp
->gp
->scr_rename(sp
, sp
->frp
->name
, 1);
74 * Historically, vi didn't require a continue message after the
75 * return of the shell. Match it.
77 F_SET(sp
, SC_EX_WAIT_NO
);
84 * Run a separate process.
86 * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, const char *, const char *, int));
89 ex_exec_proc(SCR
*sp
, EXCMD
*cmdp
, const char *cmd
, const char *msg
, int 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_wemsg(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. */
127 if ((name
= strrchr(O_STR(sp
, O_SHELL
), '/')) == NULL
)
128 name
= O_STR(sp
, O_SHELL
);
131 execl(O_STR(sp
, O_SHELL
), name
, "-c", cmd
, (char *)NULL
);
132 msgq_str(sp
, M_SYSERR
, O_STR(sp
, O_SHELL
), "execl: %s");
135 default: /* Parent. */
136 return (proc_wait(sp
, (long)pid
, cmd
, 0, 0));
143 * Wait for one of the processes.
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(SCR
*sp
, long int pid
, const char *cmd
, int silent
, int okpipe
)
160 /* Wait for the utility, ignoring interruptions. */
163 if (waitpid((pid_t
)pid
, &pstat
, 0) != -1)
165 if (errno
!= EINTR
) {
166 msgq(sp
, M_SYSERR
, "waitpid");
172 * Display the utility's exit status. Ignore SIGPIPE from the
173 * parent-writer, as that only means that the utility chose to
174 * exit before reading all of its input.
176 if (WIFSIGNALED(pstat
) && (!okpipe
|| WTERMSIG(pstat
) != SIGPIPE
)) {
177 for (; isblank((unsigned char)*cmd
); ++cmd
);
178 p
= msg_print(sp
, cmd
, &nf
);
180 msgq(sp
, M_ERR
, "%.*s%s: received signal: %s%s",
181 (int)MIN(len
, 20), p
, len
> 20 ? " ..." : "",
182 sigmsg(WTERMSIG(pstat
)),
183 WCOREDUMP(pstat
) ? "; core dumped" : "");
185 FREE_SPACE(sp
, p
, 0);
189 if (WIFEXITED(pstat
) && WEXITSTATUS(pstat
)) {
191 * Remain silent for "normal" errors when doing shell file
192 * name expansions, they almost certainly indicate nothing
193 * more than a failure to match.
195 * Remain silent for vi read filter errors. It's historic
199 for (; isblank((unsigned char)*cmd
); ++cmd
);
200 p
= msg_print(sp
, cmd
, &nf
);
202 msgq(sp
, M_ERR
, "%.*s%s: exited with status %d",
203 (int)MIN(len
, 20), p
, len
> 20 ? " ..." : "",
206 FREE_SPACE(sp
, p
, 0);
215 * The sys_siglist[] table in the C library has this information, but there's
216 * no portable way to get to it. (Believe me, I tried.)
218 typedef struct _sigs
{
219 int number
; /* signal number */
220 const char *message
; /* related message */
223 SIGS
const sigs
[] = {
225 { SIGABRT
, "Abort trap" },
228 { SIGALRM
, "Alarm clock" },
231 { SIGBUS
, "Bus error" },
234 { SIGCLD
, "Child exited or stopped" },
237 { SIGCHLD
, "Child exited" },
240 { SIGCONT
, "Continued" },
243 { SIGDANGER
, "System crash imminent" },
246 { SIGEMT
, "EMT trap" },
249 { SIGFPE
, "Floating point exception" },
252 { SIGGRANT
, "HFT monitor mode granted" },
255 { SIGHUP
, "Hangup" },
258 { SIGILL
, "Illegal instruction" },
261 { SIGINFO
, "Information request" },
264 { SIGINT
, "Interrupt" },
267 { SIGIO
, "I/O possible" },
270 { SIGIOT
, "IOT trap" },
273 { SIGKILL
, "Killed" },
276 { SIGLOST
, "Record lock" },
279 { SIGMIGRATE
, "Migrate process to another CPU" },
282 { SIGMSG
, "HFT input data pending" },
285 { SIGPIPE
, "Broken pipe" },
288 { SIGPOLL
, "I/O possible" },
291 { SIGPRE
, "Programming error" },
294 { SIGPROF
, "Profiling timer expired" },
297 { SIGPWR
, "Power failure imminent" },
300 { SIGRETRACT
, "HFT monitor mode retracted" },
306 { SIGSAK
, "Secure Attention Key" },
309 { SIGSEGV
, "Segmentation fault" },
312 { SIGSOUND
, "HFT sound sequence completed" },
315 { SIGSTOP
, "Suspended (signal)" },
318 { SIGSYS
, "Bad system call" },
321 { SIGTERM
, "Terminated" },
324 { SIGTRAP
, "Trace/BPT trap" },
327 { SIGTSTP
, "Suspended" },
330 { SIGTTIN
, "Stopped (tty input)" },
333 { SIGTTOU
, "Stopped (tty output)" },
336 { SIGURG
, "Urgent I/O condition" },
339 { SIGUSR1
, "User defined signal 1" },
342 { SIGUSR2
, "User defined signal 2" },
345 { SIGVTALRM
, "Virtual timer expired" },
348 { SIGWINCH
, "Window size changes" },
351 { SIGXCPU
, "Cputime limit exceeded" },
354 { SIGXFSZ
, "Filesize limit exceeded" },
360 * Return a pointer to a message describing a signal.
370 sigp
= &sigs
[0]; n
< sizeof(sigs
) / sizeof(sigs
[0]); ++n
, ++sigp
)
371 if (sigp
->number
== signo
)
372 return (sigp
->message
);
373 (void)snprintf(buf
, sizeof(buf
), "Unknown signal: %d", signo
);