diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-05-22 11:37:15 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1996-05-22 11:37:15 +0000 |
commit | 0157a77a51c5e35e093ae03581f66dea010edcc8 (patch) | |
tree | 5e8bd32aa4d2b5ed37b7cf3ad26e8bdfc7f20a04 /usr.bin/vi/ex/ex_shell.c | |
parent | 806021be093ad00ce2022a532c0f4cc99b0065ac (diff) |
new vi
Diffstat (limited to 'usr.bin/vi/ex/ex_shell.c')
-rw-r--r-- | usr.bin/vi/ex/ex_shell.c | 382 |
1 files changed, 300 insertions, 82 deletions
diff --git a/usr.bin/vi/ex/ex_shell.c b/usr.bin/vi/ex/ex_shell.c index b6f9aedd3f2..abb016f3d88 100644 --- a/usr.bin/vi/ex/ex_shell.c +++ b/usr.bin/vi/ex/ex_shell.c @@ -1,150 +1,368 @@ /*- * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. + * Copyright (c) 1992, 1993, 1994, 1995, 1996 + * Keith Bostic. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * See the LICENSE file for redistribution information. */ +#include "config.h" + #ifndef lint -static char sccsid[] = "@(#)ex_shell.c 8.26 (Berkeley) 8/17/94"; +static const char sccsid[] = "@(#)ex_shell.c 10.33 (Berkeley) 4/27/96"; #endif /* not lint */ #include <sys/param.h> #include <sys/queue.h> -#include <sys/time.h> +#include <sys/wait.h> #include <bitstring.h> #include <errno.h> #include <limits.h> #include <signal.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <termios.h> #include <unistd.h> -#include "compat.h" -#include <db.h> -#include <regex.h> +#include "../common/common.h" -#include "vi.h" -#include "excmd.h" -#include "../svi/svi_screen.h" +static const char *sigmsg __P((int)); /* * ex_shell -- :sh[ell] * Invoke the program named in the SHELL environment variable * with the argument -i. + * + * PUBLIC: int ex_shell __P((SCR *, EXCMD *)); */ int -ex_shell(sp, ep, cmdp) +ex_shell(sp, cmdp) SCR *sp; - EXF *ep; - EXCMDARG *cmdp; + EXCMD *cmdp; { + int rval; char buf[MAXPATHLEN]; + /* We'll need a shell. */ + if (opts_empty(sp, O_SHELL, 0)) + return (1); + + /* + * XXX + * Assumes all shells use -i. + */ (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL)); - return (ex_exec_proc(sp, buf, "\n", NULL)); + + /* If we're stil in a vi screen, move out explicitly. */ + rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE)); + + /* + * !!! + * Historically, vi didn't require a continue message after the + * return of the shell. Match it. + */ + F_SET(sp, SC_EX_DONTWAIT); + + return (rval); } /* * ex_exec_proc -- * Run a separate process. + * + * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, char *, const char *, int)); */ int -ex_exec_proc(sp, cmd, p1, p2) +ex_exec_proc(sp, cmdp, cmd, msg, need_newline) SCR *sp; - char *cmd, *p1, *p2; + EXCMD *cmdp; + char *cmd; + const char *msg; + int need_newline; { const char *name; pid_t pid; - int rval, teardown; - /* Clear the rest of the screen. */ - if (sp->s_clear(sp)) + /* We'll need a shell. */ + if (opts_empty(sp, O_SHELL, 0)) return (1); - /* Save ex/vi terminal settings, and restore the original ones. */ - teardown = !ex_sleave(sp); - - /* - * Flush waiting messages (autowrite, for example) so the output - * matches historic practice. - */ - (void)sex_refresh(sp, sp->ep); + /* Enter ex mode. */ + if (F_ISSET(sp, SC_VI)) { + if (sp->gp->scr_screen(sp, SC_EX)) { + ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON); + return (1); + } + F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE); + } - /* Put out various messages. */ - if (p1 != NULL) - (void)write(STDOUT_FILENO, p1, strlen(p1)); - if (p2 != NULL) - (void)write(STDOUT_FILENO, p2, strlen(p2)); + /* Put out additional newline, message. */ + if (need_newline) + (void)ex_puts(sp, "\n"); + if (msg != NULL) { + (void)ex_puts(sp, msg); + (void)ex_puts(sp, "\n"); + } + (void)ex_fflush(sp); - SIGBLOCK(sp->gp); switch (pid = vfork()) { case -1: /* Error. */ - SIGUNBLOCK(sp->gp); - msgq(sp, M_SYSERR, "vfork"); - rval = 1; - break; + return (1); case 0: /* Utility. */ - /* The utility has default signal behavior. */ - sig_end(); - if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL) name = O_STR(sp, O_SHELL); else ++name; execl(O_STR(sp, O_SHELL), name, "-c", cmd, NULL); - msgq(sp, M_ERR, "Error: execl: %s: %s", - O_STR(sp, O_SHELL), strerror(errno)); + msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s"); _exit(127); /* NOTREACHED */ default: /* Parent. */ - SIGUNBLOCK(sp->gp); - - rval = proc_wait(sp, (long)pid, cmd, 0); - break; + return (proc_wait(sp, (long)pid, cmd, 0, 0)); } + /* NOTREACHED */ +} - /* Restore ex/vi terminal settings. */ - if (teardown) - ex_rleave(sp); +/* + * proc_wait -- + * Wait for one of the processes. + * + * !!! + * The pid_t type varies in size from a short to a long depending on the + * system. It has to be cast into something or the standard promotion + * rules get you. I'm using a long based on the belief that nobody is + * going to make it unsigned and it's unlikely to be a quad. + * + * PUBLIC: int proc_wait __P((SCR *, long, const char *, int, int)); + */ +int +proc_wait(sp, pid, cmd, silent, okpipe) + SCR *sp; + long pid; + const char *cmd; + int silent, okpipe; +{ + size_t len; + int nf, pstat; + char *p; + + /* Wait for the utility, ignoring interruptions. */ + for (;;) { + errno = 0; + if (waitpid((pid_t)pid, &pstat, 0) != -1) + break; + if (errno != EINTR) { + msgq(sp, M_SYSERR, "waitpid"); + return (1); + } + } /* - * XXX - * Stat of the tty structures (see ex_sleave, ex_rleave) only give - * us 1-second resolution on the tty changes. A fast '!' command, - * e.g. ":!pwd" can beat us to the refresh. When there's better - * resolution from the stat(2) timers, this can go away. + * Display the utility's exit status. Ignore SIGPIPE from the + * parent-writer, as that only means that the utility chose to + * exit before reading all of its input. */ - F_SET(sp, S_REFRESH); + if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) { + for (; isblank(*cmd); ++cmd); + p = msg_print(sp, cmd, &nf); + len = strlen(p); + msgq(sp, M_ERR, "%.*s%s: received signal: %s%s", + MIN(len, 20), p, len > 20 ? " ..." : "", + sigmsg(WTERMSIG(pstat)), + WCOREDUMP(pstat) ? "; core dumped" : ""); + if (nf) + FREE_SPACE(sp, p, 0); + return (1); + } - return (rval); + if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) { + /* + * Remain silent for "normal" errors when doing shell file + * name expansions, they almost certainly indicate nothing + * more than a failure to match. + * + * Remain silent for vi read filter errors. It's historic + * practice. + */ + if (!silent) { + for (; isblank(*cmd); ++cmd); + p = msg_print(sp, cmd, &nf); + len = strlen(p); + msgq(sp, M_ERR, "%.*s%s: exited with status %d", + MIN(len, 20), p, len > 20 ? " ..." : "", + WEXITSTATUS(pstat)); + if (nf) + FREE_SPACE(sp, p, 0); + } + return (1); + } + return (0); +} + +/* + * XXX + * The sys_siglist[] table in the C library has this information, but there's + * no portable way to get to it. (Believe me, I tried.) + */ +typedef struct _sigs { + int number; /* signal number */ + char *message; /* related message */ +} SIGS; + +SIGS const sigs[] = { +#ifdef SIGABRT + SIGABRT, "Abort trap", +#endif +#ifdef SIGALRM + SIGALRM, "Alarm clock", +#endif +#ifdef SIGBUS + SIGBUS, "Bus error", +#endif +#ifdef SIGCLD + SIGCLD, "Child exited or stopped", +#endif +#ifdef SIGCHLD + SIGCHLD, "Child exited", +#endif +#ifdef SIGCONT + SIGCONT, "Continued", +#endif +#ifdef SIGDANGER + SIGDANGER, "System crash imminent", +#endif +#ifdef SIGEMT + SIGEMT, "EMT trap", +#endif +#ifdef SIGFPE + SIGFPE, "Floating point exception", +#endif +#ifdef SIGGRANT + SIGGRANT, "HFT monitor mode granted", +#endif +#ifdef SIGHUP + SIGHUP, "Hangup", +#endif +#ifdef SIGILL + SIGILL, "Illegal instruction", +#endif +#ifdef SIGINFO + SIGINFO, "Information request", +#endif +#ifdef SIGINT + SIGINT, "Interrupt", +#endif +#ifdef SIGIO + SIGIO, "I/O possible", +#endif +#ifdef SIGIOT + SIGIOT, "IOT trap", +#endif +#ifdef SIGKILL + SIGKILL, "Killed", +#endif +#ifdef SIGLOST + SIGLOST, "Record lock", +#endif +#ifdef SIGMIGRATE + SIGMIGRATE, "Migrate process to another CPU", +#endif +#ifdef SIGMSG + SIGMSG, "HFT input data pending", +#endif +#ifdef SIGPIPE + SIGPIPE, "Broken pipe", +#endif +#ifdef SIGPOLL + SIGPOLL, "I/O possible", +#endif +#ifdef SIGPRE + SIGPRE, "Programming error", +#endif +#ifdef SIGPROF + SIGPROF, "Profiling timer expired", +#endif +#ifdef SIGPWR + SIGPWR, "Power failure imminent", +#endif +#ifdef SIGRETRACT + SIGRETRACT, "HFT monitor mode retracted", +#endif +#ifdef SIGQUIT + SIGQUIT, "Quit", +#endif +#ifdef SIGSAK + SIGSAK, "Secure Attention Key", +#endif +#ifdef SIGSEGV + SIGSEGV, "Segmentation fault", +#endif +#ifdef SIGSOUND + SIGSOUND, "HFT sound sequence completed", +#endif +#ifdef SIGSTOP + SIGSTOP, "Suspended (signal)", +#endif +#ifdef SIGSYS + SIGSYS, "Bad system call", +#endif +#ifdef SIGTERM + SIGTERM, "Terminated", +#endif +#ifdef SIGTRAP + SIGTRAP, "Trace/BPT trap", +#endif +#ifdef SIGTSTP + SIGTSTP, "Suspended", +#endif +#ifdef SIGTTIN + SIGTTIN, "Stopped (tty input)", +#endif +#ifdef SIGTTOU + SIGTTOU, "Stopped (tty output)", +#endif +#ifdef SIGURG + SIGURG, "Urgent I/O condition", +#endif +#ifdef SIGUSR1 + SIGUSR1, "User defined signal 1", +#endif +#ifdef SIGUSR2 + SIGUSR2, "User defined signal 2", +#endif +#ifdef SIGVTALRM + SIGVTALRM, "Virtual timer expired", +#endif +#ifdef SIGWINCH + SIGWINCH, "Window size changes", +#endif +#ifdef SIGXCPU + SIGXCPU, "Cputime limit exceeded", +#endif +#ifdef SIGXFSZ + SIGXFSZ, "Filesize limit exceeded", +#endif +}; + +/* + * sigmsg -- + * Return a pointer to a message describing a signal. + */ +static const char * +sigmsg(signo) + int signo; +{ + static char buf[40]; + const SIGS *sigp; + int n; + + for (n = 0, + sigp = &sigs[0]; n < sizeof(sigs) / sizeof(sigs[0]); ++n, ++sigp) + if (sigp->number == signo) + return (sigp->message); + (void)snprintf(buf, sizeof(buf), "Unknown signal: %d", signo); + return (buf); } |