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 8*35292Skarels static char *sccsid = "@(#)ex_unix.c 7.8 (Berkeley) 07/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" 15*35292Skarels #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) { 169536Smark if (mode & 2) { 170536Smark close(0); 171536Smark dup(newstdin); 172536Smark close(newstdin); 173536Smark } 174536Smark if (mode & 1) { 175536Smark close(pvec[0]); 176536Smark close(1); 177536Smark dup(pvec[1]); 178536Smark if (inopen) { 179536Smark close(2); 180536Smark dup(1); 181536Smark } 182536Smark close(pvec[1]); 183536Smark } 184536Smark if (io) 185536Smark close(io); 186536Smark if (tfile) 187536Smark close(tfile); 18830596Sconrad #ifdef EXSTRINGS 189536Smark close(erfile); 190536Smark #endif 191536Smark signal(SIGHUP, oldhup); 192536Smark signal(SIGQUIT, oldquit); 193536Smark if (ruptible) 194536Smark signal(SIGINT, SIG_DFL); 195536Smark execl(svalue(SHELL), "sh", opt, up, (char *) 0); 19630596Sconrad ex_printf("No %s!\n", svalue(SHELL)); 197536Smark error(NOSTR); 198536Smark } 199536Smark if (mode & 1) { 200536Smark io = pvec[0]; 201536Smark close(pvec[1]); 202536Smark } 203536Smark if (newstdin) 204536Smark close(newstdin); 205536Smark return (f); 206536Smark } 207536Smark 208536Smark /* 209536Smark * Wait for the command to complete. 210536Smark * F is for restoration of tty mode if from open/visual. 211536Smark * C flags suppression of printing. 212536Smark */ 213536Smark unixwt(c, f) 214536Smark bool c; 215536Smark ttymode f; 216536Smark { 217536Smark 218536Smark waitfor(); 219864Smark #ifdef SIGTSTP 220536Smark if (dosusp) 221536Smark signal(SIGTSTP, onsusp); 222536Smark #endif 223536Smark if (inopen) 22430596Sconrad ignore(setty(f)); 225536Smark setrupt(); 226536Smark if (!inopen && c && hush == 0) { 22730596Sconrad ex_printf("!\n"); 228536Smark flush(); 229536Smark termreset(); 230536Smark gettmode(); 231536Smark } 232536Smark } 233536Smark 234536Smark /* 235536Smark * Setup a pipeline for the filtration implied by mode 236536Smark * which is like a open number. If input is required to 237536Smark * the filter, then a child editor is created to write it. 238536Smark * If output is catch it from io which is created by unixex. 239536Smark */ 240536Smark filter(mode) 241536Smark register int mode; 242536Smark { 243536Smark static int pvec[2]; 24421692Sdist ttymode f; /* mjm: was register */ 245536Smark register int lines = lineDOL(); 24621692Sdist struct stat statb; 247536Smark 248536Smark mode++; 249536Smark if (mode & 2) { 250536Smark signal(SIGINT, SIG_IGN); 251536Smark if (pipe(pvec) < 0) 252536Smark error("Can't make pipe"); 253536Smark pid = fork(); 254536Smark io = pvec[0]; 255536Smark if (pid < 0) { 256536Smark setrupt(); 257536Smark close(pvec[1]); 258536Smark error("No more processes"); 259536Smark } 260536Smark if (pid == 0) { 261536Smark setrupt(); 262536Smark io = pvec[1]; 263536Smark close(pvec[0]); 26421692Sdist putfile(1); 26530596Sconrad ex_exit(0); 266536Smark } 267536Smark close(pvec[1]); 268536Smark io = pvec[0]; 269536Smark setrupt(); 270536Smark } 271536Smark f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); 272536Smark if (mode == 3) { 27330596Sconrad ex_delete(0); 274536Smark addr2 = addr1 - 1; 275536Smark } 276536Smark if (mode & 1) { 277536Smark if(FIXUNDO) 278536Smark undap1 = undap2 = addr2+1; 27921692Sdist if (fstat(io, &statb) < 0) 28021692Sdist bsize = LBSIZE; 28121692Sdist else { 28221692Sdist bsize = statb.st_blksize; 28321692Sdist if (bsize <= 0) 28421692Sdist bsize = LBSIZE; 28521692Sdist } 286536Smark ignore(append(getfile, addr2)); 28721692Sdist #ifdef TRACE 28821692Sdist if (trace) 28921692Sdist vudump("after append in filter"); 29021692Sdist #endif 291536Smark } 292536Smark close(io); 293536Smark io = -1; 294536Smark unixwt(!inopen, f); 295536Smark netchHAD(lines); 296536Smark } 297536Smark 298536Smark /* 299536Smark * Set up to do a recover, getting io to be a pipe from 300536Smark * the recover process. 301536Smark */ 302536Smark recover() 303536Smark { 304536Smark static int pvec[2]; 305536Smark 306536Smark if (pipe(pvec) < 0) 307536Smark error(" Can't make pipe for recovery"); 308536Smark pid = fork(); 309536Smark io = pvec[0]; 310536Smark if (pid < 0) { 311536Smark close(pvec[1]); 312536Smark error(" Can't fork to execute recovery"); 313536Smark } 314536Smark if (pid == 0) { 315536Smark close(2); 316536Smark dup(1); 317536Smark close(1); 318536Smark dup(pvec[1]); 319536Smark close(pvec[1]); 320536Smark execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); 321536Smark close(1); 322536Smark dup(2); 323536Smark error(" No recovery routine"); 324536Smark } 325536Smark close(pvec[1]); 326536Smark } 327536Smark 328536Smark /* 329536Smark * Wait for the process (pid an external) to complete. 330536Smark */ 331536Smark waitfor() 332536Smark { 333*35292Skarels union wait stat, pstat; 334*35292Skarels int wpid; 335*35292Skarels extern char *sys_siglist[]; 336536Smark 337*35292Skarels pstat.w_status = 0; 33825248Sbloom do { 339*35292Skarels wpid = wait(&stat); 340*35292Skarels if (wpid == pid) { 341*35292Skarels pstat = stat; 342*35292Skarels rpid = wpid; 343*35292Skarels } 344*35292Skarels } while (wpid != -1); 345*35292Skarels 346*35292Skarels if (WIFEXITED(pstat)) 347*35292Skarels status = pstat.w_retcode; 348*35292Skarels else { 349*35292Skarels ex_printf("%d: terminated abnormally: %s ", 350*35292Skarels pid, sys_siglist[pstat.w_termsig]); 351*35292Skarels if (pstat.w_coredump) 352*35292Skarels ex_printf("(core dumped) "); 353*35292Skarels if (!inopen) 354*35292Skarels ex_printf("\r\n"); 355*35292Skarels status = pstat.w_termsig; 356*35292Skarels } 357536Smark } 358536Smark 359536Smark /* 360536Smark * The end of a recover operation. If the process 361536Smark * exits non-zero, force not edited; otherwise force 362536Smark * a write. 363536Smark */ 364536Smark revocer() 365536Smark { 366536Smark 367536Smark waitfor(); 368536Smark if (pid == rpid && status != 0) 369536Smark edited = 0; 370536Smark else 371536Smark change(); 372536Smark } 373