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