121667Sdist /* 221667Sdist * Copyright (c) 1980 Regents of the University of California. 321667Sdist * All rights reserved. The Berkeley software License Agreement 421667Sdist * specifies the terms and conditions for redistribution. 521667Sdist */ 621667Sdist 721667Sdist #ifndef lint 844576Smarc static char *sccsid = "@(#)ex_unix.c 7.8 (Berkeley) 7/28/88"; 921667Sdist #endif not lint 1021667Sdist 11536Smark #include "ex.h" 12536Smark #include "ex_temp.h" 13536Smark #include "ex_tty.h" 14536Smark #include "ex_vis.h" 1535292Skarels #include <sys/wait.h> 16536Smark 17536Smark /* 18536Smark * Unix escapes, filtering 19536Smark */ 20536Smark 21536Smark /* 22536Smark * First part of a shell escape, 23536Smark * parse the line, expanding # and % and ! and printing if implied. 24536Smark */ 25536Smark unix0(warn) 26536Smark bool warn; 27536Smark { 28536Smark register char *up, *fp; 29536Smark register short c; 30536Smark char printub, puxb[UXBSIZE + sizeof (int)]; 31536Smark 32536Smark printub = 0; 33536Smark CP(puxb, uxb); 3430596Sconrad c = ex_getchar(); 35536Smark if (c == '\n' || c == EOF) 36536Smark error("Incomplete shell escape command@- use 'shell' to get a shell"); 37536Smark up = uxb; 38536Smark do { 39536Smark switch (c) { 40536Smark 41536Smark case '\\': 42536Smark if (any(peekchar(), "%#!")) 4330596Sconrad c = ex_getchar(); 44536Smark default: 45536Smark if (up >= &uxb[UXBSIZE]) { 46536Smark tunix: 47536Smark uxb[0] = 0; 48536Smark error("Command too long"); 49536Smark } 50536Smark *up++ = c; 51536Smark break; 52536Smark 53536Smark case '!': 54536Smark fp = puxb; 55536Smark if (*fp == 0) { 56536Smark uxb[0] = 0; 57536Smark error("No previous command@to substitute for !"); 58536Smark } 59536Smark printub++; 60536Smark while (*fp) { 61536Smark if (up >= &uxb[UXBSIZE]) 62536Smark goto tunix; 63536Smark *up++ = *fp++; 64536Smark } 65536Smark break; 66536Smark 67536Smark case '#': 68536Smark fp = altfile; 69536Smark if (*fp == 0) { 70536Smark uxb[0] = 0; 71536Smark error("No alternate filename@to substitute for #"); 72536Smark } 73536Smark goto uexp; 74536Smark 75536Smark case '%': 76536Smark fp = savedfile; 77536Smark if (*fp == 0) { 78536Smark uxb[0] = 0; 79536Smark error("No filename@to substitute for %%"); 80536Smark } 81536Smark uexp: 82536Smark printub++; 83536Smark while (*fp) { 84536Smark if (up >= &uxb[UXBSIZE]) 85536Smark goto tunix; 86536Smark *up++ = *fp++ | QUOTE; 87536Smark } 88536Smark break; 89536Smark } 9030596Sconrad c = ex_getchar(); 91536Smark } while (c == '"' || c == '|' || !endcmd(c)); 92536Smark if (c == EOF) 93536Smark ungetchar(c); 94536Smark *up = 0; 95536Smark if (!inopen) 96536Smark resetflav(); 97536Smark if (warn) 98536Smark ckaw(); 99536Smark if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) { 100536Smark xchng = chng; 101536Smark vnfl(); 10230596Sconrad ex_printf(mesg("[No write]|[No write since last change]")); 103536Smark noonl(); 104536Smark flush(); 105536Smark } else 106536Smark warn = 0; 107536Smark if (printub) { 108536Smark if (uxb[0] == 0) 109536Smark error("No previous command@to repeat"); 110536Smark if (inopen) { 111536Smark splitw++; 112536Smark vclean(); 113536Smark vgoto(WECHO, 0); 114536Smark } 115536Smark if (warn) 116536Smark vnfl(); 117536Smark if (hush == 0) 118536Smark lprintf("!%s", uxb); 119536Smark if (inopen && Outchar != termchar) { 120536Smark vclreol(); 121536Smark vgoto(WECHO, 0); 122536Smark } else 123536Smark putnl(); 124536Smark flush(); 125536Smark } 126536Smark } 127536Smark 128536Smark /* 129536Smark * Do the real work for execution of a shell escape. 130536Smark * Mode is like the number passed to open system calls 131536Smark * and indicates filtering. If input is implied, newstdin 132536Smark * must have been setup already. 133536Smark */ 134536Smark ttymode 135536Smark unixex(opt, up, newstdin, mode) 136536Smark char *opt, *up; 137536Smark int newstdin, mode; 138536Smark { 139536Smark int pvec[2]; 140536Smark ttymode f; 141536Smark 142536Smark signal(SIGINT, SIG_IGN); 143864Smark #ifdef SIGTSTP 144536Smark if (dosusp) 145536Smark signal(SIGTSTP, SIG_DFL); 146536Smark #endif 147536Smark if (inopen) 148536Smark f = setty(normf); 149536Smark if ((mode & 1) && pipe(pvec) < 0) { 150536Smark /* Newstdin should be io so it will be closed */ 151536Smark if (inopen) 15230596Sconrad ignore(setty(f)); 153536Smark error("Can't make pipe for filter"); 154536Smark } 155536Smark #ifndef VFORK 156536Smark pid = fork(); 157536Smark #else 158536Smark pid = vfork(); 159536Smark #endif 160536Smark if (pid < 0) { 161536Smark if (mode & 1) { 162536Smark close(pvec[0]); 163536Smark close(pvec[1]); 164536Smark } 165536Smark setrupt(); 166536Smark error("No more processes"); 167536Smark } 168536Smark if (pid == 0) { 16944576Smarc if (up) { 17044576Smarc register char *cp = up; 17144576Smarc while (*cp) 17244576Smarc *cp++ &= TRIM; 17344576Smarc } 174536Smark if (mode & 2) { 175536Smark close(0); 176536Smark dup(newstdin); 177536Smark close(newstdin); 178536Smark } 179536Smark if (mode & 1) { 180536Smark close(pvec[0]); 181536Smark close(1); 182536Smark dup(pvec[1]); 183536Smark if (inopen) { 184536Smark close(2); 185536Smark dup(1); 186536Smark } 187536Smark close(pvec[1]); 188536Smark } 189536Smark if (io) 190536Smark close(io); 191536Smark if (tfile) 192536Smark close(tfile); 19330596Sconrad #ifdef EXSTRINGS 194536Smark close(erfile); 195536Smark #endif 196536Smark signal(SIGHUP, oldhup); 197536Smark signal(SIGQUIT, oldquit); 198536Smark if (ruptible) 199536Smark signal(SIGINT, SIG_DFL); 200536Smark execl(svalue(SHELL), "sh", opt, up, (char *) 0); 20130596Sconrad ex_printf("No %s!\n", svalue(SHELL)); 202536Smark error(NOSTR); 203536Smark } 204536Smark if (mode & 1) { 205536Smark io = pvec[0]; 206536Smark close(pvec[1]); 207536Smark } 208536Smark if (newstdin) 209536Smark close(newstdin); 210536Smark return (f); 211536Smark } 212536Smark 213536Smark /* 214536Smark * Wait for the command to complete. 215536Smark * F is for restoration of tty mode if from open/visual. 216536Smark * C flags suppression of printing. 217536Smark */ 218536Smark unixwt(c, f) 219536Smark bool c; 220536Smark ttymode f; 221536Smark { 222536Smark 223536Smark waitfor(); 224864Smark #ifdef SIGTSTP 225536Smark if (dosusp) 226536Smark signal(SIGTSTP, onsusp); 227536Smark #endif 228536Smark if (inopen) 22930596Sconrad ignore(setty(f)); 230536Smark setrupt(); 231536Smark if (!inopen && c && hush == 0) { 23230596Sconrad ex_printf("!\n"); 233536Smark flush(); 234536Smark termreset(); 235536Smark gettmode(); 236536Smark } 237536Smark } 238536Smark 239536Smark /* 240536Smark * Setup a pipeline for the filtration implied by mode 241536Smark * which is like a open number. If input is required to 242536Smark * the filter, then a child editor is created to write it. 243536Smark * If output is catch it from io which is created by unixex. 244536Smark */ 245536Smark filter(mode) 246536Smark register int mode; 247536Smark { 248536Smark static int pvec[2]; 24921692Sdist ttymode f; /* mjm: was register */ 250536Smark register int lines = lineDOL(); 25121692Sdist struct stat statb; 252536Smark 253536Smark mode++; 254536Smark if (mode & 2) { 255536Smark signal(SIGINT, SIG_IGN); 256536Smark if (pipe(pvec) < 0) 257536Smark error("Can't make pipe"); 258536Smark pid = fork(); 259536Smark io = pvec[0]; 260536Smark if (pid < 0) { 261536Smark setrupt(); 262536Smark close(pvec[1]); 263536Smark error("No more processes"); 264536Smark } 265536Smark if (pid == 0) { 266536Smark setrupt(); 267536Smark io = pvec[1]; 268536Smark close(pvec[0]); 26921692Sdist putfile(1); 27030596Sconrad ex_exit(0); 271536Smark } 272536Smark close(pvec[1]); 273536Smark io = pvec[0]; 274536Smark setrupt(); 275536Smark } 276536Smark f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); 277536Smark if (mode == 3) { 27830596Sconrad ex_delete(0); 279536Smark addr2 = addr1 - 1; 280536Smark } 281536Smark if (mode & 1) { 282536Smark if(FIXUNDO) 283536Smark undap1 = undap2 = addr2+1; 28421692Sdist if (fstat(io, &statb) < 0) 28521692Sdist bsize = LBSIZE; 28621692Sdist else { 28721692Sdist bsize = statb.st_blksize; 28821692Sdist if (bsize <= 0) 28921692Sdist bsize = LBSIZE; 29021692Sdist } 291536Smark ignore(append(getfile, addr2)); 29221692Sdist #ifdef TRACE 29321692Sdist if (trace) 29421692Sdist vudump("after append in filter"); 29521692Sdist #endif 296536Smark } 297536Smark close(io); 298536Smark io = -1; 299536Smark unixwt(!inopen, f); 300536Smark netchHAD(lines); 301536Smark } 302536Smark 303536Smark /* 304536Smark * Set up to do a recover, getting io to be a pipe from 305536Smark * the recover process. 306536Smark */ 307536Smark recover() 308536Smark { 309536Smark static int pvec[2]; 310536Smark 311536Smark if (pipe(pvec) < 0) 312536Smark error(" Can't make pipe for recovery"); 313536Smark pid = fork(); 314536Smark io = pvec[0]; 315536Smark if (pid < 0) { 316536Smark close(pvec[1]); 317536Smark error(" Can't fork to execute recovery"); 318536Smark } 319536Smark if (pid == 0) { 320536Smark close(2); 321536Smark dup(1); 322536Smark close(1); 323536Smark dup(pvec[1]); 324536Smark close(pvec[1]); 32544576Smarc execl(_PATH_EXRECOVER, "exrecover", svalue(DIRECTORY), 32644576Smarc file, (char *) 0); 327536Smark close(1); 328536Smark dup(2); 329536Smark error(" No recovery routine"); 330536Smark } 331536Smark close(pvec[1]); 332536Smark } 333536Smark 334536Smark /* 335536Smark * Wait for the process (pid an external) to complete. 336536Smark */ 337536Smark waitfor() 338536Smark { 33935292Skarels union wait stat, pstat; 34035292Skarels int wpid; 34135292Skarels extern char *sys_siglist[]; 342536Smark 34335292Skarels pstat.w_status = 0; 34425248Sbloom do { 345*46826Sbostic wpid = wait((int *)&stat); 34635292Skarels if (wpid == pid) { 34735292Skarels pstat = stat; 34835292Skarels rpid = wpid; 34935292Skarels } 35035292Skarels } while (wpid != -1); 35135292Skarels 35235292Skarels if (WIFEXITED(pstat)) 35335292Skarels status = pstat.w_retcode; 35435292Skarels else { 35535292Skarels ex_printf("%d: terminated abnormally: %s ", 35635292Skarels pid, sys_siglist[pstat.w_termsig]); 35735292Skarels if (pstat.w_coredump) 35835292Skarels ex_printf("(core dumped) "); 35935292Skarels if (!inopen) 36035292Skarels ex_printf("\r\n"); 36135292Skarels status = pstat.w_termsig; 36235292Skarels } 363536Smark } 364536Smark 365536Smark /* 366536Smark * The end of a recover operation. If the process 367536Smark * exits non-zero, force not edited; otherwise force 368536Smark * a write. 369536Smark */ 370536Smark revocer() 371536Smark { 372536Smark 373536Smark waitfor(); 374536Smark if (pid == rpid && status != 0) 375536Smark edited = 0; 376536Smark else 377536Smark change(); 378536Smark } 379