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