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) 07/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 (mode & 2) { 170 close(0); 171 dup(newstdin); 172 close(newstdin); 173 } 174 if (mode & 1) { 175 close(pvec[0]); 176 close(1); 177 dup(pvec[1]); 178 if (inopen) { 179 close(2); 180 dup(1); 181 } 182 close(pvec[1]); 183 } 184 if (io) 185 close(io); 186 if (tfile) 187 close(tfile); 188 #ifdef EXSTRINGS 189 close(erfile); 190 #endif 191 signal(SIGHUP, oldhup); 192 signal(SIGQUIT, oldquit); 193 if (ruptible) 194 signal(SIGINT, SIG_DFL); 195 execl(svalue(SHELL), "sh", opt, up, (char *) 0); 196 ex_printf("No %s!\n", svalue(SHELL)); 197 error(NOSTR); 198 } 199 if (mode & 1) { 200 io = pvec[0]; 201 close(pvec[1]); 202 } 203 if (newstdin) 204 close(newstdin); 205 return (f); 206 } 207 208 /* 209 * Wait for the command to complete. 210 * F is for restoration of tty mode if from open/visual. 211 * C flags suppression of printing. 212 */ 213 unixwt(c, f) 214 bool c; 215 ttymode f; 216 { 217 218 waitfor(); 219 #ifdef SIGTSTP 220 if (dosusp) 221 signal(SIGTSTP, onsusp); 222 #endif 223 if (inopen) 224 ignore(setty(f)); 225 setrupt(); 226 if (!inopen && c && hush == 0) { 227 ex_printf("!\n"); 228 flush(); 229 termreset(); 230 gettmode(); 231 } 232 } 233 234 /* 235 * Setup a pipeline for the filtration implied by mode 236 * which is like a open number. If input is required to 237 * the filter, then a child editor is created to write it. 238 * If output is catch it from io which is created by unixex. 239 */ 240 filter(mode) 241 register int mode; 242 { 243 static int pvec[2]; 244 ttymode f; /* mjm: was register */ 245 register int lines = lineDOL(); 246 struct stat statb; 247 248 mode++; 249 if (mode & 2) { 250 signal(SIGINT, SIG_IGN); 251 if (pipe(pvec) < 0) 252 error("Can't make pipe"); 253 pid = fork(); 254 io = pvec[0]; 255 if (pid < 0) { 256 setrupt(); 257 close(pvec[1]); 258 error("No more processes"); 259 } 260 if (pid == 0) { 261 setrupt(); 262 io = pvec[1]; 263 close(pvec[0]); 264 putfile(1); 265 ex_exit(0); 266 } 267 close(pvec[1]); 268 io = pvec[0]; 269 setrupt(); 270 } 271 f = unixex("-c", uxb, (mode & 2) ? pvec[0] : 0, mode); 272 if (mode == 3) { 273 ex_delete(0); 274 addr2 = addr1 - 1; 275 } 276 if (mode & 1) { 277 if(FIXUNDO) 278 undap1 = undap2 = addr2+1; 279 if (fstat(io, &statb) < 0) 280 bsize = LBSIZE; 281 else { 282 bsize = statb.st_blksize; 283 if (bsize <= 0) 284 bsize = LBSIZE; 285 } 286 ignore(append(getfile, addr2)); 287 #ifdef TRACE 288 if (trace) 289 vudump("after append in filter"); 290 #endif 291 } 292 close(io); 293 io = -1; 294 unixwt(!inopen, f); 295 netchHAD(lines); 296 } 297 298 /* 299 * Set up to do a recover, getting io to be a pipe from 300 * the recover process. 301 */ 302 recover() 303 { 304 static int pvec[2]; 305 306 if (pipe(pvec) < 0) 307 error(" Can't make pipe for recovery"); 308 pid = fork(); 309 io = pvec[0]; 310 if (pid < 0) { 311 close(pvec[1]); 312 error(" Can't fork to execute recovery"); 313 } 314 if (pid == 0) { 315 close(2); 316 dup(1); 317 close(1); 318 dup(pvec[1]); 319 close(pvec[1]); 320 execl(EXRECOVER, "exrecover", svalue(DIRECTORY), file, (char *) 0); 321 close(1); 322 dup(2); 323 error(" No recovery routine"); 324 } 325 close(pvec[1]); 326 } 327 328 /* 329 * Wait for the process (pid an external) to complete. 330 */ 331 waitfor() 332 { 333 union wait stat, pstat; 334 int wpid; 335 extern char *sys_siglist[]; 336 337 pstat.w_status = 0; 338 do { 339 wpid = wait(&stat); 340 if (wpid == pid) { 341 pstat = stat; 342 rpid = wpid; 343 } 344 } while (wpid != -1); 345 346 if (WIFEXITED(pstat)) 347 status = pstat.w_retcode; 348 else { 349 ex_printf("%d: terminated abnormally: %s ", 350 pid, sys_siglist[pstat.w_termsig]); 351 if (pstat.w_coredump) 352 ex_printf("(core dumped) "); 353 if (!inopen) 354 ex_printf("\r\n"); 355 status = pstat.w_termsig; 356 } 357 } 358 359 /* 360 * The end of a recover operation. If the process 361 * exits non-zero, force not edited; otherwise force 362 * a write. 363 */ 364 revocer() 365 { 366 367 waitfor(); 368 if (pid == rpid && status != 0) 369 edited = 0; 370 else 371 change(); 372 } 373