148255Sbostic /*-
2*63046Sbostic * Copyright (c) 1980, 1993
3*63046Sbostic * The Regents of the University of California. All rights reserved.
448255Sbostic *
548255Sbostic * %sccs.include.proprietary.c%
621667Sdist */
721667Sdist
821667Sdist #ifndef lint
9*63046Sbostic static char sccsid[] = "@(#)ex_unix.c 8.1 (Berkeley) 06/09/93";
1048255Sbostic #endif /* not lint */
1121667Sdist
12536Smark #include "ex.h"
13536Smark #include "ex_temp.h"
14536Smark #include "ex_tty.h"
15536Smark #include "ex_vis.h"
1635292Skarels #include <sys/wait.h>
17536Smark
18536Smark /*
19536Smark * Unix escapes, filtering
20536Smark */
21536Smark
22536Smark /*
23536Smark * First part of a shell escape,
24536Smark * parse the line, expanding # and % and ! and printing if implied.
25536Smark */
unix0(warn)26536Smark unix0(warn)
27536Smark bool warn;
28536Smark {
29536Smark register char *up, *fp;
30536Smark register short c;
31536Smark char printub, puxb[UXBSIZE + sizeof (int)];
32536Smark
33536Smark printub = 0;
34536Smark CP(puxb, uxb);
3530596Sconrad c = ex_getchar();
36536Smark if (c == '\n' || c == EOF)
37536Smark error("Incomplete shell escape command@- use 'shell' to get a shell");
38536Smark up = uxb;
39536Smark do {
40536Smark switch (c) {
41536Smark
42536Smark case '\\':
43536Smark if (any(peekchar(), "%#!"))
4430596Sconrad c = ex_getchar();
45536Smark default:
46536Smark if (up >= &uxb[UXBSIZE]) {
47536Smark tunix:
48536Smark uxb[0] = 0;
49536Smark error("Command too long");
50536Smark }
51536Smark *up++ = c;
52536Smark break;
53536Smark
54536Smark case '!':
55536Smark fp = puxb;
56536Smark if (*fp == 0) {
57536Smark uxb[0] = 0;
58536Smark error("No previous command@to substitute for !");
59536Smark }
60536Smark printub++;
61536Smark while (*fp) {
62536Smark if (up >= &uxb[UXBSIZE])
63536Smark goto tunix;
64536Smark *up++ = *fp++;
65536Smark }
66536Smark break;
67536Smark
68536Smark case '#':
69536Smark fp = altfile;
70536Smark if (*fp == 0) {
71536Smark uxb[0] = 0;
72536Smark error("No alternate filename@to substitute for #");
73536Smark }
74536Smark goto uexp;
75536Smark
76536Smark case '%':
77536Smark fp = savedfile;
78536Smark if (*fp == 0) {
79536Smark uxb[0] = 0;
80536Smark error("No filename@to substitute for %%");
81536Smark }
82536Smark uexp:
83536Smark printub++;
84536Smark while (*fp) {
85536Smark if (up >= &uxb[UXBSIZE])
86536Smark goto tunix;
87536Smark *up++ = *fp++ | QUOTE;
88536Smark }
89536Smark break;
90536Smark }
9130596Sconrad c = ex_getchar();
92536Smark } while (c == '"' || c == '|' || !endcmd(c));
93536Smark if (c == EOF)
94536Smark ungetchar(c);
95536Smark *up = 0;
96536Smark if (!inopen)
97536Smark resetflav();
98536Smark if (warn)
99536Smark ckaw();
100536Smark if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) {
101536Smark xchng = chng;
102536Smark vnfl();
10330596Sconrad ex_printf(mesg("[No write]|[No write since last change]"));
104536Smark noonl();
105536Smark flush();
106536Smark } else
107536Smark warn = 0;
108536Smark if (printub) {
109536Smark if (uxb[0] == 0)
110536Smark error("No previous command@to repeat");
111536Smark if (inopen) {
112536Smark splitw++;
113536Smark vclean();
114536Smark vgoto(WECHO, 0);
115536Smark }
116536Smark if (warn)
117536Smark vnfl();
118536Smark if (hush == 0)
119536Smark lprintf("!%s", uxb);
120536Smark if (inopen && Outchar != termchar) {
121536Smark vclreol();
122536Smark vgoto(WECHO, 0);
123536Smark } else
124536Smark putnl();
125536Smark flush();
126536Smark }
127536Smark }
128536Smark
129536Smark /*
130536Smark * Do the real work for execution of a shell escape.
131536Smark * Mode is like the number passed to open system calls
132536Smark * and indicates filtering. If input is implied, newstdin
133536Smark * must have been setup already.
134536Smark */
135536Smark ttymode
unixex(opt,up,newstdin,mode)136536Smark unixex(opt, up, newstdin, mode)
137536Smark char *opt, *up;
138536Smark int newstdin, mode;
139536Smark {
140536Smark int pvec[2];
141536Smark ttymode f;
142536Smark
143536Smark signal(SIGINT, SIG_IGN);
144864Smark #ifdef SIGTSTP
145536Smark if (dosusp)
146536Smark signal(SIGTSTP, SIG_DFL);
147536Smark #endif
148536Smark if (inopen)
149536Smark f = setty(normf);
150536Smark if ((mode & 1) && pipe(pvec) < 0) {
151536Smark /* Newstdin should be io so it will be closed */
152536Smark if (inopen)
15330596Sconrad ignore(setty(f));
154536Smark error("Can't make pipe for filter");
155536Smark }
156536Smark #ifndef VFORK
157536Smark pid = fork();
158536Smark #else
159536Smark pid = vfork();
160536Smark #endif
161536Smark if (pid < 0) {
162536Smark if (mode & 1) {
163536Smark close(pvec[0]);
164536Smark close(pvec[1]);
165536Smark }
166536Smark setrupt();
167536Smark error("No more processes");
168536Smark }
169536Smark if (pid == 0) {
17044576Smarc if (up) {
17144576Smarc register char *cp = up;
17244576Smarc while (*cp)
17344576Smarc *cp++ &= TRIM;
17444576Smarc }
175536Smark if (mode & 2) {
176536Smark close(0);
177536Smark dup(newstdin);
178536Smark close(newstdin);
179536Smark }
180536Smark if (mode & 1) {
181536Smark close(pvec[0]);
182536Smark close(1);
183536Smark dup(pvec[1]);
184536Smark if (inopen) {
185536Smark close(2);
186536Smark dup(1);
187536Smark }
188536Smark close(pvec[1]);
189536Smark }
190536Smark if (io)
191536Smark close(io);
192536Smark if (tfile)
193536Smark close(tfile);
19430596Sconrad #ifdef EXSTRINGS
195536Smark close(erfile);
196536Smark #endif
197536Smark signal(SIGHUP, oldhup);
198536Smark signal(SIGQUIT, oldquit);
199536Smark if (ruptible)
200536Smark signal(SIGINT, SIG_DFL);
201536Smark execl(svalue(SHELL), "sh", opt, up, (char *) 0);
20230596Sconrad ex_printf("No %s!\n", svalue(SHELL));
203536Smark error(NOSTR);
204536Smark }
205536Smark if (mode & 1) {
206536Smark io = pvec[0];
207536Smark close(pvec[1]);
208536Smark }
209536Smark if (newstdin)
210536Smark close(newstdin);
211536Smark return (f);
212536Smark }
213536Smark
214536Smark /*
215536Smark * Wait for the command to complete.
216536Smark * F is for restoration of tty mode if from open/visual.
217536Smark * C flags suppression of printing.
218536Smark */
unixwt(c,f)219536Smark unixwt(c, f)
220536Smark bool c;
221536Smark ttymode f;
222536Smark {
223536Smark
224536Smark waitfor();
225864Smark #ifdef SIGTSTP
226536Smark if (dosusp)
227536Smark signal(SIGTSTP, onsusp);
228536Smark #endif
229536Smark if (inopen)
23030596Sconrad ignore(setty(f));
231536Smark setrupt();
232536Smark if (!inopen && c && hush == 0) {
23330596Sconrad ex_printf("!\n");
234536Smark flush();
235536Smark termreset();
236536Smark gettmode();
237536Smark }
238536Smark }
239536Smark
240536Smark /*
241536Smark * Setup a pipeline for the filtration implied by mode
242536Smark * which is like a open number. If input is required to
243536Smark * the filter, then a child editor is created to write it.
244536Smark * If output is catch it from io which is created by unixex.
245536Smark */
filter(mode)246536Smark filter(mode)
247536Smark register int mode;
248536Smark {
249536Smark static int pvec[2];
25021692Sdist ttymode f; /* mjm: was register */
251536Smark register int lines = lineDOL();
25221692Sdist struct stat statb;
253536Smark
254536Smark mode++;
255536Smark if (mode & 2) {
256536Smark signal(SIGINT, SIG_IGN);
257536Smark if (pipe(pvec) < 0)
258536Smark error("Can't make pipe");
259536Smark pid = fork();
260536Smark io = pvec[0];
261536Smark if (pid < 0) {
262536Smark setrupt();
263536Smark close(pvec[1]);
264536Smark error("No more processes");
265536Smark }
266536Smark if (pid == 0) {
267536Smark setrupt();
268536Smark io = pvec[1];
269536Smark close(pvec[0]);
27021692Sdist putfile(1);
27130596Sconrad ex_exit(0);
272536Smark }
273536Smark close(pvec[1]);
274536Smark io = pvec[0];
275536Smark setrupt();
276536Smark }
277536Smark f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
278536Smark if (mode == 3) {
27930596Sconrad ex_delete(0);
280536Smark addr2 = addr1 - 1;
281536Smark }
282536Smark if (mode & 1) {
283536Smark if(FIXUNDO)
284536Smark undap1 = undap2 = addr2+1;
28521692Sdist if (fstat(io, &statb) < 0)
28621692Sdist bsize = LBSIZE;
28721692Sdist else {
28821692Sdist bsize = statb.st_blksize;
28921692Sdist if (bsize <= 0)
29021692Sdist bsize = LBSIZE;
29121692Sdist }
292536Smark ignore(append(getfile, addr2));
29321692Sdist #ifdef TRACE
29421692Sdist if (trace)
29521692Sdist vudump("after append in filter");
29621692Sdist #endif
297536Smark }
298536Smark close(io);
299536Smark io = -1;
300536Smark unixwt(!inopen, f);
301536Smark netchHAD(lines);
302536Smark }
303536Smark
304536Smark /*
305536Smark * Set up to do a recover, getting io to be a pipe from
306536Smark * the recover process.
307536Smark */
recover()308536Smark recover()
309536Smark {
310536Smark static int pvec[2];
311536Smark
312536Smark if (pipe(pvec) < 0)
313536Smark error(" Can't make pipe for recovery");
314536Smark pid = fork();
315536Smark io = pvec[0];
316536Smark if (pid < 0) {
317536Smark close(pvec[1]);
318536Smark error(" Can't fork to execute recovery");
319536Smark }
320536Smark if (pid == 0) {
321536Smark close(2);
322536Smark dup(1);
323536Smark close(1);
324536Smark dup(pvec[1]);
325536Smark close(pvec[1]);
32644576Smarc execl(_PATH_EXRECOVER, "exrecover", svalue(DIRECTORY),
32744576Smarc file, (char *) 0);
328536Smark close(1);
329536Smark dup(2);
330536Smark error(" No recovery routine");
331536Smark }
332536Smark close(pvec[1]);
333536Smark }
334536Smark
335536Smark /*
336536Smark * Wait for the process (pid an external) to complete.
337536Smark */
waitfor()338536Smark waitfor()
339536Smark {
34035292Skarels union wait stat, pstat;
34135292Skarels int wpid;
342536Smark
34335292Skarels pstat.w_status = 0;
34425248Sbloom do {
34546826Sbostic wpid = wait((int *)&stat);
34635292Skarels if (wpid == pid) {
34735292Skarels pstat = stat;
34835292Skarels rpid = wpid;
34935292Skarels }
35035292Skarels } while (wpid != -1);
35135292Skarels
35235292Skarels if (WIFEXITED(pstat))
35335292Skarels status = pstat.w_retcode;
35435292Skarels else {
35535292Skarels ex_printf("%d: terminated abnormally: %s ",
35635292Skarels pid, sys_siglist[pstat.w_termsig]);
35735292Skarels if (pstat.w_coredump)
35835292Skarels ex_printf("(core dumped) ");
35935292Skarels if (!inopen)
36035292Skarels ex_printf("\r\n");
36135292Skarels status = pstat.w_termsig;
36235292Skarels }
363536Smark }
364536Smark
365536Smark /*
366536Smark * The end of a recover operation. If the process
367536Smark * exits non-zero, force not edited; otherwise force
368536Smark * a write.
369536Smark */
revocer()370536Smark revocer()
371536Smark {
372536Smark
373536Smark waitfor();
374536Smark if (pid == rpid && status != 0)
375536Smark edited = 0;
376536Smark else
377536Smark change();
378536Smark }
379