xref: /csrg-svn/usr.bin/ex/ex_unix.c (revision 63046)
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