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