/*- * Copyright (c) 1980 The Regents of the University of California. * All rights reserved. * * %sccs.include.proprietary.c% */ #ifndef lint static char sccsid[] = "@(#)ex_unix.c 7.11 (Berkeley) 04/17/91"; #endif /* not lint */ #include "ex.h" #include "ex_temp.h" #include "ex_tty.h" #include "ex_vis.h" #include /* * 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 = ex_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 = ex_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; *up++ = *fp++ | QUOTE; } break; } c = ex_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(); ex_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; 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) ignore(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 (up) { register char *cp = up; while (*cp) *cp++ &= TRIM; } 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); #ifdef EXSTRINGS close(erfile); #endif signal(SIGHUP, oldhup); signal(SIGQUIT, oldquit); if (ruptible) signal(SIGINT, SIG_DFL); execl(svalue(SHELL), "sh", opt, up, (char *) 0); ex_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) ignore(setty(f)); setrupt(); if (!inopen && c && hush == 0) { ex_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); ex_exit(0); } close(pvec[1]); io = pvec[0]; setrupt(); } f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); if (mode == 3) { ex_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(_PATH_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() { union wait stat, pstat; int wpid; extern char *sys_siglist[]; pstat.w_status = 0; do { wpid = wait((int *)&stat); if (wpid == pid) { pstat = stat; rpid = wpid; } } while (wpid != -1); if (WIFEXITED(pstat)) status = pstat.w_retcode; else { ex_printf("%d: terminated abnormally: %s ", pid, sys_siglist[pstat.w_termsig]); if (pstat.w_coredump) ex_printf("(core dumped) "); if (!inopen) ex_printf("\r\n"); status = pstat.w_termsig; } } /* * 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(); }