text input: fix problem with autoindenting and ^^D
[nvi.git] / ex / ex_shell.c
blob00ce137ed609b50317ee2b44b7d0fce32eb65119
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.42 2003/11/05 17:11:54 skimo Exp $ (Berkeley) $Date: 2003/11/05 17:11:54 $";
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(SCR *sp, EXCMD *cmdp)
43 int rval;
44 char buf[MAXPATHLEN];
46 /* We'll need a shell. */
47 if (opts_empty(sp, O_SHELL, 0))
48 return (1);
51 * XXX
52 * Assumes all shells use -i.
54 (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
56 /* Restore the window name. */
57 (void)sp->gp->scr_rename(sp, NULL, 0);
59 /* If we're still in a vi screen, move out explicitly. */
60 rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE));
62 /* Set the window name. */
63 (void)sp->gp->scr_rename(sp, sp->frp->name, 1);
66 * !!!
67 * Historically, vi didn't require a continue message after the
68 * return of the shell. Match it.
70 F_SET(sp, SC_EX_WAIT_NO);
72 return (rval);
76 * ex_exec_proc --
77 * Run a separate process.
79 * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int));
81 int
82 ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, int need_newline)
84 GS *gp;
85 const char *name;
86 pid_t pid;
88 gp = sp->gp;
90 /* We'll need a shell. */
91 if (opts_empty(sp, O_SHELL, 0))
92 return (1);
94 /* Enter ex mode. */
95 if (F_ISSET(sp, SC_VI)) {
96 if (gp->scr_screen(sp, SC_EX)) {
97 ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON);
98 return (1);
100 (void)gp->scr_attr(sp, SA_ALTERNATE, 0);
101 F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
104 /* Put out additional newline, message. */
105 if (need_newline)
106 (void)ex_puts(sp, "\n");
107 if (msg != NULL) {
108 (void)ex_puts(sp, msg);
109 (void)ex_puts(sp, "\n");
111 (void)ex_fflush(sp);
113 switch (pid = vfork()) {
114 case -1: /* Error. */
115 msgq(sp, M_SYSERR, "vfork");
116 return (1);
117 case 0: /* Utility. */
118 if (gp->scr_child)
119 gp->scr_child(sp);
120 if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
121 name = O_STR(sp, O_SHELL);
122 else
123 ++name;
124 execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL);
125 msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
126 _exit(127);
127 /* NOTREACHED */
128 default: /* Parent. */
129 return (proc_wait(sp, (long)pid, cmd, 0, 0));
131 /* NOTREACHED */
135 * proc_wait --
136 * Wait for one of the processes.
138 * !!!
139 * The pid_t type varies in size from a short to a long depending on the
140 * system. It has to be cast into something or the standard promotion
141 * rules get you. I'm using a long based on the belief that nobody is
142 * going to make it unsigned and it's unlikely to be a quad.
144 * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int));
147 proc_wait(SCR *sp, long int pid, const char *cmd, int silent, int okpipe)
149 size_t len;
150 int nf, pstat;
151 char *p;
153 /* Wait for the utility, ignoring interruptions. */
154 for (;;) {
155 errno = 0;
156 if (waitpid((pid_t)pid, &pstat, 0) != -1)
157 break;
158 if (errno != EINTR) {
159 msgq(sp, M_SYSERR, "waitpid");
160 return (1);
165 * Display the utility's exit status. Ignore SIGPIPE from the
166 * parent-writer, as that only means that the utility chose to
167 * exit before reading all of its input.
169 if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
170 for (; isblank(*cmd); ++cmd);
171 p = msg_print(sp, cmd, &nf);
172 len = strlen(p);
173 msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
174 MIN(len, 20), p, len > 20 ? " ..." : "",
175 sigmsg(WTERMSIG(pstat)),
176 WCOREDUMP(pstat) ? "; core dumped" : "");
177 if (nf)
178 FREE_SPACE(sp, p, 0);
179 return (1);
182 if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
184 * Remain silent for "normal" errors when doing shell file
185 * name expansions, they almost certainly indicate nothing
186 * more than a failure to match.
188 * Remain silent for vi read filter errors. It's historic
189 * practice.
191 if (!silent) {
192 for (; isblank(*cmd); ++cmd);
193 p = msg_print(sp, cmd, &nf);
194 len = strlen(p);
195 msgq(sp, M_ERR, "%.*s%s: exited with status %d",
196 MIN(len, 20), p, len > 20 ? " ..." : "",
197 WEXITSTATUS(pstat));
198 if (nf)
199 FREE_SPACE(sp, p, 0);
201 return (1);
203 return (0);
207 * XXX
208 * The sys_siglist[] table in the C library has this information, but there's
209 * no portable way to get to it. (Believe me, I tried.)
211 typedef struct _sigs {
212 int number; /* signal number */
213 char *message; /* related message */
214 } SIGS;
216 SIGS const sigs[] = {
217 #ifdef SIGABRT
218 SIGABRT, "Abort trap",
219 #endif
220 #ifdef SIGALRM
221 SIGALRM, "Alarm clock",
222 #endif
223 #ifdef SIGBUS
224 SIGBUS, "Bus error",
225 #endif
226 #ifdef SIGCLD
227 SIGCLD, "Child exited or stopped",
228 #endif
229 #ifdef SIGCHLD
230 SIGCHLD, "Child exited",
231 #endif
232 #ifdef SIGCONT
233 SIGCONT, "Continued",
234 #endif
235 #ifdef SIGDANGER
236 SIGDANGER, "System crash imminent",
237 #endif
238 #ifdef SIGEMT
239 SIGEMT, "EMT trap",
240 #endif
241 #ifdef SIGFPE
242 SIGFPE, "Floating point exception",
243 #endif
244 #ifdef SIGGRANT
245 SIGGRANT, "HFT monitor mode granted",
246 #endif
247 #ifdef SIGHUP
248 SIGHUP, "Hangup",
249 #endif
250 #ifdef SIGILL
251 SIGILL, "Illegal instruction",
252 #endif
253 #ifdef SIGINFO
254 SIGINFO, "Information request",
255 #endif
256 #ifdef SIGINT
257 SIGINT, "Interrupt",
258 #endif
259 #ifdef SIGIO
260 SIGIO, "I/O possible",
261 #endif
262 #ifdef SIGIOT
263 SIGIOT, "IOT trap",
264 #endif
265 #ifdef SIGKILL
266 SIGKILL, "Killed",
267 #endif
268 #ifdef SIGLOST
269 SIGLOST, "Record lock",
270 #endif
271 #ifdef SIGMIGRATE
272 SIGMIGRATE, "Migrate process to another CPU",
273 #endif
274 #ifdef SIGMSG
275 SIGMSG, "HFT input data pending",
276 #endif
277 #ifdef SIGPIPE
278 SIGPIPE, "Broken pipe",
279 #endif
280 #ifdef SIGPOLL
281 SIGPOLL, "I/O possible",
282 #endif
283 #ifdef SIGPRE
284 SIGPRE, "Programming error",
285 #endif
286 #ifdef SIGPROF
287 SIGPROF, "Profiling timer expired",
288 #endif
289 #ifdef SIGPWR
290 SIGPWR, "Power failure imminent",
291 #endif
292 #ifdef SIGRETRACT
293 SIGRETRACT, "HFT monitor mode retracted",
294 #endif
295 #ifdef SIGQUIT
296 SIGQUIT, "Quit",
297 #endif
298 #ifdef SIGSAK
299 SIGSAK, "Secure Attention Key",
300 #endif
301 #ifdef SIGSEGV
302 SIGSEGV, "Segmentation fault",
303 #endif
304 #ifdef SIGSOUND
305 SIGSOUND, "HFT sound sequence completed",
306 #endif
307 #ifdef SIGSTOP
308 SIGSTOP, "Suspended (signal)",
309 #endif
310 #ifdef SIGSYS
311 SIGSYS, "Bad system call",
312 #endif
313 #ifdef SIGTERM
314 SIGTERM, "Terminated",
315 #endif
316 #ifdef SIGTRAP
317 SIGTRAP, "Trace/BPT trap",
318 #endif
319 #ifdef SIGTSTP
320 SIGTSTP, "Suspended",
321 #endif
322 #ifdef SIGTTIN
323 SIGTTIN, "Stopped (tty input)",
324 #endif
325 #ifdef SIGTTOU
326 SIGTTOU, "Stopped (tty output)",
327 #endif
328 #ifdef SIGURG
329 SIGURG, "Urgent I/O condition",
330 #endif
331 #ifdef SIGUSR1
332 SIGUSR1, "User defined signal 1",
333 #endif
334 #ifdef SIGUSR2
335 SIGUSR2, "User defined signal 2",
336 #endif
337 #ifdef SIGVTALRM
338 SIGVTALRM, "Virtual timer expired",
339 #endif
340 #ifdef SIGWINCH
341 SIGWINCH, "Window size changes",
342 #endif
343 #ifdef SIGXCPU
344 SIGXCPU, "Cputime limit exceeded",
345 #endif
346 #ifdef SIGXFSZ
347 SIGXFSZ, "Filesize limit exceeded",
348 #endif
352 * sigmsg --
353 * Return a pointer to a message describing a signal.
355 static const char *
356 sigmsg(int signo)
358 static char buf[40];
359 const SIGS *sigp;
360 int n;
362 for (n = 0,
363 sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp)
364 if (sigp->number == signo)
365 return (sigp->message);
366 (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo);
367 return (buf);