xref: /onnv-gate/usr/src/cmd/vi/port/ex_unix.c (revision 802:73b56fb6544b)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23500Sceastha  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /* Copyright (c) 1979 Regents of the University of California */
320Sstevel@tonic-gate 
330Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include "ex.h"
360Sstevel@tonic-gate #include "ex_temp.h"
370Sstevel@tonic-gate #include "ex_tty.h"
380Sstevel@tonic-gate #include "ex_vis.h"
390Sstevel@tonic-gate 
40*802Scf46844 extern int	getchar();
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  * Unix escapes, filtering
430Sstevel@tonic-gate  */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate /*
460Sstevel@tonic-gate  * First part of a shell escape,
470Sstevel@tonic-gate  * parse the line, expanding # and % and ! and printing if implied.
480Sstevel@tonic-gate  */
49500Sceastha void
50500Sceastha unix0(bool warn, int contcmd)
510Sstevel@tonic-gate {
52500Sceastha 	unsigned char *up, *fp;
53500Sceastha 	short c;
540Sstevel@tonic-gate 	char	multic[MB_LEN_MAX + 1];
550Sstevel@tonic-gate 	int	len;
56500Sceastha 	int	contread = 0;
570Sstevel@tonic-gate 	wchar_t	wc;
580Sstevel@tonic-gate 	unsigned char printub, puxb[UXBSIZE + sizeof (int)];
59500Sceastha 	const char	*specialchars = (contcmd ? "%#!\n" : "%#!");
600Sstevel@tonic-gate 
610Sstevel@tonic-gate 	printub = 0;
620Sstevel@tonic-gate 	CP(puxb, uxb);
630Sstevel@tonic-gate 	c = peekchar();
640Sstevel@tonic-gate 	if (c == '\n' || c == EOF) {
650Sstevel@tonic-gate 		(void) getchar();
660Sstevel@tonic-gate 		error(value(vi_TERSE) ?
670Sstevel@tonic-gate gettext("Incomplete shell escape command") :
680Sstevel@tonic-gate gettext("Incomplete shell escape command - use 'shell' to get a shell"));
690Sstevel@tonic-gate 	}
700Sstevel@tonic-gate 	up = (unsigned char *)uxb;
710Sstevel@tonic-gate 
720Sstevel@tonic-gate 	for (;;) {
730Sstevel@tonic-gate 		if (!isascii(c)) {
740Sstevel@tonic-gate 			if (c == EOF)
750Sstevel@tonic-gate 				break;
760Sstevel@tonic-gate 			if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) {
770Sstevel@tonic-gate 				if ((up + len) >= (unsigned char *)&uxb[UXBSIZE]) {
780Sstevel@tonic-gate 					uxb[0] = 0;
790Sstevel@tonic-gate 					error(gettext("Command too long"));
800Sstevel@tonic-gate 				}
810Sstevel@tonic-gate 				strncpy(up, multic, len);
820Sstevel@tonic-gate 				up += len;
830Sstevel@tonic-gate 				goto loop_check;
840Sstevel@tonic-gate 			}
850Sstevel@tonic-gate 		}
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 		(void) getchar();
880Sstevel@tonic-gate 		switch (c) {
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 		case '\\':
91500Sceastha 			if (any(peekchar(), specialchars)) {
920Sstevel@tonic-gate 				c = getchar();
93500Sceastha 				/*
94500Sceastha 				 * If we encountered a backslash-escaped
95500Sceastha 				 * newline, and we're processing a continuation
96500Sceastha 				 * command, then continue processing until
97500Sceastha 				 * non-backslash-escaped newline is reached.
98500Sceastha 				 */
99500Sceastha 				if (contcmd && (c == '\n')) {
100500Sceastha 					contread = 1;
101500Sceastha 				}
102500Sceastha 			}
1030Sstevel@tonic-gate 		default:
1040Sstevel@tonic-gate 			if (up >= (unsigned char *)&uxb[UXBSIZE]) {
1050Sstevel@tonic-gate tunix:
1060Sstevel@tonic-gate 				uxb[0] = 0;
1070Sstevel@tonic-gate 				error(gettext("Command too long"));
1080Sstevel@tonic-gate 			}
1090Sstevel@tonic-gate 			*up++ = c;
1100Sstevel@tonic-gate 			break;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 		case '!':
1130Sstevel@tonic-gate 			if (up != (unsigned char *)uxb && *puxb != 0) {
1140Sstevel@tonic-gate 				fp = puxb;
1150Sstevel@tonic-gate 				if (*fp == 0) {
1160Sstevel@tonic-gate 					uxb[0] = 0;
1170Sstevel@tonic-gate 					error(value(vi_TERSE) ?
1180Sstevel@tonic-gate gettext("No previous command") :
1190Sstevel@tonic-gate gettext("No previous command to substitute for !"));
1200Sstevel@tonic-gate 				}
1210Sstevel@tonic-gate 				printub++;
1220Sstevel@tonic-gate 				while (*fp) {
1230Sstevel@tonic-gate 					if (up >= (unsigned char *)&uxb[UXBSIZE])
1240Sstevel@tonic-gate 						goto tunix;
1250Sstevel@tonic-gate 					*up++ = *fp++;
1260Sstevel@tonic-gate 				}
1270Sstevel@tonic-gate 			} else if (up == (unsigned char *)uxb) {
1280Sstevel@tonic-gate 				/* If up = uxb it means we are on the first
1290Sstevel@tonic-gate 				 * character inside the shell command.
1300Sstevel@tonic-gate 				 * (i.e., after the ":!")
1310Sstevel@tonic-gate 				 *
1320Sstevel@tonic-gate 				 * The user has just entered ":!!" which
1330Sstevel@tonic-gate 				 * means that though there is only technically
1340Sstevel@tonic-gate 				 * one '!' we know he really meant ":!!!". So
1350Sstevel@tonic-gate 				 * substitute the last command for him.
1360Sstevel@tonic-gate 				 */
1370Sstevel@tonic-gate 				fp = puxb;
1380Sstevel@tonic-gate 				if (*fp == 0) {
1390Sstevel@tonic-gate 					uxb[0] = 0;
1400Sstevel@tonic-gate 					error(value(vi_TERSE) ?
1410Sstevel@tonic-gate gettext("No previous command") :
1420Sstevel@tonic-gate gettext("No previous command to substitute for !"));
1430Sstevel@tonic-gate 				}
1440Sstevel@tonic-gate 				printub++;
1450Sstevel@tonic-gate 				while (*fp) {
1460Sstevel@tonic-gate 					if (up >= (unsigned char *)&uxb[UXBSIZE])
1470Sstevel@tonic-gate 						goto tunix;
1480Sstevel@tonic-gate 					*up++ = *fp++;
1490Sstevel@tonic-gate 				}
1500Sstevel@tonic-gate 			} else {
1510Sstevel@tonic-gate 				/*
1520Sstevel@tonic-gate 				 * Treat a lone "!" as just a regular character
1530Sstevel@tonic-gate 				 * so commands like "mail machine!login" will
1540Sstevel@tonic-gate 				 * work as usual (i.e., the user doesn't need
1550Sstevel@tonic-gate 				 * to dereference the "!" with "\!").
1560Sstevel@tonic-gate 				 */
1570Sstevel@tonic-gate 				if (up >= (unsigned char *)&uxb[UXBSIZE]) {
1580Sstevel@tonic-gate 					uxb[0] = 0;
1590Sstevel@tonic-gate 					error(gettext("Command too long"));
1600Sstevel@tonic-gate 				}
1610Sstevel@tonic-gate 				*up++ = c;
1620Sstevel@tonic-gate 			}
1630Sstevel@tonic-gate 			break;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 		case '#':
1660Sstevel@tonic-gate 			fp = (unsigned char *)altfile;
1670Sstevel@tonic-gate 			if (*fp == 0) {
1680Sstevel@tonic-gate 				uxb[0] = 0;
1690Sstevel@tonic-gate 				error(value(vi_TERSE) ?
1700Sstevel@tonic-gate gettext("No alternate filename") :
1710Sstevel@tonic-gate gettext("No alternate filename to substitute for #"));
1720Sstevel@tonic-gate 			}
1730Sstevel@tonic-gate 			goto uexp;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 		case '%':
1760Sstevel@tonic-gate 			fp = savedfile;
1770Sstevel@tonic-gate 			if (*fp == 0) {
1780Sstevel@tonic-gate 				uxb[0] = 0;
1790Sstevel@tonic-gate 				error(value(vi_TERSE) ?
1800Sstevel@tonic-gate gettext("No filename") :
1810Sstevel@tonic-gate gettext("No filename to substitute for %%"));
1820Sstevel@tonic-gate 			}
1830Sstevel@tonic-gate uexp:
1840Sstevel@tonic-gate 			printub++;
1850Sstevel@tonic-gate 			while (*fp) {
1860Sstevel@tonic-gate 				if (up >= (unsigned char *)&uxb[UXBSIZE])
1870Sstevel@tonic-gate 					goto tunix;
1880Sstevel@tonic-gate 				*up++ = *fp++;
1890Sstevel@tonic-gate 			}
1900Sstevel@tonic-gate 			break;
1910Sstevel@tonic-gate 		}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate loop_check:
1940Sstevel@tonic-gate 		c = peekchar();
195500Sceastha 		if (c == '"' || c == '|' || (contread > 0) || !endcmd(c)) {
196500Sceastha 			/*
197500Sceastha 			 * If contread was set, then the newline just
198500Sceastha 			 * processed was preceeded by a backslash, and
199500Sceastha 			 * not considered the end of the command. Reset
200500Sceastha 			 * it here in case another backslash-escaped
201500Sceastha 			 * newline is processed.
202500Sceastha 			 */
203500Sceastha 			contread = 0;
2040Sstevel@tonic-gate 			continue;
2050Sstevel@tonic-gate 		} else {
2060Sstevel@tonic-gate 			(void) getchar();
2070Sstevel@tonic-gate 			break;
2080Sstevel@tonic-gate 		}
2090Sstevel@tonic-gate 	}
2100Sstevel@tonic-gate 	if (c == EOF)
2110Sstevel@tonic-gate 		ungetchar(c);
2120Sstevel@tonic-gate 	*up = 0;
2130Sstevel@tonic-gate 	if (!inopen)
2140Sstevel@tonic-gate 		resetflav();
2150Sstevel@tonic-gate 	if (warn)
2160Sstevel@tonic-gate 		ckaw();
2170Sstevel@tonic-gate 	if (warn && hush == 0 && chng && xchng != chng && value(vi_WARN) && dol > zero) {
2180Sstevel@tonic-gate 		xchng = chng;
2190Sstevel@tonic-gate 		vnfl();
220*802Scf46844 		viprintf(mesg(value(vi_TERSE) ? gettext("[No write]") :
2210Sstevel@tonic-gate gettext("[No write since last change]")));
2220Sstevel@tonic-gate 		noonl();
2230Sstevel@tonic-gate 		flush();
2240Sstevel@tonic-gate 	} else
2250Sstevel@tonic-gate 		warn = 0;
2260Sstevel@tonic-gate 	if (printub) {
2270Sstevel@tonic-gate 		if (uxb[0] == 0)
2280Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No previous command") :
2290Sstevel@tonic-gate gettext("No previous command to repeat"));
2300Sstevel@tonic-gate 		if (inopen) {
2310Sstevel@tonic-gate 			splitw++;
2320Sstevel@tonic-gate 			vclean();
2330Sstevel@tonic-gate 			vgoto(WECHO, 0);
2340Sstevel@tonic-gate 		}
2350Sstevel@tonic-gate 		if (warn)
2360Sstevel@tonic-gate 			vnfl();
2370Sstevel@tonic-gate 		if (hush == 0)
2380Sstevel@tonic-gate 			lprintf("!%s", uxb);
2390Sstevel@tonic-gate 		if (inopen && Outchar != termchar) {
2400Sstevel@tonic-gate 			vclreol();
2410Sstevel@tonic-gate 			vgoto(WECHO, 0);
2420Sstevel@tonic-gate 		} else
2430Sstevel@tonic-gate 			putnl();
2440Sstevel@tonic-gate 		flush();
2450Sstevel@tonic-gate 	}
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * Do the real work for execution of a shell escape.
2500Sstevel@tonic-gate  * Mode is like the number passed to open system calls
2510Sstevel@tonic-gate  * and indicates filtering.  If input is implied, newstdin
2520Sstevel@tonic-gate  * must have been setup already.
2530Sstevel@tonic-gate  */
2540Sstevel@tonic-gate ttymode
2550Sstevel@tonic-gate unixex(opt, up, newstdin, mode)
2560Sstevel@tonic-gate 	unsigned char *opt, *up;
2570Sstevel@tonic-gate 	int newstdin, mode;
2580Sstevel@tonic-gate {
2590Sstevel@tonic-gate 	int pvec[2];
2600Sstevel@tonic-gate 	ttymode f;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	signal(SIGINT, SIG_IGN);
2630Sstevel@tonic-gate #ifdef SIGTSTP
2640Sstevel@tonic-gate 	if (dosusp)
2650Sstevel@tonic-gate 		signal(SIGTSTP, SIG_DFL);
2660Sstevel@tonic-gate #endif
2670Sstevel@tonic-gate 	if (inopen)
2680Sstevel@tonic-gate 		f = setty(normf);
2690Sstevel@tonic-gate 	if ((mode & 1) && pipe(pvec) < 0) {
2700Sstevel@tonic-gate 		/* Newstdin should be io so it will be closed */
2710Sstevel@tonic-gate 		if (inopen)
2720Sstevel@tonic-gate 			setty(f);
2730Sstevel@tonic-gate 		error(gettext("Can't make pipe for filter"));
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate #ifndef VFORK
2760Sstevel@tonic-gate 	pid = fork();
2770Sstevel@tonic-gate #else
2780Sstevel@tonic-gate 	pid = vfork();
2790Sstevel@tonic-gate #endif
2800Sstevel@tonic-gate 	if (pid < 0) {
2810Sstevel@tonic-gate 		if (mode & 1) {
2820Sstevel@tonic-gate 			close(pvec[0]);
2830Sstevel@tonic-gate 			close(pvec[1]);
2840Sstevel@tonic-gate 		}
2850Sstevel@tonic-gate 		setrupt();
2860Sstevel@tonic-gate 		if (inopen)
2870Sstevel@tonic-gate 			setty(f);
2880Sstevel@tonic-gate 		error(gettext("No more processes"));
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 	if (pid == 0) {
2910Sstevel@tonic-gate 		if (mode & 2) {
2920Sstevel@tonic-gate 			close(0);
2930Sstevel@tonic-gate 			dup(newstdin);
2940Sstevel@tonic-gate 			close(newstdin);
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 		if (mode & 1) {
2970Sstevel@tonic-gate 			close(pvec[0]);
2980Sstevel@tonic-gate 			close(1);
2990Sstevel@tonic-gate 			dup(pvec[1]);
3000Sstevel@tonic-gate 			if (inopen) {
3010Sstevel@tonic-gate 				close(2);
3020Sstevel@tonic-gate 				dup(1);
3030Sstevel@tonic-gate 			}
3040Sstevel@tonic-gate 			close(pvec[1]);
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate 		if (io)
3070Sstevel@tonic-gate 			close(io);
3080Sstevel@tonic-gate 		if (tfile)
3090Sstevel@tonic-gate 			close(tfile);
3100Sstevel@tonic-gate 		signal(SIGHUP, oldhup);
3110Sstevel@tonic-gate 		signal(SIGQUIT, oldquit);
3120Sstevel@tonic-gate 		if (ruptible)
3130Sstevel@tonic-gate 			signal(SIGINT, SIG_DFL);
314*802Scf46844 		execlp((char *)svalue(vi_SHELL), (char *)svalue(vi_SHELL),
315*802Scf46844 		    opt, up, (char *)0);
316*802Scf46844 		viprintf(gettext("Invalid SHELL value: %s\n"),
317*802Scf46844 		    svalue(vi_SHELL));
3180Sstevel@tonic-gate 		flush();
3190Sstevel@tonic-gate 		error(NOSTR);
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 	if (mode & 1) {
3220Sstevel@tonic-gate 		io = pvec[0];
3230Sstevel@tonic-gate 		close(pvec[1]);
3240Sstevel@tonic-gate 	}
3250Sstevel@tonic-gate 	if (newstdin)
3260Sstevel@tonic-gate 		close(newstdin);
3270Sstevel@tonic-gate 	return (f);
3280Sstevel@tonic-gate }
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate /*
3310Sstevel@tonic-gate  * Wait for the command to complete.
3320Sstevel@tonic-gate  * F is for restoration of tty mode if from open/visual.
3330Sstevel@tonic-gate  * C flags suppression of printing.
3340Sstevel@tonic-gate  */
335*802Scf46844 void
3360Sstevel@tonic-gate unixwt(c, f)
3370Sstevel@tonic-gate 	bool c;
3380Sstevel@tonic-gate 	ttymode f;
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 	waitfor();
3420Sstevel@tonic-gate #ifdef SIGTSTP
3430Sstevel@tonic-gate 	if (dosusp)
3440Sstevel@tonic-gate 		signal(SIGTSTP, onsusp);
3450Sstevel@tonic-gate #endif
3460Sstevel@tonic-gate 	if (inopen)
3470Sstevel@tonic-gate 		setty(f);
3480Sstevel@tonic-gate 	setrupt();
3490Sstevel@tonic-gate 	if (!inopen && c && hush == 0) {
350*802Scf46844 		viprintf("!\n");
3510Sstevel@tonic-gate 		flush();
3520Sstevel@tonic-gate 		termreset();
3530Sstevel@tonic-gate 		gettmode();
3540Sstevel@tonic-gate 	}
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate  * Setup a pipeline for the filtration implied by mode
3590Sstevel@tonic-gate  * which is like a open number.  If input is required to
3600Sstevel@tonic-gate  * the filter, then a child editor is created to write it.
3610Sstevel@tonic-gate  * If output is catch it from io which is created by unixex.
3620Sstevel@tonic-gate  */
363*802Scf46844 int
364*802Scf46844 vi_filter(int mode)
3650Sstevel@tonic-gate {
3660Sstevel@tonic-gate 	static int pvec[2];
3670Sstevel@tonic-gate 	ttymode f;	/* was register */
368*802Scf46844 	int nlines = lineDOL();
3690Sstevel@tonic-gate 	int status2;
3700Sstevel@tonic-gate 	pid_t pid2 = 0;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	mode++;
3730Sstevel@tonic-gate 	if (mode & 2) {
3740Sstevel@tonic-gate 		signal(SIGINT, SIG_IGN);
3750Sstevel@tonic-gate 		signal(SIGPIPE, SIG_IGN);
3760Sstevel@tonic-gate 		if (pipe(pvec) < 0)
3770Sstevel@tonic-gate 			error(gettext("Can't make pipe"));
3780Sstevel@tonic-gate 		pid2 = fork();
3790Sstevel@tonic-gate 		io = pvec[0];
3800Sstevel@tonic-gate 		if (pid < 0) {
3810Sstevel@tonic-gate 			setrupt();
3820Sstevel@tonic-gate 			close(pvec[1]);
3830Sstevel@tonic-gate 			error(gettext("No more processes"));
3840Sstevel@tonic-gate 		}
3850Sstevel@tonic-gate 		if (pid2 == 0) {
3860Sstevel@tonic-gate 			extern unsigned char tfname[];
3870Sstevel@tonic-gate 			setrupt();
3880Sstevel@tonic-gate 			io = pvec[1];
3890Sstevel@tonic-gate 			close(pvec[0]);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 			/* To prevent seeking in this process and the
3920Sstevel@tonic-gate 				 parent, we must reopen tfile here */
3930Sstevel@tonic-gate 			close(tfile);
3940Sstevel@tonic-gate 			tfile = open(tfname, 2);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 			putfile(1);
3970Sstevel@tonic-gate 			exit(errcnt);
3980Sstevel@tonic-gate 		}
3990Sstevel@tonic-gate 		close(pvec[1]);
4000Sstevel@tonic-gate 		io = pvec[0];
4010Sstevel@tonic-gate 		setrupt();
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 	f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
4040Sstevel@tonic-gate 	if (mode == 3) {
405*802Scf46844 		(void) delete(0);
4060Sstevel@tonic-gate 		addr2 = addr1 - 1;
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 	if (mode == 1)
4090Sstevel@tonic-gate 		deletenone();
4100Sstevel@tonic-gate 	if (mode & 1) {
4110Sstevel@tonic-gate 		if(FIXUNDO)
4120Sstevel@tonic-gate 			undap1 = undap2 = addr2+1;
4130Sstevel@tonic-gate 		(void)append(getfile, addr2);
4140Sstevel@tonic-gate #ifdef UNDOTRACE
4150Sstevel@tonic-gate 		if (trace)
4160Sstevel@tonic-gate 			vudump(gettext("after append in filter"));
4170Sstevel@tonic-gate #endif
4180Sstevel@tonic-gate 	}
4190Sstevel@tonic-gate 	close(io);
4200Sstevel@tonic-gate 	io = -1;
4210Sstevel@tonic-gate 	unixwt(!inopen, f);
4220Sstevel@tonic-gate 	if (pid2) {
4230Sstevel@tonic-gate 		(void)kill(pid2, 9);
4240Sstevel@tonic-gate 		do
4250Sstevel@tonic-gate 			rpid = waitpid(pid2, &status2, 0);
4260Sstevel@tonic-gate 		while (rpid == (pid_t)-1 && errno == EINTR);
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 	netchHAD(nlines);
429*802Scf46844 	return (0);
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate /*
4330Sstevel@tonic-gate  * Set up to do a recover, getting io to be a pipe from
4340Sstevel@tonic-gate  * the recover process.
4350Sstevel@tonic-gate  */
436*802Scf46844 void
437*802Scf46844 recover(void)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	static int pvec[2];
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if (pipe(pvec) < 0)
4420Sstevel@tonic-gate 		error(gettext(" Can't make pipe for recovery"));
4430Sstevel@tonic-gate 	pid = fork();
4440Sstevel@tonic-gate 	io = pvec[0];
4450Sstevel@tonic-gate 	if (pid < 0) {
4460Sstevel@tonic-gate 		close(pvec[1]);
4470Sstevel@tonic-gate 		error(gettext(" Can't fork to execute recovery"));
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 	if (pid == 0) {
4500Sstevel@tonic-gate 		unsigned char cryptkey[19];
4510Sstevel@tonic-gate 		close(2);
4520Sstevel@tonic-gate 		dup(1);
4530Sstevel@tonic-gate 		close(1);
4540Sstevel@tonic-gate 		dup(pvec[1]);
4550Sstevel@tonic-gate 	        close(pvec[1]);
4560Sstevel@tonic-gate 		if(xflag) {
4570Sstevel@tonic-gate 			strcpy(cryptkey, "CrYpTkEy=XXXXXXXXX");
4580Sstevel@tonic-gate 			strcpy(cryptkey + 9, key);
4590Sstevel@tonic-gate 			if(putenv((char *)cryptkey) != 0)
4600Sstevel@tonic-gate 				smerror(gettext(" Cannot copy key to environment"));
4610Sstevel@tonic-gate 			execlp(EXRECOVER, "exrecover", "-x", svalue(vi_DIRECTORY), file, (char *) 0);
4620Sstevel@tonic-gate 		} else
4630Sstevel@tonic-gate 			execlp(EXRECOVER, "exrecover", svalue(vi_DIRECTORY), file, (char *) 0);
4640Sstevel@tonic-gate 		close(1);
4650Sstevel@tonic-gate 		dup(2);
4660Sstevel@tonic-gate 		error(gettext(" No recovery routine"));
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 	close(pvec[1]);
4690Sstevel@tonic-gate }
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate /*
4720Sstevel@tonic-gate  * Wait for the process (pid an external) to complete.
4730Sstevel@tonic-gate  */
474*802Scf46844 void
475*802Scf46844 waitfor(void)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	do
4790Sstevel@tonic-gate 		rpid = waitpid(pid, &status, 0);
4800Sstevel@tonic-gate 	while (rpid == (pid_t)-1 && errno != ECHILD);
4810Sstevel@tonic-gate 	if ((status & 0377) == 0)
4820Sstevel@tonic-gate 		status = (status >> 8) & 0377;
4830Sstevel@tonic-gate 	else {
4840Sstevel@tonic-gate 		/*
4850Sstevel@tonic-gate 		 * TRANSLATION_NOTE
4860Sstevel@tonic-gate 		 *	Reference order of arguments must not
4870Sstevel@tonic-gate 		 *	be changed using '%digit$', since vi's
488*802Scf46844 		 *	viprintf() does not support it.
4890Sstevel@tonic-gate 		 */
490*802Scf46844 		viprintf(gettext("%d: terminated with signal %d"), pid,
491*802Scf46844 		    status & 0177);
4920Sstevel@tonic-gate 		if (status & 0200)
493*802Scf46844 			viprintf(gettext(" -- core dumped"));
4940Sstevel@tonic-gate 		putchar('\n');
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate /*
4990Sstevel@tonic-gate  * The end of a recover operation.  If the process
5000Sstevel@tonic-gate  * exits non-zero, force not edited; otherwise force
5010Sstevel@tonic-gate  * a write.
5020Sstevel@tonic-gate  */
503*802Scf46844 void
504*802Scf46844 revocer(void)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	waitfor();
5080Sstevel@tonic-gate 	if (pid == rpid && status != 0)
5090Sstevel@tonic-gate 		edited = 0;
5100Sstevel@tonic-gate 	else
5110Sstevel@tonic-gate 		change();
5120Sstevel@tonic-gate }
513