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