1536Smark /* Copyright (c) 1979 Regents of the University of California */ 2*864Smark static char *sccsid = "@(#)ex_unix.c 5.2 09/12/80"; 3536Smark #include "ex.h" 4536Smark #include "ex_temp.h" 5536Smark #include "ex_tty.h" 6536Smark #include "ex_vis.h" 7536Smark 8536Smark /* 9536Smark * Unix escapes, filtering 10536Smark */ 11536Smark 12536Smark /* 13536Smark * First part of a shell escape, 14536Smark * parse the line, expanding # and % and ! and printing if implied. 15536Smark */ 16536Smark unix0(warn) 17536Smark bool warn; 18536Smark { 19536Smark register char *up, *fp; 20536Smark register short c; 21536Smark char printub, puxb[UXBSIZE + sizeof (int)]; 22536Smark 23536Smark printub = 0; 24536Smark CP(puxb, uxb); 25536Smark c = getchar(); 26536Smark if (c == '\n' || c == EOF) 27536Smark error("Incomplete shell escape command@- use 'shell' to get a shell"); 28536Smark up = uxb; 29536Smark do { 30536Smark switch (c) { 31536Smark 32536Smark case '\\': 33536Smark if (any(peekchar(), "%#!")) 34536Smark c = getchar(); 35536Smark default: 36536Smark if (up >= &uxb[UXBSIZE]) { 37536Smark tunix: 38536Smark uxb[0] = 0; 39536Smark error("Command too long"); 40536Smark } 41536Smark *up++ = c; 42536Smark break; 43536Smark 44536Smark case '!': 45536Smark fp = puxb; 46536Smark if (*fp == 0) { 47536Smark uxb[0] = 0; 48536Smark error("No previous command@to substitute for !"); 49536Smark } 50536Smark printub++; 51536Smark while (*fp) { 52536Smark if (up >= &uxb[UXBSIZE]) 53536Smark goto tunix; 54536Smark *up++ = *fp++; 55536Smark } 56536Smark break; 57536Smark 58536Smark case '#': 59536Smark fp = altfile; 60536Smark if (*fp == 0) { 61536Smark uxb[0] = 0; 62536Smark error("No alternate filename@to substitute for #"); 63536Smark } 64536Smark goto uexp; 65536Smark 66536Smark case '%': 67536Smark fp = savedfile; 68536Smark if (*fp == 0) { 69536Smark uxb[0] = 0; 70536Smark error("No filename@to substitute for %%"); 71536Smark } 72536Smark uexp: 73536Smark printub++; 74536Smark while (*fp) { 75536Smark if (up >= &uxb[UXBSIZE]) 76536Smark goto tunix; 77536Smark *up++ = *fp++ | QUOTE; 78536Smark } 79536Smark break; 80536Smark } 81536Smark c = getchar(); 82536Smark } while (c == '"' || c == '|' || !endcmd(c)); 83536Smark if (c == EOF) 84536Smark ungetchar(c); 85536Smark *up = 0; 86536Smark if (!inopen) 87536Smark resetflav(); 88536Smark if (warn) 89536Smark ckaw(); 90536Smark if (warn && hush == 0 && chng && xchng != chng && value(WARN) && dol > zero) { 91536Smark xchng = chng; 92536Smark vnfl(); 93536Smark printf(mesg("[No write]|[No write since last change]")); 94536Smark noonl(); 95536Smark flush(); 96536Smark } else 97536Smark warn = 0; 98536Smark if (printub) { 99536Smark if (uxb[0] == 0) 100536Smark error("No previous command@to repeat"); 101536Smark if (inopen) { 102536Smark splitw++; 103536Smark vclean(); 104536Smark vgoto(WECHO, 0); 105536Smark } 106536Smark if (warn) 107536Smark vnfl(); 108536Smark if (hush == 0) 109536Smark lprintf("!%s", uxb); 110536Smark if (inopen && Outchar != termchar) { 111536Smark vclreol(); 112536Smark vgoto(WECHO, 0); 113536Smark } else 114536Smark putnl(); 115536Smark flush(); 116536Smark } 117536Smark } 118536Smark 119536Smark /* 120536Smark * Do the real work for execution of a shell escape. 121536Smark * Mode is like the number passed to open system calls 122536Smark * and indicates filtering. If input is implied, newstdin 123536Smark * must have been setup already. 124536Smark */ 125536Smark ttymode 126536Smark unixex(opt, up, newstdin, mode) 127536Smark char *opt, *up; 128536Smark int newstdin, mode; 129536Smark { 130536Smark int pvec[2]; 131536Smark ttymode f; 132536Smark 133536Smark signal(SIGINT, SIG_IGN); 134*864Smark #ifdef SIGTSTP 135536Smark if (dosusp) 136536Smark signal(SIGTSTP, SIG_DFL); 137536Smark #endif 138536Smark if (inopen) 139536Smark f = setty(normf); 140536Smark if ((mode & 1) && pipe(pvec) < 0) { 141536Smark /* Newstdin should be io so it will be closed */ 142536Smark if (inopen) 143536Smark setty(f); 144536Smark error("Can't make pipe for filter"); 145536Smark } 146536Smark #ifndef VFORK 147536Smark pid = fork(); 148536Smark #else 149536Smark pid = vfork(); 150536Smark #endif 151536Smark if (pid < 0) { 152536Smark if (mode & 1) { 153536Smark close(pvec[0]); 154536Smark close(pvec[1]); 155536Smark } 156536Smark setrupt(); 157536Smark error("No more processes"); 158536Smark } 159536Smark if (pid == 0) { 160536Smark if (mode & 2) { 161536Smark close(0); 162536Smark dup(newstdin); 163536Smark close(newstdin); 164536Smark } 165536Smark if (mode & 1) { 166536Smark close(pvec[0]); 167536Smark close(1); 168536Smark dup(pvec[1]); 169536Smark if (inopen) { 170536Smark close(2); 171536Smark dup(1); 172536Smark } 173536Smark close(pvec[1]); 174536Smark } 175536Smark if (io) 176536Smark close(io); 177536Smark if (tfile) 178536Smark close(tfile); 179536Smark #ifndef VMUNIX 180536Smark close(erfile); 181536Smark #endif 182536Smark signal(SIGHUP, oldhup); 183536Smark signal(SIGQUIT, oldquit); 184536Smark if (ruptible) 185536Smark signal(SIGINT, SIG_DFL); 186536Smark execl(svalue(SHELL), "sh", opt, up, (char *) 0); 187536Smark printf("No %s!\n", svalue(SHELL)); 188536Smark error(NOSTR); 189536Smark } 190536Smark if (mode & 1) { 191536Smark io = pvec[0]; 192536Smark close(pvec[1]); 193536Smark } 194536Smark if (newstdin) 195536Smark close(newstdin); 196536Smark return (f); 197536Smark } 198536Smark 199536Smark /* 200536Smark * Wait for the command to complete. 201536Smark * F is for restoration of tty mode if from open/visual. 202536Smark * C flags suppression of printing. 203536Smark */ 204536Smark unixwt(c, f) 205536Smark bool c; 206536Smark ttymode f; 207536Smark { 208536Smark 209536Smark waitfor(); 210*864Smark #ifdef SIGTSTP 211536Smark if (dosusp) 212536Smark signal(SIGTSTP, onsusp); 213536Smark #endif 214536Smark if (inopen) 215536Smark setty(f); 216536Smark setrupt(); 217536Smark if (!inopen && c && hush == 0) { 218536Smark printf("!\n"); 219536Smark flush(); 220536Smark termreset(); 221536Smark gettmode(); 222536Smark } 223536Smark } 224536Smark 225536Smark /* 226536Smark * Setup a pipeline for the filtration implied by mode 227536Smark * which is like a open number. If input is required to 228536Smark * the filter, then a child editor is created to write it. 229536Smark * If output is catch it from io which is created by unixex. 230536Smark */ 231536Smark filter(mode) 232536Smark register int mode; 233536Smark { 234536Smark static int pvec[2]; 235536Smark register ttymode f; 236536Smark register int lines = lineDOL(); 237536Smark 238536Smark mode++; 239536Smark if (mode & 2) { 240536Smark signal(SIGINT, SIG_IGN); 241536Smark if (pipe(pvec) < 0) 242536Smark error("Can't make pipe"); 243536Smark pid = fork(); 244536Smark io = pvec[0]; 245536Smark if (pid < 0) { 246536Smark setrupt(); 247536Smark close(pvec[1]); 248536Smark error("No more processes"); 249536Smark } 250536Smark if (pid == 0) { 251536Smark setrupt(); 252536Smark io = pvec[1]; 253536Smark close(pvec[0]); 254536Smark putfile(); 255536Smark exit(0); 256536Smark } 257536Smark close(pvec[1]); 258536Smark io = pvec[0]; 259536Smark setrupt(); 260536Smark } 261536Smark f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); 262536Smark if (mode == 3) { 263536Smark delete(0); 264536Smark addr2 = addr1 - 1; 265536Smark } 266536Smark if (mode & 1) { 267536Smark if(FIXUNDO) 268536Smark undap1 = undap2 = addr2+1; 269536Smark ignore(append(getfile, addr2)); 270536Smark } 271536Smark close(io); 272536Smark io = -1; 273536Smark unixwt(!inopen, f); 274536Smark netchHAD(lines); 275536Smark } 276536Smark 277536Smark /* 278536Smark * Set up to do a recover, getting io to be a pipe from 279536Smark * the recover process. 280536Smark */ 281536Smark recover() 282536Smark { 283536Smark static int pvec[2]; 284536Smark 285536Smark if (pipe(pvec) < 0) 286536Smark error(" Can't make pipe for recovery"); 287536Smark pid = fork(); 288536Smark io = pvec[0]; 289536Smark if (pid < 0) { 290536Smark close(pvec[1]); 291536Smark error(" Can't fork to execute recovery"); 292536Smark } 293536Smark if (pid == 0) { 294536Smark close(2); 295536Smark dup(1); 296536Smark close(1); 297536Smark dup(pvec[1]); 298536Smark close(pvec[1]); 299536Smark execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); 300536Smark close(1); 301536Smark dup(2); 302536Smark error(" No recovery routine"); 303536Smark } 304536Smark close(pvec[1]); 305536Smark } 306536Smark 307536Smark /* 308536Smark * Wait for the process (pid an external) to complete. 309536Smark */ 310536Smark waitfor() 311536Smark { 312536Smark 313536Smark do 314536Smark rpid = wait(&status); 315536Smark while (rpid != pid && rpid != -1); 316536Smark status = (status >> 8) & 0377; 317536Smark } 318536Smark 319536Smark /* 320536Smark * The end of a recover operation. If the process 321536Smark * exits non-zero, force not edited; otherwise force 322536Smark * a write. 323536Smark */ 324536Smark revocer() 325536Smark { 326536Smark 327536Smark waitfor(); 328536Smark if (pid == rpid && status != 0) 329536Smark edited = 0; 330536Smark else 331536Smark change(); 332536Smark } 333