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