119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: ex_shell.c,v 10.44 2012/07/06 06:51:26 zy Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/queue.h> 17254225Speter#include <sys/time.h> 1819304Speter#include <sys/wait.h> 1919304Speter 2019304Speter#include <bitstring.h> 21254225Speter#include <ctype.h> 2219304Speter#include <errno.h> 2319304Speter#include <limits.h> 2419304Speter#include <signal.h> 2519304Speter#include <stdio.h> 2619304Speter#include <stdlib.h> 2719304Speter#include <string.h> 2819304Speter#include <unistd.h> 2919304Speter 3019304Speter#include "../common/common.h" 3119304Speter 3219304Speterstatic const char *sigmsg __P((int)); 3319304Speter 3419304Speter/* 3519304Speter * ex_shell -- :sh[ell] 3619304Speter * Invoke the program named in the SHELL environment variable 3719304Speter * with the argument -i. 3819304Speter * 3919304Speter * PUBLIC: int ex_shell __P((SCR *, EXCMD *)); 4019304Speter */ 4119304Speterint 42254225Speterex_shell(SCR *sp, EXCMD *cmdp) 4319304Speter{ 4419304Speter int rval; 45254225Speter char *buf; 4619304Speter 4719304Speter /* We'll need a shell. */ 4819304Speter if (opts_empty(sp, O_SHELL, 0)) 4919304Speter return (1); 5019304Speter 5119304Speter /* 5219304Speter * XXX 5319304Speter * Assumes all shells use -i. 5419304Speter */ 55254225Speter (void)asprintf(&buf, "%s -i", O_STR(sp, O_SHELL)); 56254225Speter if (buf == NULL) { 57254225Speter msgq(sp, M_SYSERR, NULL); 58254225Speter return (1); 59254225Speter } 6019304Speter 6119304Speter /* Restore the window name. */ 6219304Speter (void)sp->gp->scr_rename(sp, NULL, 0); 6319304Speter 6419304Speter /* If we're still in a vi screen, move out explicitly. */ 6519304Speter rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE)); 66254225Speter free(buf); 6719304Speter 6819304Speter /* Set the window name. */ 6919304Speter (void)sp->gp->scr_rename(sp, sp->frp->name, 1); 7019304Speter 7119304Speter /* 7219304Speter * !!! 7319304Speter * Historically, vi didn't require a continue message after the 7419304Speter * return of the shell. Match it. 7519304Speter */ 7619304Speter F_SET(sp, SC_EX_WAIT_NO); 7719304Speter 7819304Speter return (rval); 7919304Speter} 8019304Speter 8119304Speter/* 8219304Speter * ex_exec_proc -- 8319304Speter * Run a separate process. 8419304Speter * 8519304Speter * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int)); 8619304Speter */ 8719304Speterint 88254225Speterex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, int need_newline) 8919304Speter{ 9019304Speter GS *gp; 9119304Speter const char *name; 9219304Speter pid_t pid; 9319304Speter 9419304Speter gp = sp->gp; 9519304Speter 9619304Speter /* We'll need a shell. */ 9719304Speter if (opts_empty(sp, O_SHELL, 0)) 9819304Speter return (1); 9919304Speter 10019304Speter /* Enter ex mode. */ 10119304Speter if (F_ISSET(sp, SC_VI)) { 10219304Speter if (gp->scr_screen(sp, SC_EX)) { 103254225Speter ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON); 10419304Speter return (1); 10519304Speter } 10619304Speter (void)gp->scr_attr(sp, SA_ALTERNATE, 0); 10719304Speter F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); 10819304Speter } 10919304Speter 11019304Speter /* Put out additional newline, message. */ 11119304Speter if (need_newline) 11219304Speter (void)ex_puts(sp, "\n"); 11319304Speter if (msg != NULL) { 11419304Speter (void)ex_puts(sp, msg); 11519304Speter (void)ex_puts(sp, "\n"); 11619304Speter } 11719304Speter (void)ex_fflush(sp); 11819304Speter 11919304Speter switch (pid = vfork()) { 12019304Speter case -1: /* Error. */ 12119304Speter msgq(sp, M_SYSERR, "vfork"); 12219304Speter return (1); 12319304Speter case 0: /* Utility. */ 124254225Speter if (gp->scr_child) 125254225Speter gp->scr_child(sp); 12619304Speter if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) 12719304Speter name = O_STR(sp, O_SHELL); 12819304Speter else 12919304Speter ++name; 130254225Speter execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL); 13119304Speter msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s"); 13219304Speter _exit(127); 13319304Speter /* NOTREACHED */ 13419304Speter default: /* Parent. */ 13519304Speter return (proc_wait(sp, (long)pid, cmd, 0, 0)); 13619304Speter } 13719304Speter /* NOTREACHED */ 13819304Speter} 13919304Speter 14019304Speter/* 14119304Speter * proc_wait -- 14219304Speter * Wait for one of the processes. 14319304Speter * 14419304Speter * !!! 14519304Speter * The pid_t type varies in size from a short to a long depending on the 14619304Speter * system. It has to be cast into something or the standard promotion 14719304Speter * rules get you. I'm using a long based on the belief that nobody is 14819304Speter * going to make it unsigned and it's unlikely to be a quad. 14919304Speter * 15019304Speter * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int)); 15119304Speter */ 15219304Speterint 153254225Speterproc_wait(SCR *sp, long int pid, const char *cmd, int silent, int okpipe) 15419304Speter{ 15519304Speter size_t len; 15619304Speter int nf, pstat; 15719304Speter char *p; 15819304Speter 15919304Speter /* Wait for the utility, ignoring interruptions. */ 16019304Speter for (;;) { 16119304Speter errno = 0; 16219304Speter if (waitpid((pid_t)pid, &pstat, 0) != -1) 16319304Speter break; 16419304Speter if (errno != EINTR) { 16519304Speter msgq(sp, M_SYSERR, "waitpid"); 16619304Speter return (1); 16719304Speter } 16819304Speter } 16919304Speter 17019304Speter /* 17119304Speter * Display the utility's exit status. Ignore SIGPIPE from the 17219304Speter * parent-writer, as that only means that the utility chose to 17319304Speter * exit before reading all of its input. 17419304Speter */ 17519304Speter if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) { 176254225Speter for (; cmdskip(*cmd); ++cmd); 17719304Speter p = msg_print(sp, cmd, &nf); 17819304Speter len = strlen(p); 17919304Speter msgq(sp, M_ERR, "%.*s%s: received signal: %s%s", 180254225Speter (int)MIN(len, 20), p, len > 20 ? " ..." : "", 18119304Speter sigmsg(WTERMSIG(pstat)), 18219304Speter WCOREDUMP(pstat) ? "; core dumped" : ""); 18319304Speter if (nf) 18419304Speter FREE_SPACE(sp, p, 0); 18519304Speter return (1); 18619304Speter } 18719304Speter 18819304Speter if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) { 18919304Speter /* 19019304Speter * Remain silent for "normal" errors when doing shell file 19119304Speter * name expansions, they almost certainly indicate nothing 19219304Speter * more than a failure to match. 19319304Speter * 19419304Speter * Remain silent for vi read filter errors. It's historic 19519304Speter * practice. 19619304Speter */ 19719304Speter if (!silent) { 198254225Speter for (; cmdskip(*cmd); ++cmd); 19919304Speter p = msg_print(sp, cmd, &nf); 20019304Speter len = strlen(p); 20119304Speter msgq(sp, M_ERR, "%.*s%s: exited with status %d", 202254225Speter (int)MIN(len, 20), p, len > 20 ? " ..." : "", 20319304Speter WEXITSTATUS(pstat)); 20419304Speter if (nf) 20519304Speter FREE_SPACE(sp, p, 0); 20619304Speter } 20719304Speter return (1); 20819304Speter } 20919304Speter return (0); 21019304Speter} 21119304Speter 21219304Speter/* 21319304Speter * sigmsg -- 21419304Speter * Return a pointer to a message describing a signal. 21519304Speter */ 21619304Speterstatic const char * 217254225Spetersigmsg(int signo) 21819304Speter{ 21919304Speter static char buf[40]; 220254225Speter char *message; 22119304Speter 222254225Speter /* POSIX.1-2008 leaves strsignal(3)'s return value unspecified. */ 223254225Speter if ((message = strsignal(signo)) != NULL) 224254225Speter return message; 22519304Speter (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo); 22619304Speter return (buf); 22719304Speter} 228