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