| File: | src/usr.bin/vi/build/../ex/ex_shell.c |
| Warning: | line 117, column 15 This function call is prohibited after a successful vfork |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ex_shell.c,v 1.15 2015/03/28 12:54:37 bcallah Exp $ */ | |||
| 2 | ||||
| 3 | /*- | |||
| 4 | * Copyright (c) 1992, 1993, 1994 | |||
| 5 | * The Regents of the University of California. All rights reserved. | |||
| 6 | * Copyright (c) 1992, 1993, 1994, 1995, 1996 | |||
| 7 | * Keith Bostic. All rights reserved. | |||
| 8 | * | |||
| 9 | * See the LICENSE file for redistribution information. | |||
| 10 | */ | |||
| 11 | ||||
| 12 | #include "config.h" | |||
| 13 | ||||
| 14 | #include <sys/queue.h> | |||
| 15 | #include <sys/wait.h> | |||
| 16 | ||||
| 17 | #include <bitstring.h> | |||
| 18 | #include <ctype.h> | |||
| 19 | #include <errno(*__errno()).h> | |||
| 20 | #include <limits.h> | |||
| 21 | #include <signal.h> | |||
| 22 | #include <stdio.h> | |||
| 23 | #include <stdlib.h> | |||
| 24 | #include <string.h> | |||
| 25 | #include <unistd.h> | |||
| 26 | ||||
| 27 | #include "../common/common.h" | |||
| 28 | ||||
| 29 | #define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b)) | |||
| 30 | ||||
| 31 | /* | |||
| 32 | * ex_shell -- :sh[ell] | |||
| 33 | * Invoke the program named in the SHELL environment variable | |||
| 34 | * with the argument -i. | |||
| 35 | * | |||
| 36 | * PUBLIC: int ex_shell(SCR *, EXCMD *); | |||
| 37 | */ | |||
| 38 | int | |||
| 39 | ex_shell(SCR *sp, EXCMD *cmdp) | |||
| 40 | { | |||
| 41 | int rval; | |||
| 42 | char buf[PATH_MAX1024]; | |||
| 43 | ||||
| 44 | /* We'll need a shell. */ | |||
| 45 | if (opts_empty(sp, O_SHELL, 0)) | |||
| ||||
| 46 | return (1); | |||
| 47 | ||||
| 48 | /* | |||
| 49 | * XXX | |||
| 50 | * Assumes all shells use -i. | |||
| 51 | */ | |||
| 52 | (void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str)); | |||
| 53 | ||||
| 54 | /* Restore the window name. */ | |||
| 55 | (void)sp->gp->scr_rename(sp, NULL((void *)0), 0); | |||
| 56 | ||||
| 57 | /* If we're still in a vi screen, move out explicitly. */ | |||
| 58 | rval = ex_exec_proc(sp, cmdp, buf, NULL((void *)0), !F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010)))); | |||
| 59 | ||||
| 60 | /* Set the window name. */ | |||
| 61 | (void)sp->gp->scr_rename(sp, sp->frp->name, 1); | |||
| 62 | ||||
| 63 | /* | |||
| 64 | * !!! | |||
| 65 | * Historically, vi didn't require a continue message after the | |||
| 66 | * return of the shell. Match it. | |||
| 67 | */ | |||
| 68 | F_SET(sp, SC_EX_WAIT_NO)(((sp)->flags) |= ((0x00080000))); | |||
| 69 | ||||
| 70 | return (rval); | |||
| 71 | } | |||
| 72 | ||||
| 73 | /* | |||
| 74 | * ex_exec_proc -- | |||
| 75 | * Run a separate process. | |||
| 76 | * | |||
| 77 | * PUBLIC: int ex_exec_proc(SCR *, EXCMD *, char *, const char *, int); | |||
| 78 | */ | |||
| 79 | int | |||
| 80 | ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg, | |||
| 81 | int need_newline) | |||
| 82 | { | |||
| 83 | GS *gp; | |||
| 84 | const char *name; | |||
| 85 | pid_t pid; | |||
| 86 | ||||
| 87 | gp = sp->gp; | |||
| 88 | ||||
| 89 | /* We'll need a shell. */ | |||
| 90 | if (opts_empty(sp, O_SHELL, 0)) | |||
| 91 | return (1); | |||
| 92 | ||||
| 93 | /* Enter ex mode. */ | |||
| 94 | if (F_ISSET(sp, SC_VI)(((sp)->flags) & ((0x00000002)))) { | |||
| 95 | if (gp->scr_screen(sp, SC_EX0x00000001)) { | |||
| 96 | ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON); | |||
| 97 | return (1); | |||
| 98 | } | |||
| 99 | (void)gp->scr_attr(sp, SA_ALTERNATE, 0); | |||
| 100 | F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE)(((sp)->flags) |= ((0x00000004 | 0x00000010))); | |||
| 101 | } | |||
| 102 | ||||
| 103 | /* Put out additional newline, message. */ | |||
| 104 | if (need_newline
| |||
| 105 | (void)ex_puts(sp, "\n"); | |||
| 106 | if (msg
| |||
| 107 | (void)ex_puts(sp, msg); | |||
| 108 | (void)ex_puts(sp, "\n"); | |||
| 109 | } | |||
| 110 | (void)ex_fflush(sp); | |||
| 111 | ||||
| 112 | switch (pid = vfork()) { | |||
| 113 | case -1: /* Error. */ | |||
| 114 | msgq(sp, M_SYSERR, "vfork"); | |||
| 115 | return (1); | |||
| 116 | case 0: /* Utility. */ | |||
| 117 | if ((name = strrchr(O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str), '/')) == NULL((void *)0)) | |||
| ||||
| 118 | name = O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str); | |||
| 119 | else | |||
| 120 | ++name; | |||
| 121 | execl(O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str), name, "-c", cmd, (char *)NULL((void *)0)); | |||
| 122 | msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL)((((&((sp))->opts[((O_SHELL))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_SHELL))].o_cur .val].o_cur.str : ((sp))->opts[((O_SHELL))].o_cur.str), "execl: %s"); | |||
| 123 | _exit(127); | |||
| 124 | /* NOTREACHED */ | |||
| 125 | default: /* Parent. */ | |||
| 126 | return (proc_wait(sp, pid, cmd, 0, 0)); | |||
| 127 | } | |||
| 128 | /* NOTREACHED */ | |||
| 129 | } | |||
| 130 | ||||
| 131 | /* | |||
| 132 | * proc_wait -- | |||
| 133 | * Wait for one of the processes. | |||
| 134 | * | |||
| 135 | * !!! | |||
| 136 | * The pid_t type varies in size from a short to a long depending on the | |||
| 137 | * system. It has to be cast into something or the standard promotion | |||
| 138 | * rules get you. I'm using a long based on the belief that nobody is | |||
| 139 | * going to make it unsigned and it's unlikely to be a quad. | |||
| 140 | * | |||
| 141 | * PUBLIC: int proc_wait(SCR *, pid_t, const char *, int, int); | |||
| 142 | */ | |||
| 143 | int | |||
| 144 | proc_wait(SCR *sp, pid_t pid, const char *cmd, int silent, int okpipe) | |||
| 145 | { | |||
| 146 | size_t len; | |||
| 147 | int nf, pstat; | |||
| 148 | char *p; | |||
| 149 | ||||
| 150 | /* Wait for the utility, ignoring interruptions. */ | |||
| 151 | for (;;) { | |||
| 152 | errno(*__errno()) = 0; | |||
| 153 | if (waitpid(pid, &pstat, 0) != -1) | |||
| 154 | break; | |||
| 155 | if (errno(*__errno()) != EINTR4) { | |||
| 156 | msgq(sp, M_SYSERR, "waitpid"); | |||
| 157 | return (1); | |||
| 158 | } | |||
| 159 | } | |||
| 160 | ||||
| 161 | /* | |||
| 162 | * Display the utility's exit status. Ignore SIGPIPE from the | |||
| 163 | * parent-writer, as that only means that the utility chose to | |||
| 164 | * exit before reading all of its input. | |||
| 165 | */ | |||
| 166 | if (WIFSIGNALED(pstat)(((pstat) & 0177) != 0177 && ((pstat) & 0177) != 0) && (!okpipe || WTERMSIG(pstat)(((pstat) & 0177)) != SIGPIPE13)) { | |||
| 167 | for (; isblank(*cmd); ++cmd); | |||
| 168 | p = msg_print(sp, cmd, &nf); | |||
| 169 | len = strlen(p); | |||
| 170 | msgq(sp, M_ERR, "%.*s%s: received signal: %s%s", | |||
| 171 | MINIMUM(len, 20)(((len) < (20)) ? (len) : (20)), p, len > 20 ? " ..." : "", | |||
| 172 | strsignal(WTERMSIG(pstat)(((pstat) & 0177))), | |||
| 173 | WCOREDUMP(pstat)((pstat) & 0200) ? "; core dumped" : ""); | |||
| 174 | if (nf) | |||
| 175 | FREE_SPACE(sp, p, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp ) (((L__gp)->flags) &= ~((0x0100))); else free(p); }; | |||
| 176 | return (1); | |||
| 177 | } | |||
| 178 | ||||
| 179 | if (WIFEXITED(pstat)(((pstat) & 0177) == 0) && WEXITSTATUS(pstat)(int)(((unsigned)(pstat) >> 8) & 0xff)) { | |||
| 180 | /* | |||
| 181 | * Remain silent for "normal" errors when doing shell file | |||
| 182 | * name expansions, they almost certainly indicate nothing | |||
| 183 | * more than a failure to match. | |||
| 184 | * | |||
| 185 | * Remain silent for vi read filter errors. It's historic | |||
| 186 | * practice. | |||
| 187 | */ | |||
| 188 | if (!silent) { | |||
| 189 | for (; isblank(*cmd); ++cmd); | |||
| 190 | p = msg_print(sp, cmd, &nf); | |||
| 191 | len = strlen(p); | |||
| 192 | msgq(sp, M_ERR, "%.*s%s: exited with status %d", | |||
| 193 | MINIMUM(len, 20)(((len) < (20)) ? (len) : (20)), p, len > 20 ? " ..." : "", | |||
| 194 | WEXITSTATUS(pstat)(int)(((unsigned)(pstat) >> 8) & 0xff)); | |||
| 195 | if (nf) | |||
| 196 | FREE_SPACE(sp, p, 0){ GS *L__gp = (sp) == ((void *)0) ? ((void *)0) : (sp)->gp ; if (L__gp != ((void *)0) && (p) == L__gp->tmp_bp ) (((L__gp)->flags) &= ~((0x0100))); else free(p); }; | |||
| 197 | } | |||
| 198 | return (1); | |||
| 199 | } | |||
| 200 | return (0); | |||
| 201 | } |