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