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.
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 $";
16 #include <sys/param.h>
17 #include <sys/queue.h>
20 #include <bitstring.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 *));
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 *, char *, const char *, int));
84 ex_exec_proc(sp
, cmdp
, cmd
, msg
, 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_emsg(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
, 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(sp
, pid
, cmd
, silent
, okpipe
)
164 /* Wait for the utility, ignoring interruptions. */
167 if (waitpid((pid_t
)pid
, &pstat
, 0) != -1)
169 if (errno
!= EINTR
) {
170 msgq(sp
, M_SYSERR
, "waitpid");
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
);
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" : "");
189 FREE_SPACE(sp
, p
, 0);
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
203 for (; isblank(*cmd
); ++cmd
);
204 p
= msg_print(sp
, cmd
, &nf
);
206 msgq(sp
, M_ERR
, "%.*s%s: exited with status %d",
207 MIN(len
, 20), p
, len
> 20 ? " ..." : "",
210 FREE_SPACE(sp
, p
, 0);
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 */
227 SIGS
const sigs
[] = {
229 SIGABRT
, "Abort trap",
232 SIGALRM
, "Alarm clock",
238 SIGCLD
, "Child exited or stopped",
241 SIGCHLD
, "Child exited",
244 SIGCONT
, "Continued",
247 SIGDANGER
, "System crash imminent",
253 SIGFPE
, "Floating point exception",
256 SIGGRANT
, "HFT monitor mode granted",
262 SIGILL
, "Illegal instruction",
265 SIGINFO
, "Information request",
271 SIGIO
, "I/O possible",
280 SIGLOST
, "Record lock",
283 SIGMIGRATE
, "Migrate process to another CPU",
286 SIGMSG
, "HFT input data pending",
289 SIGPIPE
, "Broken pipe",
292 SIGPOLL
, "I/O possible",
295 SIGPRE
, "Programming error",
298 SIGPROF
, "Profiling timer expired",
301 SIGPWR
, "Power failure imminent",
304 SIGRETRACT
, "HFT monitor mode retracted",
310 SIGSAK
, "Secure Attention Key",
313 SIGSEGV
, "Segmentation fault",
316 SIGSOUND
, "HFT sound sequence completed",
319 SIGSTOP
, "Suspended (signal)",
322 SIGSYS
, "Bad system call",
325 SIGTERM
, "Terminated",
328 SIGTRAP
, "Trace/BPT trap",
331 SIGTSTP
, "Suspended",
334 SIGTTIN
, "Stopped (tty input)",
337 SIGTTOU
, "Stopped (tty output)",
340 SIGURG
, "Urgent I/O condition",
343 SIGUSR1
, "User defined signal 1",
346 SIGUSR2
, "User defined signal 2",
349 SIGVTALRM
, "Virtual timer expired",
352 SIGWINCH
, "Window size changes",
355 SIGXCPU
, "Cputime limit exceeded",
358 SIGXFSZ
, "Filesize limit exceeded",
364 * Return a pointer to a message describing a signal.
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
);