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