xref: /titanic_51/usr/src/cmd/vi/port/ex_unix.c (revision 68c92b9f236192fc4b1af4355a207acf7469bd59)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*68c92b9fScf46844  * Common Development and Distribution License (the "License").
6*68c92b9fScf46844  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*68c92b9fScf46844  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
277c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /* Copyright (c) 1979 Regents of the University of California */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include "ex.h"
357c478bd9Sstevel@tonic-gate #include "ex_temp.h"
367c478bd9Sstevel@tonic-gate #include "ex_tty.h"
377c478bd9Sstevel@tonic-gate #include "ex_vis.h"
387c478bd9Sstevel@tonic-gate 
39f6db9f27Scf46844 extern int	getchar();
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Unix escapes, filtering
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate /*
457c478bd9Sstevel@tonic-gate  * First part of a shell escape,
467c478bd9Sstevel@tonic-gate  * parse the line, expanding # and % and ! and printing if implied.
477c478bd9Sstevel@tonic-gate  */
48ec427229Sceastha void
49ec427229Sceastha unix0(bool warn, int contcmd)
507c478bd9Sstevel@tonic-gate {
51ec427229Sceastha 	unsigned char *up, *fp;
52ec427229Sceastha 	short c;
537c478bd9Sstevel@tonic-gate 	char	multic[MB_LEN_MAX + 1];
547c478bd9Sstevel@tonic-gate 	int	len;
55ec427229Sceastha 	int	contread = 0;
567c478bd9Sstevel@tonic-gate 	wchar_t	wc;
577c478bd9Sstevel@tonic-gate 	unsigned char printub, puxb[UXBSIZE + sizeof (int)];
58ec427229Sceastha 	const char	*specialchars = (contcmd ? "%#!\n" : "%#!");
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	printub = 0;
617c478bd9Sstevel@tonic-gate 	CP(puxb, uxb);
627c478bd9Sstevel@tonic-gate 	c = peekchar();
637c478bd9Sstevel@tonic-gate 	if (c == '\n' || c == EOF) {
647c478bd9Sstevel@tonic-gate 		(void) getchar();
657c478bd9Sstevel@tonic-gate 		error(value(vi_TERSE) ?
667c478bd9Sstevel@tonic-gate gettext("Incomplete shell escape command") :
677c478bd9Sstevel@tonic-gate gettext("Incomplete shell escape command - use 'shell' to get a shell"));
687c478bd9Sstevel@tonic-gate 	}
697c478bd9Sstevel@tonic-gate 	up = (unsigned char *)uxb;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	for (;;) {
727c478bd9Sstevel@tonic-gate 		if (!isascii(c)) {
737c478bd9Sstevel@tonic-gate 			if (c == EOF)
747c478bd9Sstevel@tonic-gate 				break;
757c478bd9Sstevel@tonic-gate 			if ((len = _mbftowc(multic, &wc, getchar, &peekc)) > 0) {
767c478bd9Sstevel@tonic-gate 				if ((up + len) >= (unsigned char *)&uxb[UXBSIZE]) {
777c478bd9Sstevel@tonic-gate 					uxb[0] = 0;
787c478bd9Sstevel@tonic-gate 					error(gettext("Command too long"));
797c478bd9Sstevel@tonic-gate 				}
807c478bd9Sstevel@tonic-gate 				strncpy(up, multic, len);
817c478bd9Sstevel@tonic-gate 				up += len;
827c478bd9Sstevel@tonic-gate 				goto loop_check;
837c478bd9Sstevel@tonic-gate 			}
847c478bd9Sstevel@tonic-gate 		}
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 		(void) getchar();
877c478bd9Sstevel@tonic-gate 		switch (c) {
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 		case '\\':
90ec427229Sceastha 			if (any(peekchar(), specialchars)) {
917c478bd9Sstevel@tonic-gate 				c = getchar();
92ec427229Sceastha 				/*
93ec427229Sceastha 				 * If we encountered a backslash-escaped
94ec427229Sceastha 				 * newline, and we're processing a continuation
95ec427229Sceastha 				 * command, then continue processing until
96ec427229Sceastha 				 * non-backslash-escaped newline is reached.
97ec427229Sceastha 				 */
98ec427229Sceastha 				if (contcmd && (c == '\n')) {
99ec427229Sceastha 					contread = 1;
100ec427229Sceastha 				}
101ec427229Sceastha 			}
1027c478bd9Sstevel@tonic-gate 		default:
1037c478bd9Sstevel@tonic-gate 			if (up >= (unsigned char *)&uxb[UXBSIZE]) {
1047c478bd9Sstevel@tonic-gate tunix:
1057c478bd9Sstevel@tonic-gate 				uxb[0] = 0;
1067c478bd9Sstevel@tonic-gate 				error(gettext("Command too long"));
1077c478bd9Sstevel@tonic-gate 			}
108*68c92b9fScf46844 			/*
109*68c92b9fScf46844 			 * If this is a tag command (-t or :tag),
110*68c92b9fScf46844 			 * then don't save any command that follows
111*68c92b9fScf46844 			 * '!' in the invalid tags file, ie:
112*68c92b9fScf46844 			 * '!!' should not repeat the invalid command
113*68c92b9fScf46844 			 * later on when tagflg has been cleared.
114*68c92b9fScf46844 			 */
115*68c92b9fScf46844 			if (!tagflg)
1167c478bd9Sstevel@tonic-gate 				*up++ = c;
1177c478bd9Sstevel@tonic-gate 			break;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 		case '!':
1207c478bd9Sstevel@tonic-gate 			if (up != (unsigned char *)uxb && *puxb != 0) {
1217c478bd9Sstevel@tonic-gate 				fp = puxb;
1227c478bd9Sstevel@tonic-gate 				if (*fp == 0) {
1237c478bd9Sstevel@tonic-gate 					uxb[0] = 0;
1247c478bd9Sstevel@tonic-gate 					error(value(vi_TERSE) ?
1257c478bd9Sstevel@tonic-gate gettext("No previous command") :
1267c478bd9Sstevel@tonic-gate gettext("No previous command to substitute for !"));
1277c478bd9Sstevel@tonic-gate 				}
1287c478bd9Sstevel@tonic-gate 				printub++;
1297c478bd9Sstevel@tonic-gate 				while (*fp) {
1307c478bd9Sstevel@tonic-gate 					if (up >= (unsigned char *)&uxb[UXBSIZE])
1317c478bd9Sstevel@tonic-gate 						goto tunix;
1327c478bd9Sstevel@tonic-gate 					*up++ = *fp++;
1337c478bd9Sstevel@tonic-gate 				}
1347c478bd9Sstevel@tonic-gate 			} else if (up == (unsigned char *)uxb) {
1357c478bd9Sstevel@tonic-gate 				/* If up = uxb it means we are on the first
1367c478bd9Sstevel@tonic-gate 				 * character inside the shell command.
1377c478bd9Sstevel@tonic-gate 				 * (i.e., after the ":!")
1387c478bd9Sstevel@tonic-gate 				 *
1397c478bd9Sstevel@tonic-gate 				 * The user has just entered ":!!" which
1407c478bd9Sstevel@tonic-gate 				 * means that though there is only technically
1417c478bd9Sstevel@tonic-gate 				 * one '!' we know he really meant ":!!!". So
1427c478bd9Sstevel@tonic-gate 				 * substitute the last command for him.
1437c478bd9Sstevel@tonic-gate 				 */
1447c478bd9Sstevel@tonic-gate 				fp = puxb;
1457c478bd9Sstevel@tonic-gate 				if (*fp == 0) {
1467c478bd9Sstevel@tonic-gate 					uxb[0] = 0;
1477c478bd9Sstevel@tonic-gate 					error(value(vi_TERSE) ?
1487c478bd9Sstevel@tonic-gate gettext("No previous command") :
1497c478bd9Sstevel@tonic-gate gettext("No previous command to substitute for !"));
1507c478bd9Sstevel@tonic-gate 				}
1517c478bd9Sstevel@tonic-gate 				printub++;
1527c478bd9Sstevel@tonic-gate 				while (*fp) {
1537c478bd9Sstevel@tonic-gate 					if (up >= (unsigned char *)&uxb[UXBSIZE])
1547c478bd9Sstevel@tonic-gate 						goto tunix;
1557c478bd9Sstevel@tonic-gate 					*up++ = *fp++;
1567c478bd9Sstevel@tonic-gate 				}
1577c478bd9Sstevel@tonic-gate 			} else {
1587c478bd9Sstevel@tonic-gate 				/*
1597c478bd9Sstevel@tonic-gate 				 * Treat a lone "!" as just a regular character
1607c478bd9Sstevel@tonic-gate 				 * so commands like "mail machine!login" will
1617c478bd9Sstevel@tonic-gate 				 * work as usual (i.e., the user doesn't need
1627c478bd9Sstevel@tonic-gate 				 * to dereference the "!" with "\!").
1637c478bd9Sstevel@tonic-gate 				 */
1647c478bd9Sstevel@tonic-gate 				if (up >= (unsigned char *)&uxb[UXBSIZE]) {
1657c478bd9Sstevel@tonic-gate 					uxb[0] = 0;
1667c478bd9Sstevel@tonic-gate 					error(gettext("Command too long"));
1677c478bd9Sstevel@tonic-gate 				}
1687c478bd9Sstevel@tonic-gate 				*up++ = c;
1697c478bd9Sstevel@tonic-gate 			}
1707c478bd9Sstevel@tonic-gate 			break;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 		case '#':
1737c478bd9Sstevel@tonic-gate 			fp = (unsigned char *)altfile;
1747c478bd9Sstevel@tonic-gate 			if (*fp == 0) {
1757c478bd9Sstevel@tonic-gate 				uxb[0] = 0;
1767c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
1777c478bd9Sstevel@tonic-gate gettext("No alternate filename") :
1787c478bd9Sstevel@tonic-gate gettext("No alternate filename to substitute for #"));
1797c478bd9Sstevel@tonic-gate 			}
1807c478bd9Sstevel@tonic-gate 			goto uexp;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 		case '%':
1837c478bd9Sstevel@tonic-gate 			fp = savedfile;
1847c478bd9Sstevel@tonic-gate 			if (*fp == 0) {
1857c478bd9Sstevel@tonic-gate 				uxb[0] = 0;
1867c478bd9Sstevel@tonic-gate 				error(value(vi_TERSE) ?
1877c478bd9Sstevel@tonic-gate gettext("No filename") :
1887c478bd9Sstevel@tonic-gate gettext("No filename to substitute for %%"));
1897c478bd9Sstevel@tonic-gate 			}
1907c478bd9Sstevel@tonic-gate uexp:
1917c478bd9Sstevel@tonic-gate 			printub++;
1927c478bd9Sstevel@tonic-gate 			while (*fp) {
1937c478bd9Sstevel@tonic-gate 				if (up >= (unsigned char *)&uxb[UXBSIZE])
1947c478bd9Sstevel@tonic-gate 					goto tunix;
1957c478bd9Sstevel@tonic-gate 				*up++ = *fp++;
1967c478bd9Sstevel@tonic-gate 			}
1977c478bd9Sstevel@tonic-gate 			break;
1987c478bd9Sstevel@tonic-gate 		}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate loop_check:
2017c478bd9Sstevel@tonic-gate 		c = peekchar();
202ec427229Sceastha 		if (c == '"' || c == '|' || (contread > 0) || !endcmd(c)) {
203ec427229Sceastha 			/*
204ec427229Sceastha 			 * If contread was set, then the newline just
205ec427229Sceastha 			 * processed was preceeded by a backslash, and
206ec427229Sceastha 			 * not considered the end of the command. Reset
207ec427229Sceastha 			 * it here in case another backslash-escaped
208ec427229Sceastha 			 * newline is processed.
209ec427229Sceastha 			 */
210ec427229Sceastha 			contread = 0;
2117c478bd9Sstevel@tonic-gate 			continue;
2127c478bd9Sstevel@tonic-gate 		} else {
2137c478bd9Sstevel@tonic-gate 			(void) getchar();
2147c478bd9Sstevel@tonic-gate 			break;
2157c478bd9Sstevel@tonic-gate 		}
2167c478bd9Sstevel@tonic-gate 	}
2177c478bd9Sstevel@tonic-gate 	if (c == EOF)
2187c478bd9Sstevel@tonic-gate 		ungetchar(c);
2197c478bd9Sstevel@tonic-gate 	*up = 0;
2207c478bd9Sstevel@tonic-gate 	if (!inopen)
2217c478bd9Sstevel@tonic-gate 		resetflav();
2227c478bd9Sstevel@tonic-gate 	if (warn)
2237c478bd9Sstevel@tonic-gate 		ckaw();
2247c478bd9Sstevel@tonic-gate 	if (warn && hush == 0 && chng && xchng != chng && value(vi_WARN) && dol > zero) {
2257c478bd9Sstevel@tonic-gate 		xchng = chng;
2267c478bd9Sstevel@tonic-gate 		vnfl();
227f6db9f27Scf46844 		viprintf(mesg(value(vi_TERSE) ? gettext("[No write]") :
2287c478bd9Sstevel@tonic-gate gettext("[No write since last change]")));
2297c478bd9Sstevel@tonic-gate 		noonl();
2307c478bd9Sstevel@tonic-gate 		flush();
2317c478bd9Sstevel@tonic-gate 	} else
2327c478bd9Sstevel@tonic-gate 		warn = 0;
2337c478bd9Sstevel@tonic-gate 	if (printub) {
2347c478bd9Sstevel@tonic-gate 		if (uxb[0] == 0)
2357c478bd9Sstevel@tonic-gate 			error(value(vi_TERSE) ? gettext("No previous command") :
2367c478bd9Sstevel@tonic-gate gettext("No previous command to repeat"));
2377c478bd9Sstevel@tonic-gate 		if (inopen) {
2387c478bd9Sstevel@tonic-gate 			splitw++;
2397c478bd9Sstevel@tonic-gate 			vclean();
2407c478bd9Sstevel@tonic-gate 			vgoto(WECHO, 0);
2417c478bd9Sstevel@tonic-gate 		}
2427c478bd9Sstevel@tonic-gate 		if (warn)
2437c478bd9Sstevel@tonic-gate 			vnfl();
2447c478bd9Sstevel@tonic-gate 		if (hush == 0)
2457c478bd9Sstevel@tonic-gate 			lprintf("!%s", uxb);
2467c478bd9Sstevel@tonic-gate 		if (inopen && Outchar != termchar) {
2477c478bd9Sstevel@tonic-gate 			vclreol();
2487c478bd9Sstevel@tonic-gate 			vgoto(WECHO, 0);
2497c478bd9Sstevel@tonic-gate 		} else
2507c478bd9Sstevel@tonic-gate 			putnl();
2517c478bd9Sstevel@tonic-gate 		flush();
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate /*
2567c478bd9Sstevel@tonic-gate  * Do the real work for execution of a shell escape.
2577c478bd9Sstevel@tonic-gate  * Mode is like the number passed to open system calls
2587c478bd9Sstevel@tonic-gate  * and indicates filtering.  If input is implied, newstdin
2597c478bd9Sstevel@tonic-gate  * must have been setup already.
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate ttymode
2627c478bd9Sstevel@tonic-gate unixex(opt, up, newstdin, mode)
2637c478bd9Sstevel@tonic-gate 	unsigned char *opt, *up;
2647c478bd9Sstevel@tonic-gate 	int newstdin, mode;
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	int pvec[2];
2677c478bd9Sstevel@tonic-gate 	ttymode f;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	signal(SIGINT, SIG_IGN);
2707c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
2717c478bd9Sstevel@tonic-gate 	if (dosusp)
2727c478bd9Sstevel@tonic-gate 		signal(SIGTSTP, SIG_DFL);
2737c478bd9Sstevel@tonic-gate #endif
2747c478bd9Sstevel@tonic-gate 	if (inopen)
2757c478bd9Sstevel@tonic-gate 		f = setty(normf);
2767c478bd9Sstevel@tonic-gate 	if ((mode & 1) && pipe(pvec) < 0) {
2777c478bd9Sstevel@tonic-gate 		/* Newstdin should be io so it will be closed */
2787c478bd9Sstevel@tonic-gate 		if (inopen)
2797c478bd9Sstevel@tonic-gate 			setty(f);
2807c478bd9Sstevel@tonic-gate 		error(gettext("Can't make pipe for filter"));
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate #ifndef VFORK
2837c478bd9Sstevel@tonic-gate 	pid = fork();
2847c478bd9Sstevel@tonic-gate #else
2857c478bd9Sstevel@tonic-gate 	pid = vfork();
2867c478bd9Sstevel@tonic-gate #endif
2877c478bd9Sstevel@tonic-gate 	if (pid < 0) {
2887c478bd9Sstevel@tonic-gate 		if (mode & 1) {
2897c478bd9Sstevel@tonic-gate 			close(pvec[0]);
2907c478bd9Sstevel@tonic-gate 			close(pvec[1]);
2917c478bd9Sstevel@tonic-gate 		}
2927c478bd9Sstevel@tonic-gate 		setrupt();
2937c478bd9Sstevel@tonic-gate 		if (inopen)
2947c478bd9Sstevel@tonic-gate 			setty(f);
2957c478bd9Sstevel@tonic-gate 		error(gettext("No more processes"));
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 	if (pid == 0) {
2987c478bd9Sstevel@tonic-gate 		if (mode & 2) {
2997c478bd9Sstevel@tonic-gate 			close(0);
3007c478bd9Sstevel@tonic-gate 			dup(newstdin);
3017c478bd9Sstevel@tonic-gate 			close(newstdin);
3027c478bd9Sstevel@tonic-gate 		}
3037c478bd9Sstevel@tonic-gate 		if (mode & 1) {
3047c478bd9Sstevel@tonic-gate 			close(pvec[0]);
3057c478bd9Sstevel@tonic-gate 			close(1);
3067c478bd9Sstevel@tonic-gate 			dup(pvec[1]);
3077c478bd9Sstevel@tonic-gate 			if (inopen) {
3087c478bd9Sstevel@tonic-gate 				close(2);
3097c478bd9Sstevel@tonic-gate 				dup(1);
3107c478bd9Sstevel@tonic-gate 			}
3117c478bd9Sstevel@tonic-gate 			close(pvec[1]);
3127c478bd9Sstevel@tonic-gate 		}
3137c478bd9Sstevel@tonic-gate 		if (io)
3147c478bd9Sstevel@tonic-gate 			close(io);
3157c478bd9Sstevel@tonic-gate 		if (tfile)
3167c478bd9Sstevel@tonic-gate 			close(tfile);
3177c478bd9Sstevel@tonic-gate 		signal(SIGHUP, oldhup);
3187c478bd9Sstevel@tonic-gate 		signal(SIGQUIT, oldquit);
3197c478bd9Sstevel@tonic-gate 		if (ruptible)
3207c478bd9Sstevel@tonic-gate 			signal(SIGINT, SIG_DFL);
321f6db9f27Scf46844 		execlp((char *)svalue(vi_SHELL), (char *)svalue(vi_SHELL),
322f6db9f27Scf46844 		    opt, up, (char *)0);
323f6db9f27Scf46844 		viprintf(gettext("Invalid SHELL value: %s\n"),
324f6db9f27Scf46844 		    svalue(vi_SHELL));
3257c478bd9Sstevel@tonic-gate 		flush();
3267c478bd9Sstevel@tonic-gate 		error(NOSTR);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 	if (mode & 1) {
3297c478bd9Sstevel@tonic-gate 		io = pvec[0];
3307c478bd9Sstevel@tonic-gate 		close(pvec[1]);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 	if (newstdin)
3337c478bd9Sstevel@tonic-gate 		close(newstdin);
3347c478bd9Sstevel@tonic-gate 	return (f);
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
3387c478bd9Sstevel@tonic-gate  * Wait for the command to complete.
3397c478bd9Sstevel@tonic-gate  * F is for restoration of tty mode if from open/visual.
3407c478bd9Sstevel@tonic-gate  * C flags suppression of printing.
3417c478bd9Sstevel@tonic-gate  */
342f6db9f27Scf46844 void
3437c478bd9Sstevel@tonic-gate unixwt(c, f)
3447c478bd9Sstevel@tonic-gate 	bool c;
3457c478bd9Sstevel@tonic-gate 	ttymode f;
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	waitfor();
3497c478bd9Sstevel@tonic-gate #ifdef SIGTSTP
3507c478bd9Sstevel@tonic-gate 	if (dosusp)
3517c478bd9Sstevel@tonic-gate 		signal(SIGTSTP, onsusp);
3527c478bd9Sstevel@tonic-gate #endif
3537c478bd9Sstevel@tonic-gate 	if (inopen)
3547c478bd9Sstevel@tonic-gate 		setty(f);
3557c478bd9Sstevel@tonic-gate 	setrupt();
3567c478bd9Sstevel@tonic-gate 	if (!inopen && c && hush == 0) {
357f6db9f27Scf46844 		viprintf("!\n");
3587c478bd9Sstevel@tonic-gate 		flush();
3597c478bd9Sstevel@tonic-gate 		termreset();
3607c478bd9Sstevel@tonic-gate 		gettmode();
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate /*
3657c478bd9Sstevel@tonic-gate  * Setup a pipeline for the filtration implied by mode
3667c478bd9Sstevel@tonic-gate  * which is like a open number.  If input is required to
3677c478bd9Sstevel@tonic-gate  * the filter, then a child editor is created to write it.
3687c478bd9Sstevel@tonic-gate  * If output is catch it from io which is created by unixex.
3697c478bd9Sstevel@tonic-gate  */
370f6db9f27Scf46844 int
371f6db9f27Scf46844 vi_filter(int mode)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	static int pvec[2];
3747c478bd9Sstevel@tonic-gate 	ttymode f;	/* was register */
375f6db9f27Scf46844 	int nlines = lineDOL();
3767c478bd9Sstevel@tonic-gate 	int status2;
3777c478bd9Sstevel@tonic-gate 	pid_t pid2 = 0;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	mode++;
3807c478bd9Sstevel@tonic-gate 	if (mode & 2) {
3817c478bd9Sstevel@tonic-gate 		signal(SIGINT, SIG_IGN);
3827c478bd9Sstevel@tonic-gate 		signal(SIGPIPE, SIG_IGN);
3837c478bd9Sstevel@tonic-gate 		if (pipe(pvec) < 0)
3847c478bd9Sstevel@tonic-gate 			error(gettext("Can't make pipe"));
3857c478bd9Sstevel@tonic-gate 		pid2 = fork();
3867c478bd9Sstevel@tonic-gate 		io = pvec[0];
3877c478bd9Sstevel@tonic-gate 		if (pid < 0) {
3887c478bd9Sstevel@tonic-gate 			setrupt();
3897c478bd9Sstevel@tonic-gate 			close(pvec[1]);
3907c478bd9Sstevel@tonic-gate 			error(gettext("No more processes"));
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 		if (pid2 == 0) {
3937c478bd9Sstevel@tonic-gate 			extern unsigned char tfname[];
3947c478bd9Sstevel@tonic-gate 			setrupt();
3957c478bd9Sstevel@tonic-gate 			io = pvec[1];
3967c478bd9Sstevel@tonic-gate 			close(pvec[0]);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 			/* To prevent seeking in this process and the
3997c478bd9Sstevel@tonic-gate 				 parent, we must reopen tfile here */
4007c478bd9Sstevel@tonic-gate 			close(tfile);
4017c478bd9Sstevel@tonic-gate 			tfile = open(tfname, 2);
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 			putfile(1);
4047c478bd9Sstevel@tonic-gate 			exit(errcnt);
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 		close(pvec[1]);
4077c478bd9Sstevel@tonic-gate 		io = pvec[0];
4087c478bd9Sstevel@tonic-gate 		setrupt();
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 	f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode);
4117c478bd9Sstevel@tonic-gate 	if (mode == 3) {
412f6db9f27Scf46844 		(void) delete(0);
4137c478bd9Sstevel@tonic-gate 		addr2 = addr1 - 1;
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 	if (mode == 1)
4167c478bd9Sstevel@tonic-gate 		deletenone();
4177c478bd9Sstevel@tonic-gate 	if (mode & 1) {
4187c478bd9Sstevel@tonic-gate 		if(FIXUNDO)
4197c478bd9Sstevel@tonic-gate 			undap1 = undap2 = addr2+1;
4207c478bd9Sstevel@tonic-gate 		(void)append(getfile, addr2);
4217c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
4227c478bd9Sstevel@tonic-gate 		if (trace)
4237c478bd9Sstevel@tonic-gate 			vudump(gettext("after append in filter"));
4247c478bd9Sstevel@tonic-gate #endif
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 	close(io);
4277c478bd9Sstevel@tonic-gate 	io = -1;
4287c478bd9Sstevel@tonic-gate 	unixwt(!inopen, f);
4297c478bd9Sstevel@tonic-gate 	if (pid2) {
4307c478bd9Sstevel@tonic-gate 		(void)kill(pid2, 9);
4317c478bd9Sstevel@tonic-gate 		do
4327c478bd9Sstevel@tonic-gate 			rpid = waitpid(pid2, &status2, 0);
4337c478bd9Sstevel@tonic-gate 		while (rpid == (pid_t)-1 && errno == EINTR);
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 	netchHAD(nlines);
436f6db9f27Scf46844 	return (0);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate /*
4407c478bd9Sstevel@tonic-gate  * Set up to do a recover, getting io to be a pipe from
4417c478bd9Sstevel@tonic-gate  * the recover process.
4427c478bd9Sstevel@tonic-gate  */
443f6db9f27Scf46844 void
444f6db9f27Scf46844 recover(void)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	static int pvec[2];
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if (pipe(pvec) < 0)
4497c478bd9Sstevel@tonic-gate 		error(gettext(" Can't make pipe for recovery"));
4507c478bd9Sstevel@tonic-gate 	pid = fork();
4517c478bd9Sstevel@tonic-gate 	io = pvec[0];
4527c478bd9Sstevel@tonic-gate 	if (pid < 0) {
4537c478bd9Sstevel@tonic-gate 		close(pvec[1]);
4547c478bd9Sstevel@tonic-gate 		error(gettext(" Can't fork to execute recovery"));
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 	if (pid == 0) {
4577c478bd9Sstevel@tonic-gate 		unsigned char cryptkey[19];
4587c478bd9Sstevel@tonic-gate 		close(2);
4597c478bd9Sstevel@tonic-gate 		dup(1);
4607c478bd9Sstevel@tonic-gate 		close(1);
4617c478bd9Sstevel@tonic-gate 		dup(pvec[1]);
4627c478bd9Sstevel@tonic-gate 	        close(pvec[1]);
4637c478bd9Sstevel@tonic-gate 		if(xflag) {
4647c478bd9Sstevel@tonic-gate 			strcpy(cryptkey, "CrYpTkEy=XXXXXXXXX");
4657c478bd9Sstevel@tonic-gate 			strcpy(cryptkey + 9, key);
4667c478bd9Sstevel@tonic-gate 			if(putenv((char *)cryptkey) != 0)
4677c478bd9Sstevel@tonic-gate 				smerror(gettext(" Cannot copy key to environment"));
4687c478bd9Sstevel@tonic-gate 			execlp(EXRECOVER, "exrecover", "-x", svalue(vi_DIRECTORY), file, (char *) 0);
4697c478bd9Sstevel@tonic-gate 		} else
4707c478bd9Sstevel@tonic-gate 			execlp(EXRECOVER, "exrecover", svalue(vi_DIRECTORY), file, (char *) 0);
4717c478bd9Sstevel@tonic-gate 		close(1);
4727c478bd9Sstevel@tonic-gate 		dup(2);
4737c478bd9Sstevel@tonic-gate 		error(gettext(" No recovery routine"));
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	close(pvec[1]);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * Wait for the process (pid an external) to complete.
4807c478bd9Sstevel@tonic-gate  */
481f6db9f27Scf46844 void
482f6db9f27Scf46844 waitfor(void)
4837c478bd9Sstevel@tonic-gate {
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	do
4867c478bd9Sstevel@tonic-gate 		rpid = waitpid(pid, &status, 0);
4877c478bd9Sstevel@tonic-gate 	while (rpid == (pid_t)-1 && errno != ECHILD);
4887c478bd9Sstevel@tonic-gate 	if ((status & 0377) == 0)
4897c478bd9Sstevel@tonic-gate 		status = (status >> 8) & 0377;
4907c478bd9Sstevel@tonic-gate 	else {
4917c478bd9Sstevel@tonic-gate 		/*
4927c478bd9Sstevel@tonic-gate 		 * TRANSLATION_NOTE
4937c478bd9Sstevel@tonic-gate 		 *	Reference order of arguments must not
4947c478bd9Sstevel@tonic-gate 		 *	be changed using '%digit$', since vi's
495f6db9f27Scf46844 		 *	viprintf() does not support it.
4967c478bd9Sstevel@tonic-gate 		 */
497f6db9f27Scf46844 		viprintf(gettext("%d: terminated with signal %d"), pid,
498f6db9f27Scf46844 		    status & 0177);
4997c478bd9Sstevel@tonic-gate 		if (status & 0200)
500f6db9f27Scf46844 			viprintf(gettext(" -- core dumped"));
5017c478bd9Sstevel@tonic-gate 		putchar('\n');
5027c478bd9Sstevel@tonic-gate 	}
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate /*
5067c478bd9Sstevel@tonic-gate  * The end of a recover operation.  If the process
5077c478bd9Sstevel@tonic-gate  * exits non-zero, force not edited; otherwise force
5087c478bd9Sstevel@tonic-gate  * a write.
5097c478bd9Sstevel@tonic-gate  */
510f6db9f27Scf46844 void
511f6db9f27Scf46844 revocer(void)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	waitfor();
5157c478bd9Sstevel@tonic-gate 	if (pid == rpid && status != 0)
5167c478bd9Sstevel@tonic-gate 		edited = 0;
5177c478bd9Sstevel@tonic-gate 	else
5187c478bd9Sstevel@tonic-gate 		change();
5197c478bd9Sstevel@tonic-gate }
520