/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #if !defined(lint) && defined(DOSCCS) static char *sccsid = "@(#)ex_unix.c 7.6 (Berkeley) 10/22/85"; #endif #include "ex.h" #include "ex_temp.h" #include "ex_tty.h" #include "ex_vis.h" /* * Unix escapes, filtering */ /* * First part of a shell escape, * parse the line, expanding # and % and ! and printing if implied. */ unix0(warn) bool warn; { register char *up, *fp; register short c; char printub, puxb[UXBSIZE + sizeof (int)]; printub = 0; CP(puxb, uxb); c = getchar(); if (c == '\n' || c == EOF) error("Incomplete shell escape command@- use 'shell' to get a shell"); up = uxb; do { switch (c) { case '\\': if (any(peekchar(), "%#!")) c = getchar(); default: if (up >= &uxb[UXBSIZE]) { tunix: uxb[0] = 0; error("Command too long"); } *up++ = c; break; case '!': fp = puxb; if (*fp == 0) { uxb[0] = 0; error("No previous command@to substitute for !"); } printub++; while (*fp) { if (up >= &uxb[UXBSIZE]) goto tunix; *up++ = *fp++; } break; case '#': fp = altfile; if (*fp == 0) { uxb[0] = 0; error("No alternate filename@to substitute for #"); } goto uexp; case '%': fp = savedfile; if (*fp == 0) { uxb[0] = 0; error("No filename@to substitute for %%"); } uexp: printub++; while (*fp) { if (up >= &uxb[UXBSIZE]) goto tunix; #ifdef BIT8 /* XXX */ /* GR */ abort(); #endif *up++ = *fp++ | QUOTE; } break; } c = getchar(); } while (c == '"' || c == '|' || !endcmd(c)); if (c == EOF) ungetchar(c); *up = 0; if (!inopen) resetflav(); if (warn) ckaw(); if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) { xchng = chng; vnfl(); printf(mesg("[No write]|[No write since last change]")); noonl(); flush(); } else warn = 0; if (printub) { if (uxb[0] == 0) error("No previous command@to repeat"); if (inopen) { splitw++; vclean(); vgoto(WECHO, 0); } if (warn) vnfl(); if (hush == 0) lprintf("!%s", uxb); if (inopen && Outchar != termchar) { vclreol(); vgoto(WECHO, 0); } else putnl(); flush(); } } /* * Do the real work for execution of a shell escape. * Mode is like the number passed to open system calls * and indicates filtering. If input is implied, newstdin * must have been setup already. */ ttymode unixex(opt, up, newstdin, mode) char *opt, *up; int newstdin, mode; { int pvec[2]; ttymode f; char euxb[UXBSIZE + sizeof (int)]; char *p; /* dequote the unix command */ CP(euxb,up); for (p = euxb; *p; ++p) *p &= ~QUOTE; signal(SIGINT, SIG_IGN); #ifdef SIGTSTP if (dosusp) signal(SIGTSTP, SIG_DFL); #endif if (inopen) f = setty(normf); if ((mode & 1) && pipe(pvec) < 0) { /* Newstdin should be io so it will be closed */ if (inopen) setty(f); error("Can't make pipe for filter"); } #ifndef VFORK pid = fork(); #else pid = vfork(); #endif if (pid < 0) { if (mode & 1) { close(pvec[0]); close(pvec[1]); } setrupt(); error("No more processes"); } if (pid == 0) { if (mode & 2) { close(0); dup(newstdin); close(newstdin); } if (mode & 1) { close(pvec[0]); close(1); dup(pvec[1]); if (inopen) { close(2); dup(1); } close(pvec[1]); } if (io) close(io); if (tfile) close(tfile); #ifndef VMUNIX close(erfile); #endif signal(SIGHUP, oldhup); signal(SIGQUIT, oldquit); if (ruptible) signal(SIGINT, SIG_DFL); execl(svalue(SHELL), "sh", opt, euxb, (char *) 0); printf("No %s!\n", svalue(SHELL)); error(NOSTR); } if (mode & 1) { io = pvec[0]; close(pvec[1]); } if (newstdin) close(newstdin); return (f); } /* * Wait for the command to complete. * F is for restoration of tty mode if from open/visual. * C flags suppression of printing. */ unixwt(c, f) bool c; ttymode f; { waitfor(); #ifdef SIGTSTP if (dosusp) signal(SIGTSTP, onsusp); #endif if (inopen) setty(f); setrupt(); if (!inopen && c && hush == 0) { printf("!\n"); flush(); termreset(); gettmode(); } } /* * Setup a pipeline for the filtration implied by mode * which is like a open number. If input is required to * the filter, then a child editor is created to write it. * If output is catch it from io which is created by unixex. */ filter(mode) register int mode; { static int pvec[2]; ttymode f; /* mjm: was register */ register int lines = lineDOL(); struct stat statb; mode++; if (mode & 2) { signal(SIGINT, SIG_IGN); if (pipe(pvec) < 0) error("Can't make pipe"); pid = fork(); io = pvec[0]; if (pid < 0) { setrupt(); close(pvec[1]); error("No more processes"); } if (pid == 0) { setrupt(); io = pvec[1]; close(pvec[0]); putfile(1); exit(0); } close(pvec[1]); io = pvec[0]; setrupt(); } f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); if (mode == 3) { delete(0); addr2 = addr1 - 1; } if (mode & 1) { if(FIXUNDO) undap1 = undap2 = addr2+1; if (fstat(io, &statb) < 0) bsize = LBSIZE; else { bsize = statb.st_blksize; if (bsize <= 0) bsize = LBSIZE; } ignore(append(getfile, addr2)); #ifdef TRACE if (trace) vudump("after append in filter"); #endif } close(io); io = -1; unixwt(!inopen, f); netchHAD(lines); } /* * Set up to do a recover, getting io to be a pipe from * the recover process. */ recover() { static int pvec[2]; if (pipe(pvec) < 0) error(" Can't make pipe for recovery"); pid = fork(); io = pvec[0]; if (pid < 0) { close(pvec[1]); error(" Can't fork to execute recovery"); } if (pid == 0) { close(2); dup(1); close(1); dup(pvec[1]); close(pvec[1]); execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); close(1); dup(2); error(" No recovery routine"); } close(pvec[1]); } /* * Wait for the process (pid an external) to complete. */ waitfor() { int stat = 0; do { rpid = wait(&stat); if (rpid == pid) status = stat; } while (rpid != -1); status = (status >> 8) & 0377; } /* * The end of a recover operation. If the process * exits non-zero, force not edited; otherwise force * a write. */ revocer() { waitfor(); if (pid == rpid && status != 0) edited = 0; else change(); }