1 /* $NetBSD: ex_shell.c,v 1.3 2009/01/18 03:45:50 lukem Exp $ */
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.
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";
18 #include <sys/param.h>
19 #include <sys/queue.h>
22 #include <bitstring.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 *));
43 ex_shell(SCR
*sp
, EXCMD
*cmdp
)
48 /* We'll need a shell. */
49 if (opts_empty(sp
, O_SHELL
, 0))
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);
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
);
79 * Run a separate process.
81 * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, const char *, const char *, int));
84 ex_exec_proc(SCR
*sp
, EXCMD
*cmdp
, const char *cmd
, const char *msg
, int need_newline
)
92 /* We'll need a shell. */
93 if (opts_empty(sp
, O_SHELL
, 0))
97 if (F_ISSET(sp
, SC_VI
)) {
98 if (gp
->scr_screen(sp
, SC_EX
)) {
99 ex_wemsg(sp
, cmdp
->cmd
->name
, EXM_NOCANON
);
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. */
108 (void)ex_puts(sp
, "\n");
110 (void)ex_puts(sp
, msg
);
111 (void)ex_puts(sp
, "\n");
115 switch (pid
= vfork()) {
116 case -1: /* Error. */
117 msgq(sp
, M_SYSERR
, "vfork");
119 case 0: /* Utility. */
122 if ((name
= strrchr(O_STR(sp
, O_SHELL
), '/')) == NULL
)
123 name
= O_STR(sp
, O_SHELL
);
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");
130 default: /* Parent. */
131 return (proc_wait(sp
, (long)pid
, cmd
, 0, 0));
138 * Wait for one of the processes.
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
)
155 /* Wait for the utility, ignoring interruptions. */
158 if (waitpid((pid_t
)pid
, &pstat
, 0) != -1)
160 if (errno
!= EINTR
) {
161 msgq(sp
, M_SYSERR
, "waitpid");
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
);
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" : "");
180 FREE_SPACE(sp
, p
, 0);
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
194 for (; isblank(*cmd
); ++cmd
);
195 p
= msg_print(sp
, cmd
, &nf
);
197 msgq(sp
, M_ERR
, "%.*s%s: exited with status %d",
198 (int)MIN(len
, 20), p
, len
> 20 ? " ..." : "",
201 FREE_SPACE(sp
, p
, 0);
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 */
218 SIGS
const sigs
[] = {
220 { SIGABRT
, "Abort trap" },
223 { SIGALRM
, "Alarm clock" },
226 { SIGBUS
, "Bus error" },
229 { SIGCLD
, "Child exited or stopped" },
232 { SIGCHLD
, "Child exited" },
235 { SIGCONT
, "Continued" },
238 { SIGDANGER
, "System crash imminent" },
241 { SIGEMT
, "EMT trap" },
244 { SIGFPE
, "Floating point exception" },
247 { SIGGRANT
, "HFT monitor mode granted" },
250 { SIGHUP
, "Hangup" },
253 { SIGILL
, "Illegal instruction" },
256 { SIGINFO
, "Information request" },
259 { SIGINT
, "Interrupt" },
262 { SIGIO
, "I/O possible" },
265 { SIGIOT
, "IOT trap" },
268 { SIGKILL
, "Killed" },
271 { SIGLOST
, "Record lock" },
274 { SIGMIGRATE
, "Migrate process to another CPU" },
277 { SIGMSG
, "HFT input data pending" },
280 { SIGPIPE
, "Broken pipe" },
283 { SIGPOLL
, "I/O possible" },
286 { SIGPRE
, "Programming error" },
289 { SIGPROF
, "Profiling timer expired" },
292 { SIGPWR
, "Power failure imminent" },
295 { SIGRETRACT
, "HFT monitor mode retracted" },
301 { SIGSAK
, "Secure Attention Key" },
304 { SIGSEGV
, "Segmentation fault" },
307 { SIGSOUND
, "HFT sound sequence completed" },
310 { SIGSTOP
, "Suspended (signal)" },
313 { SIGSYS
, "Bad system call" },
316 { SIGTERM
, "Terminated" },
319 { SIGTRAP
, "Trace/BPT trap" },
322 { SIGTSTP
, "Suspended" },
325 { SIGTTIN
, "Stopped (tty input)" },
328 { SIGTTOU
, "Stopped (tty output)" },
331 { SIGURG
, "Urgent I/O condition" },
334 { SIGUSR1
, "User defined signal 1" },
337 { SIGUSR2
, "User defined signal 2" },
340 { SIGVTALRM
, "Virtual timer expired" },
343 { SIGWINCH
, "Window size changes" },
346 { SIGXCPU
, "Cputime limit exceeded" },
349 { SIGXFSZ
, "Filesize limit exceeded" },
355 * Return a pointer to a message describing a signal.
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
);