xref: /csrg-svn/usr.bin/ex/ex_unix.c (revision 35292)
121667Sdist /*
221667Sdist  * Copyright (c) 1980 Regents of the University of California.
321667Sdist  * All rights reserved.  The Berkeley software License Agreement
421667Sdist  * specifies the terms and conditions for redistribution.
521667Sdist  */
621667Sdist 
721667Sdist #ifndef lint
8*35292Skarels static char *sccsid = "@(#)ex_unix.c	7.8 (Berkeley) 07/28/88";
921667Sdist #endif not lint
1021667Sdist 
11536Smark #include "ex.h"
12536Smark #include "ex_temp.h"
13536Smark #include "ex_tty.h"
14536Smark #include "ex_vis.h"
15*35292Skarels #include <sys/wait.h>
16536Smark 
17536Smark /*
18536Smark  * Unix escapes, filtering
19536Smark  */
20536Smark 
21536Smark /*
22536Smark  * First part of a shell escape,
23536Smark  * parse the line, expanding # and % and ! and printing if implied.
24536Smark  */
25536Smark unix0(warn)
26536Smark 	bool warn;
27536Smark {
28536Smark 	register char *up, *fp;
29536Smark 	register short c;
30536Smark 	char printub, puxb[UXBSIZE + sizeof (int)];
31536Smark 
32536Smark 	printub = 0;
33536Smark 	CP(puxb, uxb);
3430596Sconrad 	c = ex_getchar();
35536Smark 	if (c == '\n' || c == EOF)
36536Smark 		error("Incomplete shell escape command@- use 'shell' to get a shell");
37536Smark 	up = uxb;
38536Smark 	do {
39536Smark 		switch (c) {
40536Smark 
41536Smark 		case '\\':
42536Smark 			if (any(peekchar(), "%#!"))
4330596Sconrad 				c = ex_getchar();
44536Smark 		default:
45536Smark 			if (up >= &uxb[UXBSIZE]) {
46536Smark tunix:
47536Smark 				uxb[0] = 0;
48536Smark 				error("Command too long");
49536Smark 			}
50536Smark 			*up++ = c;
51536Smark 			break;
52536Smark 
53536Smark 		case '!':
54536Smark 			fp = puxb;
55536Smark 			if (*fp == 0) {
56536Smark 				uxb[0] = 0;
57536Smark 				error("No previous command@to substitute for !");
58536Smark 			}
59536Smark 			printub++;
60536Smark 			while (*fp) {
61536Smark 				if (up >= &uxb[UXBSIZE])
62536Smark 					goto tunix;
63536Smark 				*up++ = *fp++;
64536Smark 			}
65536Smark 			break;
66536Smark 
67536Smark 		case '#':
68536Smark 			fp = altfile;
69536Smark 			if (*fp == 0) {
70536Smark 				uxb[0] = 0;
71536Smark 				error("No alternate filename@to substitute for #");
72536Smark 			}
73536Smark 			goto uexp;
74536Smark 
75536Smark 		case '%':
76536Smark 			fp = savedfile;
77536Smark 			if (*fp == 0) {
78536Smark 				uxb[0] = 0;
79536Smark 				error("No filename@to substitute for %%");
80536Smark 			}
81536Smark uexp:
82536Smark 			printub++;
83536Smark 			while (*fp) {
84536Smark 				if (up >= &uxb[UXBSIZE])
85536Smark 					goto tunix;
86536Smark 				*up++ = *fp++ | QUOTE;
87536Smark 			}
88536Smark 			break;
89536Smark 		}
9030596Sconrad 		c = ex_getchar();
91536Smark 	} while (c == '"' || c == '|' || !endcmd(c));
92536Smark 	if (c == EOF)
93536Smark 		ungetchar(c);
94536Smark 	*up = 0;
95536Smark 	if (!inopen)
96536Smark 		resetflav();
97536Smark 	if (warn)
98536Smark 		ckaw();
99536Smark 	if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) {
100536Smark 		xchng = chng;
101536Smark 		vnfl();
10230596Sconrad 		ex_printf(mesg("[No write]|[No write since last change]"));
103536Smark 		noonl();
104536Smark 		flush();
105536Smark 	} else
106536Smark 		warn = 0;
107536Smark 	if (printub) {
108536Smark 		if (uxb[0] == 0)
109536Smark 			error("No previous command@to repeat");
110536Smark 		if (inopen) {
111536Smark 			splitw++;
112536Smark 			vclean();
113536Smark 			vgoto(WECHO, 0);
114536Smark 		}
115536Smark 		if (warn)
116536Smark 			vnfl();
117536Smark 		if (hush == 0)
118536Smark 			lprintf("!%s", uxb);
119536Smark 		if (inopen && Outchar != termchar) {
120536Smark 			vclreol();
121536Smark 			vgoto(WECHO, 0);
122536Smark 		} else
123536Smark 			putnl();
124536Smark 		flush();
125536Smark 	}
126536Smark }
127536Smark 
128536Smark /*
129536Smark  * Do the real work for execution of a shell escape.
130536Smark  * Mode is like the number passed to open system calls
131536Smark  * and indicates filtering.  If input is implied, newstdin
132536Smark  * must have been setup already.
133536Smark  */
134536Smark ttymode
135536Smark unixex(opt, up, newstdin, mode)
136536Smark 	char *opt, *up;
137536Smark 	int newstdin, mode;
138536Smark {
139536Smark 	int pvec[2];
140536Smark 	ttymode f;
141536Smark 
142536Smark 	signal(SIGINT, SIG_IGN);
143864Smark #ifdef SIGTSTP
144536Smark 	if (dosusp)
145536Smark 		signal(SIGTSTP, SIG_DFL);
146536Smark #endif
147536Smark 	if (inopen)
148536Smark 		f = setty(normf);
149536Smark 	if ((mode & 1) && pipe(pvec) < 0) {
150536Smark 		/* Newstdin should be io so it will be closed */
151536Smark 		if (inopen)
15230596Sconrad 			ignore(setty(f));
153536Smark 		error("Can't make pipe for filter");
154536Smark 	}
155536Smark #ifndef VFORK
156536Smark 	pid = fork();
157536Smark #else
158536Smark 	pid = vfork();
159536Smark #endif
160536Smark 	if (pid < 0) {
161536Smark 		if (mode & 1) {
162536Smark 			close(pvec[0]);
163536Smark 			close(pvec[1]);
164536Smark 		}
165536Smark 		setrupt();
166536Smark 		error("No more processes");
167536Smark 	}
168536Smark 	if (pid == 0) {
169536Smark 		if (mode & 2) {
170536Smark 			close(0);
171536Smark 			dup(newstdin);
172536Smark 			close(newstdin);
173536Smark 		}
174536Smark 		if (mode & 1) {
175536Smark 			close(pvec[0]);
176536Smark 			close(1);
177536Smark 			dup(pvec[1]);
178536Smark 			if (inopen) {
179536Smark 				close(2);
180536Smark 				dup(1);
181536Smark 			}
182536Smark 			close(pvec[1]);
183536Smark 		}
184536Smark 		if (io)
185536Smark 			close(io);
186536Smark 		if (tfile)
187536Smark 			close(tfile);
18830596Sconrad #ifdef EXSTRINGS
189536Smark 		close(erfile);
190536Smark #endif
191536Smark 		signal(SIGHUP, oldhup);
192536Smark 		signal(SIGQUIT, oldquit);
193536Smark 		if (ruptible)
194536Smark 			signal(SIGINT, SIG_DFL);
195536Smark 		execl(svalue(SHELL), "sh", opt, up, (char *) 0);
19630596Sconrad 		ex_printf("No %s!\n", svalue(SHELL));
197536Smark 		error(NOSTR);
198536Smark 	}
199536Smark 	if (mode & 1) {
200536Smark 		io = pvec[0];
201536Smark 		close(pvec[1]);
202536Smark 	}
203536Smark 	if (newstdin)
204536Smark 		close(newstdin);
205536Smark 	return (f);
206536Smark }
207536Smark 
208536Smark /*
209536Smark  * Wait for the command to complete.
210536Smark  * F is for restoration of tty mode if from open/visual.
211536Smark  * C flags suppression of printing.
212536Smark  */
213536Smark unixwt(c, f)
214536Smark 	bool c;
215536Smark 	ttymode f;
216536Smark {
217536Smark 
218536Smark 	waitfor();
219864Smark #ifdef SIGTSTP
220536Smark 	if (dosusp)
221536Smark 		signal(SIGTSTP, onsusp);
222536Smark #endif
223536Smark 	if (inopen)
22430596Sconrad 		ignore(setty(f));
225536Smark 	setrupt();
226536Smark 	if (!inopen && c && hush == 0) {
22730596Sconrad 		ex_printf("!\n");
228536Smark 		flush();
229536Smark 		termreset();
230536Smark 		gettmode();
231536Smark 	}
232536Smark }
233536Smark 
234536Smark /*
235536Smark  * Setup a pipeline for the filtration implied by mode
236536Smark  * which is like a open number.  If input is required to
237536Smark  * the filter, then a child editor is created to write it.
238536Smark  * If output is catch it from io which is created by unixex.
239536Smark  */
240536Smark filter(mode)
241536Smark 	register int mode;
242536Smark {
243536Smark 	static int pvec[2];
24421692Sdist 	ttymode f;	/* mjm: was register */
245536Smark 	register int lines = lineDOL();
24621692Sdist 	struct stat statb;
247536Smark 
248536Smark 	mode++;
249536Smark 	if (mode & 2) {
250536Smark 		signal(SIGINT, SIG_IGN);
251536Smark 		if (pipe(pvec) < 0)
252536Smark 			error("Can't make pipe");
253536Smark 		pid = fork();
254536Smark 		io = pvec[0];
255536Smark 		if (pid < 0) {
256536Smark 			setrupt();
257536Smark 			close(pvec[1]);
258536Smark 			error("No more processes");
259536Smark 		}
260536Smark 		if (pid == 0) {
261536Smark 			setrupt();
262536Smark 			io = pvec[1];
263536Smark 			close(pvec[0]);
26421692Sdist 			putfile(1);
26530596Sconrad 			ex_exit(0);
266536Smark 		}
267536Smark 		close(pvec[1]);
268536Smark 		io = pvec[0];
269536Smark 		setrupt();
270536Smark 	}
271536Smark 	f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
272536Smark 	if (mode == 3) {
27330596Sconrad 		ex_delete(0);
274536Smark 		addr2 = addr1 - 1;
275536Smark 	}
276536Smark 	if (mode & 1) {
277536Smark 		if(FIXUNDO)
278536Smark 			undap1 = undap2 = addr2+1;
27921692Sdist 		if (fstat(io, &statb) < 0)
28021692Sdist 			bsize = LBSIZE;
28121692Sdist 		else {
28221692Sdist 			bsize = statb.st_blksize;
28321692Sdist 			if (bsize <= 0)
28421692Sdist 				bsize = LBSIZE;
28521692Sdist 		}
286536Smark 		ignore(append(getfile, addr2));
28721692Sdist #ifdef TRACE
28821692Sdist 		if (trace)
28921692Sdist 			vudump("after append in filter");
29021692Sdist #endif
291536Smark 	}
292536Smark 	close(io);
293536Smark 	io = -1;
294536Smark 	unixwt(!inopen, f);
295536Smark 	netchHAD(lines);
296536Smark }
297536Smark 
298536Smark /*
299536Smark  * Set up to do a recover, getting io to be a pipe from
300536Smark  * the recover process.
301536Smark  */
302536Smark recover()
303536Smark {
304536Smark 	static int pvec[2];
305536Smark 
306536Smark 	if (pipe(pvec) < 0)
307536Smark 		error(" Can't make pipe for recovery");
308536Smark 	pid = fork();
309536Smark 	io = pvec[0];
310536Smark 	if (pid < 0) {
311536Smark 		close(pvec[1]);
312536Smark 		error(" Can't fork to execute recovery");
313536Smark 	}
314536Smark 	if (pid == 0) {
315536Smark 		close(2);
316536Smark 		dup(1);
317536Smark 		close(1);
318536Smark 		dup(pvec[1]);
319536Smark 	        close(pvec[1]);
320536Smark 		execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0);
321536Smark 		close(1);
322536Smark 		dup(2);
323536Smark 		error(" No recovery routine");
324536Smark 	}
325536Smark 	close(pvec[1]);
326536Smark }
327536Smark 
328536Smark /*
329536Smark  * Wait for the process (pid an external) to complete.
330536Smark  */
331536Smark waitfor()
332536Smark {
333*35292Skarels 	union wait stat, pstat;
334*35292Skarels 	int wpid;
335*35292Skarels 	extern char *sys_siglist[];
336536Smark 
337*35292Skarels 	pstat.w_status = 0;
33825248Sbloom 	do {
339*35292Skarels 		wpid = wait(&stat);
340*35292Skarels 		if (wpid == pid) {
341*35292Skarels 			pstat = stat;
342*35292Skarels 			rpid = wpid;
343*35292Skarels 		}
344*35292Skarels 	} while (wpid != -1);
345*35292Skarels 
346*35292Skarels 	if (WIFEXITED(pstat))
347*35292Skarels 		status = pstat.w_retcode;
348*35292Skarels 	else {
349*35292Skarels 		ex_printf("%d: terminated abnormally: %s ",
350*35292Skarels 		    pid, sys_siglist[pstat.w_termsig]);
351*35292Skarels 		if (pstat.w_coredump)
352*35292Skarels 			ex_printf("(core dumped) ");
353*35292Skarels 		if (!inopen)
354*35292Skarels 			ex_printf("\r\n");
355*35292Skarels 		status = pstat.w_termsig;
356*35292Skarels 	}
357536Smark }
358536Smark 
359536Smark /*
360536Smark  * The end of a recover operation.  If the process
361536Smark  * exits non-zero, force not edited; otherwise force
362536Smark  * a write.
363536Smark  */
364536Smark revocer()
365536Smark {
366536Smark 
367536Smark 	waitfor();
368536Smark 	if (pid == rpid && status != 0)
369536Smark 		edited = 0;
370536Smark 	else
371536Smark 		change();
372536Smark }
373