1*536Smark /* Copyright (c) 1979 Regents of the University of California */ 2*536Smark #include "ex.h" 3*536Smark #include "ex_temp.h" 4*536Smark #include "ex_tty.h" 5*536Smark #include "ex_vis.h" 6*536Smark 7*536Smark /* 8*536Smark * Unix escapes, filtering 9*536Smark */ 10*536Smark 11*536Smark /* 12*536Smark * First part of a shell escape, 13*536Smark * parse the line, expanding # and % and ! and printing if implied. 14*536Smark */ 15*536Smark unix0(warn) 16*536Smark bool warn; 17*536Smark { 18*536Smark register char *up, *fp; 19*536Smark register short c; 20*536Smark char printub, puxb[UXBSIZE + sizeof (int)]; 21*536Smark 22*536Smark printub = 0; 23*536Smark CP(puxb, uxb); 24*536Smark c = getchar(); 25*536Smark if (c == '\n' || c == EOF) 26*536Smark error("Incomplete shell escape command@- use 'shell' to get a shell"); 27*536Smark up = uxb; 28*536Smark do { 29*536Smark switch (c) { 30*536Smark 31*536Smark case '\\': 32*536Smark if (any(peekchar(), "%#!")) 33*536Smark c = getchar(); 34*536Smark default: 35*536Smark if (up >= &uxb[UXBSIZE]) { 36*536Smark tunix: 37*536Smark uxb[0] = 0; 38*536Smark error("Command too long"); 39*536Smark } 40*536Smark *up++ = c; 41*536Smark break; 42*536Smark 43*536Smark case '!': 44*536Smark fp = puxb; 45*536Smark if (*fp == 0) { 46*536Smark uxb[0] = 0; 47*536Smark error("No previous command@to substitute for !"); 48*536Smark } 49*536Smark printub++; 50*536Smark while (*fp) { 51*536Smark if (up >= &uxb[UXBSIZE]) 52*536Smark goto tunix; 53*536Smark *up++ = *fp++; 54*536Smark } 55*536Smark break; 56*536Smark 57*536Smark case '#': 58*536Smark fp = altfile; 59*536Smark if (*fp == 0) { 60*536Smark uxb[0] = 0; 61*536Smark error("No alternate filename@to substitute for #"); 62*536Smark } 63*536Smark goto uexp; 64*536Smark 65*536Smark case '%': 66*536Smark fp = savedfile; 67*536Smark if (*fp == 0) { 68*536Smark uxb[0] = 0; 69*536Smark error("No filename@to substitute for %%"); 70*536Smark } 71*536Smark uexp: 72*536Smark printub++; 73*536Smark while (*fp) { 74*536Smark if (up >= &uxb[UXBSIZE]) 75*536Smark goto tunix; 76*536Smark *up++ = *fp++ | QUOTE; 77*536Smark } 78*536Smark break; 79*536Smark } 80*536Smark c = getchar(); 81*536Smark } while (c == '"' || c == '|' || !endcmd(c)); 82*536Smark if (c == EOF) 83*536Smark ungetchar(c); 84*536Smark *up = 0; 85*536Smark if (!inopen) 86*536Smark resetflav(); 87*536Smark if (warn) 88*536Smark ckaw(); 89*536Smark if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) { 90*536Smark xchng = chng; 91*536Smark vnfl(); 92*536Smark printf(mesg("[No write]|[No write since last change]")); 93*536Smark noonl(); 94*536Smark flush(); 95*536Smark } else 96*536Smark warn = 0; 97*536Smark if (printub) { 98*536Smark if (uxb[0] == 0) 99*536Smark error("No previous command@to repeat"); 100*536Smark if (inopen) { 101*536Smark splitw++; 102*536Smark vclean(); 103*536Smark vgoto(WECHO, 0); 104*536Smark } 105*536Smark if (warn) 106*536Smark vnfl(); 107*536Smark if (hush == 0) 108*536Smark lprintf("!%s", uxb); 109*536Smark if (inopen && Outchar != termchar) { 110*536Smark vclreol(); 111*536Smark vgoto(WECHO, 0); 112*536Smark } else 113*536Smark putnl(); 114*536Smark flush(); 115*536Smark } 116*536Smark } 117*536Smark 118*536Smark /* 119*536Smark * Do the real work for execution of a shell escape. 120*536Smark * Mode is like the number passed to open system calls 121*536Smark * and indicates filtering. If input is implied, newstdin 122*536Smark * must have been setup already. 123*536Smark */ 124*536Smark ttymode 125*536Smark unixex(opt, up, newstdin, mode) 126*536Smark char *opt, *up; 127*536Smark int newstdin, mode; 128*536Smark { 129*536Smark int pvec[2]; 130*536Smark ttymode f; 131*536Smark 132*536Smark signal(SIGINT, SIG_IGN); 133*536Smark #ifdef TIOCLGET 134*536Smark if (dosusp) 135*536Smark signal(SIGTSTP, SIG_DFL); 136*536Smark #endif 137*536Smark if (inopen) 138*536Smark f = setty(normf); 139*536Smark if ((mode & 1) && pipe(pvec) < 0) { 140*536Smark /* Newstdin should be io so it will be closed */ 141*536Smark if (inopen) 142*536Smark setty(f); 143*536Smark error("Can't make pipe for filter"); 144*536Smark } 145*536Smark #ifndef VFORK 146*536Smark pid = fork(); 147*536Smark #else 148*536Smark pid = vfork(); 149*536Smark #endif 150*536Smark if (pid < 0) { 151*536Smark if (mode & 1) { 152*536Smark close(pvec[0]); 153*536Smark close(pvec[1]); 154*536Smark } 155*536Smark setrupt(); 156*536Smark error("No more processes"); 157*536Smark } 158*536Smark if (pid == 0) { 159*536Smark if (mode & 2) { 160*536Smark close(0); 161*536Smark dup(newstdin); 162*536Smark close(newstdin); 163*536Smark } 164*536Smark if (mode & 1) { 165*536Smark close(pvec[0]); 166*536Smark close(1); 167*536Smark dup(pvec[1]); 168*536Smark if (inopen) { 169*536Smark close(2); 170*536Smark dup(1); 171*536Smark } 172*536Smark close(pvec[1]); 173*536Smark } 174*536Smark if (io) 175*536Smark close(io); 176*536Smark if (tfile) 177*536Smark close(tfile); 178*536Smark #ifndef VMUNIX 179*536Smark close(erfile); 180*536Smark #endif 181*536Smark signal(SIGHUP, oldhup); 182*536Smark signal(SIGQUIT, oldquit); 183*536Smark if (ruptible) 184*536Smark signal(SIGINT, SIG_DFL); 185*536Smark execl(svalue(SHELL), "sh", opt, up, (char *) 0); 186*536Smark printf("No %s!\n", svalue(SHELL)); 187*536Smark error(NOSTR); 188*536Smark } 189*536Smark if (mode & 1) { 190*536Smark io = pvec[0]; 191*536Smark close(pvec[1]); 192*536Smark } 193*536Smark if (newstdin) 194*536Smark close(newstdin); 195*536Smark return (f); 196*536Smark } 197*536Smark 198*536Smark /* 199*536Smark * Wait for the command to complete. 200*536Smark * F is for restoration of tty mode if from open/visual. 201*536Smark * C flags suppression of printing. 202*536Smark */ 203*536Smark unixwt(c, f) 204*536Smark bool c; 205*536Smark ttymode f; 206*536Smark { 207*536Smark 208*536Smark waitfor(); 209*536Smark #ifdef TIOCLGET 210*536Smark if (dosusp) 211*536Smark signal(SIGTSTP, onsusp); 212*536Smark #endif 213*536Smark if (inopen) 214*536Smark setty(f); 215*536Smark setrupt(); 216*536Smark if (!inopen && c && hush == 0) { 217*536Smark printf("!\n"); 218*536Smark flush(); 219*536Smark termreset(); 220*536Smark gettmode(); 221*536Smark } 222*536Smark } 223*536Smark 224*536Smark /* 225*536Smark * Setup a pipeline for the filtration implied by mode 226*536Smark * which is like a open number. If input is required to 227*536Smark * the filter, then a child editor is created to write it. 228*536Smark * If output is catch it from io which is created by unixex. 229*536Smark */ 230*536Smark filter(mode) 231*536Smark register int mode; 232*536Smark { 233*536Smark static int pvec[2]; 234*536Smark register ttymode f; 235*536Smark register int lines = lineDOL(); 236*536Smark 237*536Smark mode++; 238*536Smark if (mode & 2) { 239*536Smark signal(SIGINT, SIG_IGN); 240*536Smark if (pipe(pvec) < 0) 241*536Smark error("Can't make pipe"); 242*536Smark pid = fork(); 243*536Smark io = pvec[0]; 244*536Smark if (pid < 0) { 245*536Smark setrupt(); 246*536Smark close(pvec[1]); 247*536Smark error("No more processes"); 248*536Smark } 249*536Smark if (pid == 0) { 250*536Smark setrupt(); 251*536Smark io = pvec[1]; 252*536Smark close(pvec[0]); 253*536Smark putfile(); 254*536Smark exit(0); 255*536Smark } 256*536Smark close(pvec[1]); 257*536Smark io = pvec[0]; 258*536Smark setrupt(); 259*536Smark } 260*536Smark f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); 261*536Smark if (mode == 3) { 262*536Smark delete(0); 263*536Smark addr2 = addr1 - 1; 264*536Smark } 265*536Smark if (mode & 1) { 266*536Smark if(FIXUNDO) 267*536Smark undap1 = undap2 = addr2+1; 268*536Smark ignore(append(getfile, addr2)); 269*536Smark } 270*536Smark close(io); 271*536Smark io = -1; 272*536Smark unixwt(!inopen, f); 273*536Smark netchHAD(lines); 274*536Smark } 275*536Smark 276*536Smark /* 277*536Smark * Set up to do a recover, getting io to be a pipe from 278*536Smark * the recover process. 279*536Smark */ 280*536Smark recover() 281*536Smark { 282*536Smark static int pvec[2]; 283*536Smark 284*536Smark if (pipe(pvec) < 0) 285*536Smark error(" Can't make pipe for recovery"); 286*536Smark pid = fork(); 287*536Smark io = pvec[0]; 288*536Smark if (pid < 0) { 289*536Smark close(pvec[1]); 290*536Smark error(" Can't fork to execute recovery"); 291*536Smark } 292*536Smark if (pid == 0) { 293*536Smark close(2); 294*536Smark dup(1); 295*536Smark close(1); 296*536Smark dup(pvec[1]); 297*536Smark close(pvec[1]); 298*536Smark execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); 299*536Smark close(1); 300*536Smark dup(2); 301*536Smark error(" No recovery routine"); 302*536Smark } 303*536Smark close(pvec[1]); 304*536Smark } 305*536Smark 306*536Smark /* 307*536Smark * Wait for the process (pid an external) to complete. 308*536Smark */ 309*536Smark waitfor() 310*536Smark { 311*536Smark 312*536Smark do 313*536Smark rpid = wait(&status); 314*536Smark while (rpid != pid && rpid != -1); 315*536Smark status = (status >> 8) & 0377; 316*536Smark } 317*536Smark 318*536Smark /* 319*536Smark * The end of a recover operation. If the process 320*536Smark * exits non-zero, force not edited; otherwise force 321*536Smark * a write. 322*536Smark */ 323*536Smark revocer() 324*536Smark { 325*536Smark 326*536Smark waitfor(); 327*536Smark if (pid == rpid && status != 0) 328*536Smark edited = 0; 329*536Smark else 330*536Smark change(); 331*536Smark } 332