xref: /csrg-svn/usr.bin/ex/ex_unix.c (revision 21667)
1*21667Sdist /*
2*21667Sdist  * Copyright (c) 1980 Regents of the University of California.
3*21667Sdist  * All rights reserved.  The Berkeley software License Agreement
4*21667Sdist  * specifies the terms and conditions for redistribution.
5*21667Sdist  */
6*21667Sdist 
7*21667Sdist #ifndef lint
8*21667Sdist static char sccsid[] = "@(#)ex_unix.c	5.2.1.1 (Berkeley) 05/31/85";
9*21667Sdist #endif not lint
10*21667Sdist 
11536Smark #include "ex.h"
12536Smark #include "ex_temp.h"
13536Smark #include "ex_tty.h"
14536Smark #include "ex_vis.h"
15536Smark 
16536Smark /*
17536Smark  * Unix escapes, filtering
18536Smark  */
19536Smark 
20536Smark /*
21536Smark  * First part of a shell escape,
22536Smark  * parse the line, expanding # and % and ! and printing if implied.
23536Smark  */
24536Smark unix0(warn)
25536Smark 	bool warn;
26536Smark {
27536Smark 	register char *up, *fp;
28536Smark 	register short c;
29536Smark 	char printub, puxb[UXBSIZE + sizeof (int)];
30536Smark 
31536Smark 	printub = 0;
32536Smark 	CP(puxb, uxb);
33536Smark 	c = getchar();
34536Smark 	if (c == '\n' || c == EOF)
35536Smark 		error("Incomplete shell escape command@- use 'shell' to get a shell");
36536Smark 	up = uxb;
37536Smark 	do {
38536Smark 		switch (c) {
39536Smark 
40536Smark 		case '\\':
41536Smark 			if (any(peekchar(), "%#!"))
42536Smark 				c = getchar();
43536Smark 		default:
44536Smark 			if (up >= &uxb[UXBSIZE]) {
45536Smark tunix:
46536Smark 				uxb[0] = 0;
47536Smark 				error("Command too long");
48536Smark 			}
49536Smark 			*up++ = c;
50536Smark 			break;
51536Smark 
52536Smark 		case '!':
53536Smark 			fp = puxb;
54536Smark 			if (*fp == 0) {
55536Smark 				uxb[0] = 0;
56536Smark 				error("No previous command@to substitute for !");
57536Smark 			}
58536Smark 			printub++;
59536Smark 			while (*fp) {
60536Smark 				if (up >= &uxb[UXBSIZE])
61536Smark 					goto tunix;
62536Smark 				*up++ = *fp++;
63536Smark 			}
64536Smark 			break;
65536Smark 
66536Smark 		case '#':
67536Smark 			fp = altfile;
68536Smark 			if (*fp == 0) {
69536Smark 				uxb[0] = 0;
70536Smark 				error("No alternate filename@to substitute for #");
71536Smark 			}
72536Smark 			goto uexp;
73536Smark 
74536Smark 		case '%':
75536Smark 			fp = savedfile;
76536Smark 			if (*fp == 0) {
77536Smark 				uxb[0] = 0;
78536Smark 				error("No filename@to substitute for %%");
79536Smark 			}
80536Smark uexp:
81536Smark 			printub++;
82536Smark 			while (*fp) {
83536Smark 				if (up >= &uxb[UXBSIZE])
84536Smark 					goto tunix;
85536Smark 				*up++ = *fp++ | QUOTE;
86536Smark 			}
87536Smark 			break;
88536Smark 		}
89536Smark 		c = getchar();
90536Smark 	} while (c == '"' || c == '|' || !endcmd(c));
91536Smark 	if (c == EOF)
92536Smark 		ungetchar(c);
93536Smark 	*up = 0;
94536Smark 	if (!inopen)
95536Smark 		resetflav();
96536Smark 	if (warn)
97536Smark 		ckaw();
98536Smark 	if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) {
99536Smark 		xchng = chng;
100536Smark 		vnfl();
101536Smark 		printf(mesg("[No write]|[No write since last change]"));
102536Smark 		noonl();
103536Smark 		flush();
104536Smark 	} else
105536Smark 		warn = 0;
106536Smark 	if (printub) {
107536Smark 		if (uxb[0] == 0)
108536Smark 			error("No previous command@to repeat");
109536Smark 		if (inopen) {
110536Smark 			splitw++;
111536Smark 			vclean();
112536Smark 			vgoto(WECHO, 0);
113536Smark 		}
114536Smark 		if (warn)
115536Smark 			vnfl();
116536Smark 		if (hush == 0)
117536Smark 			lprintf("!%s", uxb);
118536Smark 		if (inopen && Outchar != termchar) {
119536Smark 			vclreol();
120536Smark 			vgoto(WECHO, 0);
121536Smark 		} else
122536Smark 			putnl();
123536Smark 		flush();
124536Smark 	}
125536Smark }
126536Smark 
127536Smark /*
128536Smark  * Do the real work for execution of a shell escape.
129536Smark  * Mode is like the number passed to open system calls
130536Smark  * and indicates filtering.  If input is implied, newstdin
131536Smark  * must have been setup already.
132536Smark  */
133536Smark ttymode
134536Smark unixex(opt, up, newstdin, mode)
135536Smark 	char *opt, *up;
136536Smark 	int newstdin, mode;
137536Smark {
138536Smark 	int pvec[2];
139536Smark 	ttymode f;
140536Smark 
141536Smark 	signal(SIGINT, SIG_IGN);
142864Smark #ifdef SIGTSTP
143536Smark 	if (dosusp)
144536Smark 		signal(SIGTSTP, SIG_DFL);
145536Smark #endif
146536Smark 	if (inopen)
147536Smark 		f = setty(normf);
148536Smark 	if ((mode & 1) && pipe(pvec) < 0) {
149536Smark 		/* Newstdin should be io so it will be closed */
150536Smark 		if (inopen)
151536Smark 			setty(f);
152536Smark 		error("Can't make pipe for filter");
153536Smark 	}
154536Smark #ifndef VFORK
155536Smark 	pid = fork();
156536Smark #else
157536Smark 	pid = vfork();
158536Smark #endif
159536Smark 	if (pid < 0) {
160536Smark 		if (mode & 1) {
161536Smark 			close(pvec[0]);
162536Smark 			close(pvec[1]);
163536Smark 		}
164536Smark 		setrupt();
165536Smark 		error("No more processes");
166536Smark 	}
167536Smark 	if (pid == 0) {
168536Smark 		if (mode & 2) {
169536Smark 			close(0);
170536Smark 			dup(newstdin);
171536Smark 			close(newstdin);
172536Smark 		}
173536Smark 		if (mode & 1) {
174536Smark 			close(pvec[0]);
175536Smark 			close(1);
176536Smark 			dup(pvec[1]);
177536Smark 			if (inopen) {
178536Smark 				close(2);
179536Smark 				dup(1);
180536Smark 			}
181536Smark 			close(pvec[1]);
182536Smark 		}
183536Smark 		if (io)
184536Smark 			close(io);
185536Smark 		if (tfile)
186536Smark 			close(tfile);
187536Smark #ifndef VMUNIX
188536Smark 		close(erfile);
189536Smark #endif
190536Smark 		signal(SIGHUP, oldhup);
191536Smark 		signal(SIGQUIT, oldquit);
192536Smark 		if (ruptible)
193536Smark 			signal(SIGINT, SIG_DFL);
194536Smark 		execl(svalue(SHELL), "sh", opt, up, (char *) 0);
195536Smark 		printf("No %s!\n", svalue(SHELL));
196536Smark 		error(NOSTR);
197536Smark 	}
198536Smark 	if (mode & 1) {
199536Smark 		io = pvec[0];
200536Smark 		close(pvec[1]);
201536Smark 	}
202536Smark 	if (newstdin)
203536Smark 		close(newstdin);
204536Smark 	return (f);
205536Smark }
206536Smark 
207536Smark /*
208536Smark  * Wait for the command to complete.
209536Smark  * F is for restoration of tty mode if from open/visual.
210536Smark  * C flags suppression of printing.
211536Smark  */
212536Smark unixwt(c, f)
213536Smark 	bool c;
214536Smark 	ttymode f;
215536Smark {
216536Smark 
217536Smark 	waitfor();
218864Smark #ifdef SIGTSTP
219536Smark 	if (dosusp)
220536Smark 		signal(SIGTSTP, onsusp);
221536Smark #endif
222536Smark 	if (inopen)
223536Smark 		setty(f);
224536Smark 	setrupt();
225536Smark 	if (!inopen && c && hush == 0) {
226536Smark 		printf("!\n");
227536Smark 		flush();
228536Smark 		termreset();
229536Smark 		gettmode();
230536Smark 	}
231536Smark }
232536Smark 
233536Smark /*
234536Smark  * Setup a pipeline for the filtration implied by mode
235536Smark  * which is like a open number.  If input is required to
236536Smark  * the filter, then a child editor is created to write it.
237536Smark  * If output is catch it from io which is created by unixex.
238536Smark  */
239536Smark filter(mode)
240536Smark 	register int mode;
241536Smark {
242536Smark 	static int pvec[2];
243*21667Sdist 	register ttymode f;
244536Smark 	register int lines = lineDOL();
245536Smark 
246536Smark 	mode++;
247536Smark 	if (mode & 2) {
248536Smark 		signal(SIGINT, SIG_IGN);
249536Smark 		if (pipe(pvec) < 0)
250536Smark 			error("Can't make pipe");
251536Smark 		pid = fork();
252536Smark 		io = pvec[0];
253536Smark 		if (pid < 0) {
254536Smark 			setrupt();
255536Smark 			close(pvec[1]);
256536Smark 			error("No more processes");
257536Smark 		}
258536Smark 		if (pid == 0) {
259536Smark 			setrupt();
260536Smark 			io = pvec[1];
261536Smark 			close(pvec[0]);
262*21667Sdist 			putfile();
263536Smark 			exit(0);
264536Smark 		}
265536Smark 		close(pvec[1]);
266536Smark 		io = pvec[0];
267536Smark 		setrupt();
268536Smark 	}
269536Smark 	f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
270536Smark 	if (mode == 3) {
271536Smark 		delete(0);
272536Smark 		addr2 = addr1 - 1;
273536Smark 	}
274536Smark 	if (mode & 1) {
275536Smark 		if(FIXUNDO)
276536Smark 			undap1 = undap2 = addr2+1;
277536Smark 		ignore(append(getfile, addr2));
278536Smark 	}
279536Smark 	close(io);
280536Smark 	io = -1;
281536Smark 	unixwt(!inopen, f);
282536Smark 	netchHAD(lines);
283536Smark }
284536Smark 
285536Smark /*
286536Smark  * Set up to do a recover, getting io to be a pipe from
287536Smark  * the recover process.
288536Smark  */
289536Smark recover()
290536Smark {
291536Smark 	static int pvec[2];
292536Smark 
293536Smark 	if (pipe(pvec) < 0)
294536Smark 		error(" Can't make pipe for recovery");
295536Smark 	pid = fork();
296536Smark 	io = pvec[0];
297536Smark 	if (pid < 0) {
298536Smark 		close(pvec[1]);
299536Smark 		error(" Can't fork to execute recovery");
300536Smark 	}
301536Smark 	if (pid == 0) {
302536Smark 		close(2);
303536Smark 		dup(1);
304536Smark 		close(1);
305536Smark 		dup(pvec[1]);
306536Smark 	        close(pvec[1]);
307536Smark 		execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0);
308536Smark 		close(1);
309536Smark 		dup(2);
310536Smark 		error(" No recovery routine");
311536Smark 	}
312536Smark 	close(pvec[1]);
313536Smark }
314536Smark 
315536Smark /*
316536Smark  * Wait for the process (pid an external) to complete.
317536Smark  */
318536Smark waitfor()
319536Smark {
320536Smark 
321536Smark 	do
322536Smark 		rpid = wait(&status);
323536Smark 	while (rpid != pid && rpid != -1);
324536Smark 	status = (status >> 8) & 0377;
325536Smark }
326536Smark 
327536Smark /*
328536Smark  * The end of a recover operation.  If the process
329536Smark  * exits non-zero, force not edited; otherwise force
330536Smark  * a write.
331536Smark  */
332536Smark revocer()
333536Smark {
334536Smark 
335536Smark 	waitfor();
336536Smark 	if (pid == rpid && status != 0)
337536Smark 		edited = 0;
338536Smark 	else
339536Smark 		change();
340536Smark }
341