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