summaryrefslogtreecommitdiff
path: root/usr.bin/vi/ex/ex_shell.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>1996-05-22 11:37:15 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>1996-05-22 11:37:15 +0000
commit0157a77a51c5e35e093ae03581f66dea010edcc8 (patch)
tree5e8bd32aa4d2b5ed37b7cf3ad26e8bdfc7f20a04 /usr.bin/vi/ex/ex_shell.c
parent806021be093ad00ce2022a532c0f4cc99b0065ac (diff)
new vi
Diffstat (limited to 'usr.bin/vi/ex/ex_shell.c')
-rw-r--r--usr.bin/vi/ex/ex_shell.c382
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);
}