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