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