new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / ex / ex_unix.c
CommitLineData
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
6c15a6c1 8static char *sccsid = "@(#)ex_unix.c 7.8 (Berkeley) 7/28/88";
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 */
25unix0(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]) {
46tunix:
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 }
81uexp:
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 */
134ttymode
135unixex(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) {
6c15a6c1
MT
169 if (up) {
170 register char *cp = up;
171 while (*cp)
172 *cp++ &= TRIM;
173 }
9cf6814f
MH
174 if (mode & 2) {
175 close(0);
176 dup(newstdin);
177 close(newstdin);
178 }
179 if (mode & 1) {
180 close(pvec[0]);
181 close(1);
182 dup(pvec[1]);
183 if (inopen) {
184 close(2);
185 dup(1);
186 }
187 close(pvec[1]);
188 }
189 if (io)
190 close(io);
191 if (tfile)
192 close(tfile);
5a6c967e 193#ifdef EXSTRINGS
9cf6814f
MH
194 close(erfile);
195#endif
196 signal(SIGHUP, oldhup);
197 signal(SIGQUIT, oldquit);
198 if (ruptible)
199 signal(SIGINT, SIG_DFL);
200 execl(svalue(SHELL), "sh", opt, up, (char *) 0);
5a6c967e 201 ex_printf("No %s!\n", svalue(SHELL));
9cf6814f
MH
202 error(NOSTR);
203 }
204 if (mode & 1) {
205 io = pvec[0];
206 close(pvec[1]);
207 }
208 if (newstdin)
209 close(newstdin);
210 return (f);
211}
212
213/*
214 * Wait for the command to complete.
215 * F is for restoration of tty mode if from open/visual.
216 * C flags suppression of printing.
217 */
218unixwt(c, f)
219 bool c;
220 ttymode f;
221{
222
223 waitfor();
bdbbb330 224#ifdef SIGTSTP
9cf6814f
MH
225 if (dosusp)
226 signal(SIGTSTP, onsusp);
227#endif
228 if (inopen)
5a6c967e 229 ignore(setty(f));
9cf6814f
MH
230 setrupt();
231 if (!inopen && c && hush == 0) {
5a6c967e 232 ex_printf("!\n");
9cf6814f
MH
233 flush();
234 termreset();
235 gettmode();
236 }
237}
238
239/*
240 * Setup a pipeline for the filtration implied by mode
241 * which is like a open number. If input is required to
242 * the filter, then a child editor is created to write it.
243 * If output is catch it from io which is created by unixex.
244 */
245filter(mode)
246 register int mode;
247{
248 static int pvec[2];
299f2784 249 ttymode f; /* mjm: was register */
9cf6814f 250 register int lines = lineDOL();
4e3d2679 251 struct stat statb;
9cf6814f
MH
252
253 mode++;
254 if (mode & 2) {
255 signal(SIGINT, SIG_IGN);
256 if (pipe(pvec) < 0)
257 error("Can't make pipe");
258 pid = fork();
259 io = pvec[0];
260 if (pid < 0) {
261 setrupt();
262 close(pvec[1]);
263 error("No more processes");
264 }
265 if (pid == 0) {
266 setrupt();
267 io = pvec[1];
268 close(pvec[0]);
299f2784 269 putfile(1);
5a6c967e 270 ex_exit(0);
9cf6814f
MH
271 }
272 close(pvec[1]);
273 io = pvec[0];
274 setrupt();
275 }
276 f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
277 if (mode == 3) {
5a6c967e 278 ex_delete(0);
9cf6814f
MH
279 addr2 = addr1 - 1;
280 }
281 if (mode & 1) {
282 if(FIXUNDO)
283 undap1 = undap2 = addr2+1;
4e3d2679
JB
284 if (fstat(io, &statb) < 0)
285 bsize = LBSIZE;
286 else {
287 bsize = statb.st_blksize;
288 if (bsize <= 0)
289 bsize = LBSIZE;
290 }
9cf6814f 291 ignore(append(getfile, addr2));
04379bab
MH
292#ifdef TRACE
293 if (trace)
294 vudump("after append in filter");
295#endif
9cf6814f
MH
296 }
297 close(io);
298 io = -1;
299 unixwt(!inopen, f);
300 netchHAD(lines);
301}
302
303/*
304 * Set up to do a recover, getting io to be a pipe from
305 * the recover process.
306 */
307recover()
308{
309 static int pvec[2];
310
311 if (pipe(pvec) < 0)
312 error(" Can't make pipe for recovery");
313 pid = fork();
314 io = pvec[0];
315 if (pid < 0) {
316 close(pvec[1]);
317 error(" Can't fork to execute recovery");
318 }
319 if (pid == 0) {
320 close(2);
321 dup(1);
322 close(1);
323 dup(pvec[1]);
324 close(pvec[1]);
6c15a6c1
MT
325 execl(_PATH_EXRECOVER, "exrecover", svalue(DIRECTORY),
326 file, (char *) 0);
9cf6814f
MH
327 close(1);
328 dup(2);
329 error(" No recovery routine");
330 }
331 close(pvec[1]);
332}
333
334/*
335 * Wait for the process (pid an external) to complete.
336 */
337waitfor()
338{
fa3a10f3
MK
339 union wait stat, pstat;
340 int wpid;
341 extern char *sys_siglist[];
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 */
370revocer()
371{
372
373 waitfor();
374 if (pid == rpid && status != 0)
375 edited = 0;
376 else
377 change();
378}