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