Commit | Line | Data |
---|---|---|
19d73a0e DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
7 | #ifndef lint | |
fa3a10f3 | 8 | static char *sccsid = "@(#)ex_unix.c 7.8 (Berkeley) %G%"; |
19d73a0e DF |
9 | #endif not lint |
10 | ||
9cf6814f MH |
11 | #include "ex.h" |
12 | #include "ex_temp.h" | |
13 | #include "ex_tty.h" | |
14 | #include "ex_vis.h" | |
fa3a10f3 | 15 | #include <sys/wait.h> |
9cf6814f MH |
16 | |
17 | /* | |
18 | * Unix escapes, filtering | |
19 | */ | |
20 | ||
21 | /* | |
22 | * First part of a shell escape, | |
23 | * parse the line, expanding # and % and ! and printing if implied. | |
24 | */ | |
25 | unix0(warn) | |
26 | bool warn; | |
27 | { | |
28 | register char *up, *fp; | |
29 | register short c; | |
30 | char printub, puxb[UXBSIZE + sizeof (int)]; | |
31 | ||
32 | printub = 0; | |
33 | CP(puxb, uxb); | |
5a6c967e | 34 | c = ex_getchar(); |
9cf6814f MH |
35 | if (c == '\n' || c == EOF) |
36 | error("Incomplete shell escape command@- use 'shell' to get a shell"); | |
37 | up = uxb; | |
38 | do { | |
39 | switch (c) { | |
40 | ||
41 | case '\\': | |
42 | if (any(peekchar(), "%#!")) | |
5a6c967e | 43 | c = ex_getchar(); |
9cf6814f MH |
44 | default: |
45 | if (up >= &uxb[UXBSIZE]) { | |
46 | tunix: | |
47 | uxb[0] = 0; | |
48 | error("Command too long"); | |
49 | } | |
50 | *up++ = c; | |
51 | break; | |
52 | ||
53 | case '!': | |
54 | fp = puxb; | |
55 | if (*fp == 0) { | |
56 | uxb[0] = 0; | |
57 | error("No previous command@to substitute for !"); | |
58 | } | |
59 | printub++; | |
60 | while (*fp) { | |
61 | if (up >= &uxb[UXBSIZE]) | |
62 | goto tunix; | |
63 | *up++ = *fp++; | |
64 | } | |
65 | break; | |
66 | ||
67 | case '#': | |
68 | fp = altfile; | |
69 | if (*fp == 0) { | |
70 | uxb[0] = 0; | |
71 | error("No alternate filename@to substitute for #"); | |
72 | } | |
73 | goto uexp; | |
74 | ||
75 | case '%': | |
76 | fp = savedfile; | |
77 | if (*fp == 0) { | |
78 | uxb[0] = 0; | |
79 | error("No filename@to substitute for %%"); | |
80 | } | |
81 | uexp: | |
82 | printub++; | |
83 | while (*fp) { | |
84 | if (up >= &uxb[UXBSIZE]) | |
85 | goto tunix; | |
86 | *up++ = *fp++ | QUOTE; | |
87 | } | |
88 | break; | |
89 | } | |
5a6c967e | 90 | c = ex_getchar(); |
9cf6814f MH |
91 | } while (c == '"' || c == '|' || !endcmd(c)); |
92 | if (c == EOF) | |
93 | ungetchar(c); | |
94 | *up = 0; | |
95 | if (!inopen) | |
96 | resetflav(); | |
97 | if (warn) | |
98 | ckaw(); | |
99 | if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) { | |
100 | xchng = chng; | |
101 | vnfl(); | |
5a6c967e | 102 | ex_printf(mesg("[No write]|[No write since last change]")); |
9cf6814f MH |
103 | noonl(); |
104 | flush(); | |
105 | } else | |
106 | warn = 0; | |
107 | if (printub) { | |
108 | if (uxb[0] == 0) | |
109 | error("No previous command@to repeat"); | |
110 | if (inopen) { | |
111 | splitw++; | |
112 | vclean(); | |
113 | vgoto(WECHO, 0); | |
114 | } | |
115 | if (warn) | |
116 | vnfl(); | |
117 | if (hush == 0) | |
118 | lprintf("!%s", uxb); | |
119 | if (inopen && Outchar != termchar) { | |
120 | vclreol(); | |
121 | vgoto(WECHO, 0); | |
122 | } else | |
123 | putnl(); | |
124 | flush(); | |
125 | } | |
126 | } | |
127 | ||
128 | /* | |
129 | * Do the real work for execution of a shell escape. | |
130 | * Mode is like the number passed to open system calls | |
131 | * and indicates filtering. If input is implied, newstdin | |
132 | * must have been setup already. | |
133 | */ | |
134 | ttymode | |
135 | unixex(opt, up, newstdin, mode) | |
136 | char *opt, *up; | |
137 | int newstdin, mode; | |
138 | { | |
139 | int pvec[2]; | |
140 | ttymode f; | |
141 | ||
142 | signal(SIGINT, SIG_IGN); | |
bdbbb330 | 143 | #ifdef SIGTSTP |
9cf6814f MH |
144 | if (dosusp) |
145 | signal(SIGTSTP, SIG_DFL); | |
146 | #endif | |
147 | if (inopen) | |
148 | f = setty(normf); | |
149 | if ((mode & 1) && pipe(pvec) < 0) { | |
150 | /* Newstdin should be io so it will be closed */ | |
151 | if (inopen) | |
5a6c967e | 152 | ignore(setty(f)); |
9cf6814f MH |
153 | error("Can't make pipe for filter"); |
154 | } | |
155 | #ifndef VFORK | |
156 | pid = fork(); | |
157 | #else | |
158 | pid = vfork(); | |
159 | #endif | |
160 | if (pid < 0) { | |
161 | if (mode & 1) { | |
162 | close(pvec[0]); | |
163 | close(pvec[1]); | |
164 | } | |
165 | setrupt(); | |
166 | error("No more processes"); | |
167 | } | |
168 | if (pid == 0) { | |
169 | if (mode & 2) { | |
170 | close(0); | |
171 | dup(newstdin); | |
172 | close(newstdin); | |
173 | } | |
174 | if (mode & 1) { | |
175 | close(pvec[0]); | |
176 | close(1); | |
177 | dup(pvec[1]); | |
178 | if (inopen) { | |
179 | close(2); | |
180 | dup(1); | |
181 | } | |
182 | close(pvec[1]); | |
183 | } | |
184 | if (io) | |
185 | close(io); | |
186 | if (tfile) | |
187 | close(tfile); | |
5a6c967e | 188 | #ifdef EXSTRINGS |
9cf6814f MH |
189 | close(erfile); |
190 | #endif | |
191 | signal(SIGHUP, oldhup); | |
192 | signal(SIGQUIT, oldquit); | |
193 | if (ruptible) | |
194 | signal(SIGINT, SIG_DFL); | |
195 | execl(svalue(SHELL), "sh", opt, up, (char *) 0); | |
5a6c967e | 196 | ex_printf("No %s!\n", svalue(SHELL)); |
9cf6814f MH |
197 | error(NOSTR); |
198 | } | |
199 | if (mode & 1) { | |
200 | io = pvec[0]; | |
201 | close(pvec[1]); | |
202 | } | |
203 | if (newstdin) | |
204 | close(newstdin); | |
205 | return (f); | |
206 | } | |
207 | ||
208 | /* | |
209 | * Wait for the command to complete. | |
210 | * F is for restoration of tty mode if from open/visual. | |
211 | * C flags suppression of printing. | |
212 | */ | |
213 | unixwt(c, f) | |
214 | bool c; | |
215 | ttymode f; | |
216 | { | |
217 | ||
218 | waitfor(); | |
bdbbb330 | 219 | #ifdef SIGTSTP |
9cf6814f MH |
220 | if (dosusp) |
221 | signal(SIGTSTP, onsusp); | |
222 | #endif | |
223 | if (inopen) | |
5a6c967e | 224 | ignore(setty(f)); |
9cf6814f MH |
225 | setrupt(); |
226 | if (!inopen && c && hush == 0) { | |
5a6c967e | 227 | ex_printf("!\n"); |
9cf6814f MH |
228 | flush(); |
229 | termreset(); | |
230 | gettmode(); | |
231 | } | |
232 | } | |
233 | ||
234 | /* | |
235 | * Setup a pipeline for the filtration implied by mode | |
236 | * which is like a open number. If input is required to | |
237 | * the filter, then a child editor is created to write it. | |
238 | * If output is catch it from io which is created by unixex. | |
239 | */ | |
240 | filter(mode) | |
241 | register int mode; | |
242 | { | |
243 | static int pvec[2]; | |
299f2784 | 244 | ttymode f; /* mjm: was register */ |
9cf6814f | 245 | register int lines = lineDOL(); |
4e3d2679 | 246 | struct stat statb; |
9cf6814f MH |
247 | |
248 | mode++; | |
249 | if (mode & 2) { | |
250 | signal(SIGINT, SIG_IGN); | |
251 | if (pipe(pvec) < 0) | |
252 | error("Can't make pipe"); | |
253 | pid = fork(); | |
254 | io = pvec[0]; | |
255 | if (pid < 0) { | |
256 | setrupt(); | |
257 | close(pvec[1]); | |
258 | error("No more processes"); | |
259 | } | |
260 | if (pid == 0) { | |
261 | setrupt(); | |
262 | io = pvec[1]; | |
263 | close(pvec[0]); | |
299f2784 | 264 | putfile(1); |
5a6c967e | 265 | ex_exit(0); |
9cf6814f MH |
266 | } |
267 | close(pvec[1]); | |
268 | io = pvec[0]; | |
269 | setrupt(); | |
270 | } | |
271 | f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); | |
272 | if (mode == 3) { | |
5a6c967e | 273 | ex_delete(0); |
9cf6814f MH |
274 | addr2 = addr1 - 1; |
275 | } | |
276 | if (mode & 1) { | |
277 | if(FIXUNDO) | |
278 | undap1 = undap2 = addr2+1; | |
4e3d2679 JB |
279 | if (fstat(io, &statb) < 0) |
280 | bsize = LBSIZE; | |
281 | else { | |
282 | bsize = statb.st_blksize; | |
283 | if (bsize <= 0) | |
284 | bsize = LBSIZE; | |
285 | } | |
9cf6814f | 286 | ignore(append(getfile, addr2)); |
04379bab MH |
287 | #ifdef TRACE |
288 | if (trace) | |
289 | vudump("after append in filter"); | |
290 | #endif | |
9cf6814f MH |
291 | } |
292 | close(io); | |
293 | io = -1; | |
294 | unixwt(!inopen, f); | |
295 | netchHAD(lines); | |
296 | } | |
297 | ||
298 | /* | |
299 | * Set up to do a recover, getting io to be a pipe from | |
300 | * the recover process. | |
301 | */ | |
302 | recover() | |
303 | { | |
304 | static int pvec[2]; | |
305 | ||
306 | if (pipe(pvec) < 0) | |
307 | error(" Can't make pipe for recovery"); | |
308 | pid = fork(); | |
309 | io = pvec[0]; | |
310 | if (pid < 0) { | |
311 | close(pvec[1]); | |
312 | error(" Can't fork to execute recovery"); | |
313 | } | |
314 | if (pid == 0) { | |
315 | close(2); | |
316 | dup(1); | |
317 | close(1); | |
318 | dup(pvec[1]); | |
319 | close(pvec[1]); | |
320 | execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); | |
321 | close(1); | |
322 | dup(2); | |
323 | error(" No recovery routine"); | |
324 | } | |
325 | close(pvec[1]); | |
326 | } | |
327 | ||
328 | /* | |
329 | * Wait for the process (pid an external) to complete. | |
330 | */ | |
331 | waitfor() | |
332 | { | |
fa3a10f3 MK |
333 | union wait stat, pstat; |
334 | int wpid; | |
335 | extern char *sys_siglist[]; | |
9cf6814f | 336 | |
fa3a10f3 | 337 | pstat.w_status = 0; |
8c2c0ab9 | 338 | do { |
fa3a10f3 MK |
339 | wpid = wait(&stat); |
340 | if (wpid == pid) { | |
341 | pstat = stat; | |
342 | rpid = wpid; | |
343 | } | |
344 | } while (wpid != -1); | |
345 | ||
346 | if (WIFEXITED(pstat)) | |
347 | status = pstat.w_retcode; | |
348 | else { | |
349 | ex_printf("%d: terminated abnormally: %s ", | |
350 | pid, sys_siglist[pstat.w_termsig]); | |
351 | if (pstat.w_coredump) | |
352 | ex_printf("(core dumped) "); | |
353 | if (!inopen) | |
354 | ex_printf("\r\n"); | |
355 | status = pstat.w_termsig; | |
356 | } | |
9cf6814f MH |
357 | } |
358 | ||
359 | /* | |
360 | * The end of a recover operation. If the process | |
361 | * exits non-zero, force not edited; otherwise force | |
362 | * a write. | |
363 | */ | |
364 | revocer() | |
365 | { | |
366 | ||
367 | waitfor(); | |
368 | if (pid == rpid && status != 0) | |
369 | edited = 0; | |
370 | else | |
371 | change(); | |
372 | } |