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 | } |