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 #ifndef lint 8 static char *sccsid = "@(#)ex_unix.c 7.7 (Berkeley) 03/09/87"; 9 #endif not lint 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 = ex_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 = ex_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 = ex_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 ex_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 ignore(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 #ifdef EXSTRINGS 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 ex_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 ignore(setty(f)); 224 setrupt(); 225 if (!inopen && c && hush == 0) { 226 ex_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 ex_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 ex_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 } 356