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