1 /* $OpenBSD: io.c,v 1.9 2000/08/20 22:14:32 millert Exp $ */ 2 3 /* 4 * shell buffered IO and formatted output 5 */ 6 7 #include <ctype.h> 8 #include "sh.h" 9 #include "ksh_stat.h" 10 11 static int initio_done; 12 13 /* 14 * formatted output functions 15 */ 16 17 18 /* A shell error occured (eg, syntax error, etc.) */ 19 void 20 #ifdef HAVE_PROTOTYPES 21 errorf(const char *fmt, ...) 22 #else 23 errorf(fmt, va_alist) 24 const char *fmt; 25 va_dcl 26 #endif 27 { 28 va_list va; 29 30 shl_stdout_ok = 0; /* debugging: note that stdout not valid */ 31 exstat = 1; 32 if (*fmt) { 33 error_prefix(TRUE); 34 SH_VA_START(va, fmt); 35 shf_vfprintf(shl_out, fmt, va); 36 va_end(va); 37 shf_putchar('\n', shl_out); 38 } 39 shf_flush(shl_out); 40 unwind(LERROR); 41 } 42 43 /* like errorf(), but no unwind is done */ 44 void 45 #ifdef HAVE_PROTOTYPES 46 warningf(int fileline, const char *fmt, ...) 47 #else 48 warningf(fileline, fmt, va_alist) 49 int fileline; 50 const char *fmt; 51 va_dcl 52 #endif 53 { 54 va_list va; 55 56 error_prefix(fileline); 57 SH_VA_START(va, fmt); 58 shf_vfprintf(shl_out, fmt, va); 59 va_end(va); 60 shf_putchar('\n', shl_out); 61 shf_flush(shl_out); 62 } 63 64 /* Used by built-in utilities to prefix shell and utility name to message 65 * (also unwinds environments for special builtins). 66 */ 67 void 68 #ifdef HAVE_PROTOTYPES 69 bi_errorf(const char *fmt, ...) 70 #else 71 bi_errorf(fmt, va_alist) 72 const char *fmt; 73 va_dcl 74 #endif 75 { 76 va_list va; 77 78 shl_stdout_ok = 0; /* debugging: note that stdout not valid */ 79 exstat = 1; 80 if (*fmt) { 81 error_prefix(TRUE); 82 /* not set when main() calls parse_args() */ 83 if (builtin_argv0) 84 shf_fprintf(shl_out, "%s: ", builtin_argv0); 85 SH_VA_START(va, fmt); 86 shf_vfprintf(shl_out, fmt, va); 87 va_end(va); 88 shf_putchar('\n', shl_out); 89 } 90 shf_flush(shl_out); 91 /* POSIX special builtins and ksh special builtins cause 92 * non-interactive shells to exit. 93 * XXX odd use of KEEPASN; also may not want LERROR here 94 */ 95 if ((builtin_flag & SPEC_BI) 96 || (Flag(FPOSIX) && (builtin_flag & KEEPASN))) 97 { 98 builtin_argv0 = (char *) 0; 99 unwind(LERROR); 100 } 101 } 102 103 /* Called when something that shouldn't happen does */ 104 void 105 #ifdef HAVE_PROTOTYPES 106 internal_errorf(int jump, const char *fmt, ...) 107 #else 108 internal_errorf(jump, fmt, va_alist) 109 int jump; 110 const char *fmt; 111 va_dcl 112 #endif 113 { 114 va_list va; 115 116 error_prefix(TRUE); 117 shf_fprintf(shl_out, "internal error: "); 118 SH_VA_START(va, fmt); 119 shf_vfprintf(shl_out, fmt, va); 120 va_end(va); 121 shf_putchar('\n', shl_out); 122 shf_flush(shl_out); 123 if (jump) 124 unwind(LERROR); 125 } 126 127 /* used by error reporting functions to print "ksh: .kshrc[25]: " */ 128 void 129 error_prefix(fileline) 130 int fileline; 131 { 132 /* Avoid foo: foo[2]: ... */ 133 if (!fileline || !source || !source->file 134 || strcmp(source->file, kshname) != 0) 135 shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-')); 136 if (fileline && source && source->file != NULL) { 137 shf_fprintf(shl_out, "%s[%d]: ", source->file, 138 source->errline > 0 ? source->errline : source->line); 139 source->errline = 0; 140 } 141 } 142 143 /* printf to shl_out (stderr) with flush */ 144 void 145 #ifdef HAVE_PROTOTYPES 146 shellf(const char *fmt, ...) 147 #else 148 shellf(fmt, va_alist) 149 const char *fmt; 150 va_dcl 151 #endif 152 { 153 va_list va; 154 155 if (!initio_done) /* shl_out may not be set up yet... */ 156 return; 157 SH_VA_START(va, fmt); 158 shf_vfprintf(shl_out, fmt, va); 159 va_end(va); 160 shf_flush(shl_out); 161 } 162 163 /* printf to shl_stdout (stdout) */ 164 void 165 #ifdef HAVE_PROTOTYPES 166 shprintf(const char *fmt, ...) 167 #else 168 shprintf(fmt, va_alist) 169 const char *fmt; 170 va_dcl 171 #endif 172 { 173 va_list va; 174 175 if (!shl_stdout_ok) 176 internal_errorf(1, "shl_stdout not valid"); 177 SH_VA_START(va, fmt); 178 shf_vfprintf(shl_stdout, fmt, va); 179 va_end(va); 180 } 181 182 #ifdef KSH_DEBUG 183 static struct shf *kshdebug_shf; 184 185 void 186 kshdebug_init_() 187 { 188 if (kshdebug_shf) 189 shf_close(kshdebug_shf); 190 kshdebug_shf = shf_open("/tmp/ksh-debug.log", 191 O_WRONLY|O_APPEND|O_CREAT, 0600, 192 SHF_WR|SHF_MAPHI); 193 if (kshdebug_shf) { 194 shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid()); 195 shf_flush(kshdebug_shf); 196 } 197 } 198 199 /* print to debugging log */ 200 void 201 # ifdef HAVE_PROTOTYPES 202 kshdebug_printf_(const char *fmt, ...) 203 # else 204 kshdebug_printf_(fmt, va_alist) 205 const char *fmt; 206 va_dcl 207 # endif 208 { 209 va_list va; 210 211 if (!kshdebug_shf) 212 return; 213 SH_VA_START(va, fmt); 214 shf_fprintf(kshdebug_shf, "[%d] ", getpid()); 215 shf_vfprintf(kshdebug_shf, fmt, va); 216 va_end(va); 217 shf_flush(kshdebug_shf); 218 } 219 220 void 221 kshdebug_dump_(str, mem, nbytes) 222 const char *str; 223 const void *mem; 224 int nbytes; 225 { 226 int i, j; 227 int nprow = 16; 228 229 if (!kshdebug_shf) 230 return; 231 shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str); 232 for (i = 0; i < nbytes; i += nprow) { 233 char c = '\t'; 234 for (j = 0; j < nprow && i + j < nbytes; j++) { 235 shf_fprintf(kshdebug_shf, "%c%02x", 236 c, ((const unsigned char *) mem)[i + j]); 237 c = ' '; 238 } 239 shf_fprintf(kshdebug_shf, "\n"); 240 } 241 shf_flush(kshdebug_shf); 242 } 243 #endif /* KSH_DEBUG */ 244 245 /* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */ 246 int 247 can_seek(fd) 248 int fd; 249 { 250 struct stat statb; 251 252 return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ? 253 SHF_UNBUF : 0; 254 } 255 256 struct shf shf_iob[3]; 257 258 void 259 initio() 260 { 261 shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */ 262 shf_fdopen(2, SHF_WR, shl_out); 263 shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */ 264 initio_done = 1; 265 kshdebug_init(); 266 } 267 268 /* A dup2() with error checking */ 269 int 270 ksh_dup2(ofd, nfd, errok) 271 int ofd; 272 int nfd; 273 int errok; 274 { 275 int ret = dup2(ofd, nfd); 276 277 if (ret < 0 && errno != EBADF && !errok) 278 errorf("too many files open in shell"); 279 280 #ifdef DUP2_BROKEN 281 /* Ultrix systems like to preserve the close-on-exec flag */ 282 if (ret >= 0) 283 (void) fcntl(nfd, F_SETFD, 0); 284 #endif /* DUP2_BROKEN */ 285 286 return ret; 287 } 288 289 /* 290 * move fd from user space (0<=fd<10) to shell space (fd>=10), 291 * set close-on-exec flag. 292 */ 293 int 294 savefd(fd, noclose) 295 int fd; 296 int noclose; 297 { 298 int nfd; 299 300 if (fd < FDBASE) { 301 nfd = ksh_dupbase(fd, FDBASE); 302 if (nfd < 0) { 303 if (errno == EBADF) 304 return -1; 305 else 306 errorf("too many files open in shell"); 307 } 308 if (!noclose) 309 close(fd); 310 } else 311 nfd = fd; 312 fd_clexec(nfd); 313 return nfd; 314 } 315 316 void 317 restfd(fd, ofd) 318 int fd, ofd; 319 { 320 if (fd == 2) 321 shf_flush(&shf_iob[fd]); 322 if (ofd < 0) /* original fd closed */ 323 close(fd); 324 else { 325 ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */ 326 close(ofd); 327 } 328 } 329 330 void 331 openpipe(pv) 332 register int *pv; 333 { 334 if (pipe(pv) < 0) 335 errorf("can't create pipe - try again"); 336 pv[0] = savefd(pv[0], 0); 337 pv[1] = savefd(pv[1], 0); 338 } 339 340 void 341 closepipe(pv) 342 register int *pv; 343 { 344 close(pv[0]); 345 close(pv[1]); 346 } 347 348 /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn 349 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor. 350 */ 351 int 352 check_fd(name, mode, emsgp) 353 char *name; 354 int mode; 355 const char **emsgp; 356 { 357 int fd, fl; 358 359 if (isdigit(name[0]) && !name[1]) { 360 fd = name[0] - '0'; 361 if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) { 362 if (emsgp) 363 *emsgp = "bad file descriptor"; 364 return -1; 365 } 366 fl &= O_ACCMODE; 367 #ifdef OS2 368 if (mode == W_OK ) { 369 if (setmode(fd, O_TEXT) == -1) { 370 if (emsgp) 371 *emsgp = "couldn't set write mode"; 372 return -1; 373 } 374 } else if (mode == R_OK) 375 if (setmode(fd, O_BINARY) == -1) { 376 if (emsgp) 377 *emsgp = "couldn't set read mode"; 378 return -1; 379 } 380 #else /* OS2 */ 381 /* X_OK is a kludge to disable this check for dups (x<&1): 382 * historical shells never did this check (XXX don't know what 383 * posix has to say). 384 */ 385 if (!(mode & X_OK) && fl != O_RDWR 386 && (((mode & R_OK) && fl != O_RDONLY) 387 || ((mode & W_OK) && fl != O_WRONLY))) 388 { 389 if (emsgp) 390 *emsgp = (fl == O_WRONLY) ? 391 "fd not open for reading" 392 : "fd not open for writing"; 393 return -1; 394 } 395 #endif /* OS2 */ 396 return fd; 397 } 398 #ifdef KSH 399 else if (name[0] == 'p' && !name[1]) 400 return coproc_getfd(mode, emsgp); 401 #endif /* KSH */ 402 if (emsgp) 403 *emsgp = "illegal file descriptor name"; 404 return -1; 405 } 406 407 #ifdef KSH 408 /* Called once from main */ 409 void 410 coproc_init() 411 { 412 coproc.read = coproc.readw = coproc.write = -1; 413 coproc.njobs = 0; 414 coproc.id = 0; 415 } 416 417 /* Called by c_read() when eof is read - close fd if it is the co-process fd */ 418 void 419 coproc_read_close(fd) 420 int fd; 421 { 422 if (coproc.read >= 0 && fd == coproc.read) { 423 coproc_readw_close(fd); 424 close(coproc.read); 425 coproc.read = -1; 426 } 427 } 428 429 /* Called by c_read() and by iosetup() to close the other side of the 430 * read pipe, so reads will actually terminate. 431 */ 432 void 433 coproc_readw_close(fd) 434 int fd; 435 { 436 if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) { 437 close(coproc.readw); 438 coproc.readw = -1; 439 } 440 } 441 442 /* Called by c_print when a write to a fd fails with EPIPE and by iosetup 443 * when co-process input is dup'd 444 */ 445 void 446 coproc_write_close(fd) 447 int fd; 448 { 449 if (coproc.write >= 0 && fd == coproc.write) { 450 close(coproc.write); 451 coproc.write = -1; 452 } 453 } 454 455 /* Called to check for existance of/value of the co-process file descriptor. 456 * (Used by check_fd() and by c_read/c_print to deal with -p option). 457 */ 458 int 459 coproc_getfd(mode, emsgp) 460 int mode; 461 const char **emsgp; 462 { 463 int fd = (mode & R_OK) ? coproc.read : coproc.write; 464 465 if (fd >= 0) 466 return fd; 467 if (emsgp) 468 *emsgp = "no coprocess"; 469 return -1; 470 } 471 472 /* called to close file descriptors related to the coprocess (if any) 473 * Should be called with SIGCHLD blocked. 474 */ 475 void 476 coproc_cleanup(reuse) 477 int reuse; 478 { 479 /* This to allow co-processes to share output pipe */ 480 if (!reuse || coproc.readw < 0 || coproc.read < 0) { 481 if (coproc.read >= 0) { 482 close(coproc.read); 483 coproc.read = -1; 484 } 485 if (coproc.readw >= 0) { 486 close(coproc.readw); 487 coproc.readw = -1; 488 } 489 } 490 if (coproc.write >= 0) { 491 close(coproc.write); 492 coproc.write = -1; 493 } 494 } 495 #endif /* KSH */ 496 497 498 /* 499 * temporary files 500 */ 501 502 struct temp * 503 maketemp(ap, type, tlist) 504 Area *ap; 505 Temp_type type; 506 struct temp **tlist; 507 { 508 static unsigned int inc; 509 struct temp *tp; 510 int len; 511 int fd; 512 char *path; 513 const char *dir; 514 515 dir = tmpdir ? tmpdir : "/tmp"; 516 /* The 20 + 20 is a paranoid worst case for pid/inc */ 517 len = strlen(dir) + 3 + 20 + 20 + 1; 518 tp = (struct temp *) alloc(sizeof(struct temp) + len, ap); 519 tp->name = path = (char *) &tp[1]; 520 tp->shf = (struct shf *) 0; 521 tp->type = type; 522 #ifdef __OpenBSD__ 523 shf_snprintf(path, len, "%s/shXXXXXXXX", dir); 524 fd = mkstemp(path); 525 if (fd >= 0) 526 tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0); 527 #else 528 while (1) { 529 /* Note that temp files need to fit 8.3 DOS limits */ 530 shf_snprintf(path, len, "%s/sh%05u.%03x", 531 dir, (unsigned) procpid, inc++); 532 /* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't 533 * really there. 534 */ 535 fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600); 536 if (fd >= 0) { 537 tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0); 538 break; 539 } 540 if (errno != EINTR 541 #ifdef EEXIST 542 && errno != EEXIST 543 #endif /* EEXIST */ 544 #ifdef EISDIR 545 && errno != EISDIR 546 #endif /* EISDIR */ 547 ) 548 /* Error must be printed by caller: don't know here if 549 * errorf() or bi_errorf() should be used. 550 */ 551 break; 552 } 553 #endif /* __OpenBSD__ */ 554 tp->pid = procpid; 555 556 tp->next = *tlist; 557 *tlist = tp; 558 559 return tp; 560 } 561