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