1 /* 2 * io.c --- routines for dealing with input and output and records 3 */ 4 5 /* 6 * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. 7 * 8 * This file is part of GAWK, the GNU implementation of the 9 * AWK Progamming Language. 10 * 11 * GAWK is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * GAWK is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with GAWK; see the file COPYING. If not, write to 23 * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 24 */ 25 26 #include <sys/param.h> 27 #include "awk.h" 28 29 #ifndef O_RDONLY 30 #include <fcntl.h> 31 #endif 32 33 #if !defined(S_ISDIR) && defined(S_IFDIR) 34 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 35 #endif 36 37 #ifndef atarist 38 #define INVALID_HANDLE (-1) 39 #else 40 #define INVALID_HANDLE (__SMALLEST_VALID_HANDLE - 1) 41 #endif 42 43 #if defined(MSDOS) || defined(atarist) 44 #define PIPES_SIMULATED 45 #endif 46 47 static IOBUF *nextfile P((int skipping)); 48 static int inrec P((IOBUF *iop)); 49 static int iop_close P((IOBUF *iop)); 50 struct redirect *redirect P((NODE *tree, int *errflg)); 51 static void close_one P((void)); 52 static int close_redir P((struct redirect *rp)); 53 #ifndef PIPES_SIMULATED 54 static int wait_any P((int interesting)); 55 #endif 56 static IOBUF *gawk_popen P((char *cmd, struct redirect *rp)); 57 static IOBUF *iop_open P((char *file, char *how)); 58 static int gawk_pclose P((struct redirect *rp)); 59 static int do_pathopen P((char *file)); 60 61 extern FILE *fdopen(); 62 extern FILE *popen(); 63 64 static struct redirect *red_head = NULL; 65 66 extern int output_is_tty; 67 extern NODE *ARGC_node; 68 extern NODE *ARGV_node; 69 extern NODE *ARGIND_node; 70 extern NODE *ERRNO_node; 71 extern NODE **fields_arr; 72 73 static jmp_buf filebuf; /* for do_nextfile() */ 74 75 /* do_nextfile --- implement gawk "next file" extension */ 76 77 void 78 do_nextfile() 79 { 80 (void) nextfile(1); 81 longjmp(filebuf, 1); 82 } 83 84 static IOBUF * 85 nextfile(skipping) 86 int skipping; 87 { 88 static int i = 1; 89 static int files = 0; 90 NODE *arg; 91 int fd = INVALID_HANDLE; 92 static IOBUF *curfile = NULL; 93 94 if (skipping) { 95 if (curfile != NULL) 96 iop_close(curfile); 97 curfile = NULL; 98 return NULL; 99 } 100 if (curfile != NULL) { 101 if (curfile->cnt == EOF) { 102 (void) iop_close(curfile); 103 curfile = NULL; 104 } else 105 return curfile; 106 } 107 for (; i < (int) (ARGC_node->lnode->numbr); i++) { 108 arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)); 109 if (arg->stptr[0] == '\0') 110 continue; 111 arg->stptr[arg->stlen] = '\0'; 112 if (! do_unix) { 113 ARGIND_node->var_value->numbr = i; 114 ARGIND_node->var_value->flags = NUM|NUMBER; 115 } 116 if (!arg_assign(arg->stptr)) { 117 files++; 118 curfile = iop_open(arg->stptr, "r"); 119 if (curfile == NULL) 120 fatal("cannot open file `%s' for reading (%s)", 121 arg->stptr, strerror(errno)); 122 /* NOTREACHED */ 123 /* This is a kludge. */ 124 unref(FILENAME_node->var_value); 125 FILENAME_node->var_value = 126 dupnode(arg); 127 FNR = 0; 128 i++; 129 break; 130 } 131 } 132 if (files == 0) { 133 files++; 134 /* no args. -- use stdin */ 135 /* FILENAME is init'ed to "-" */ 136 /* FNR is init'ed to 0 */ 137 curfile = iop_alloc(fileno(stdin)); 138 } 139 return curfile; 140 } 141 142 void 143 set_FNR() 144 { 145 FNR = (int) FNR_node->var_value->numbr; 146 } 147 148 void 149 set_NR() 150 { 151 NR = (int) NR_node->var_value->numbr; 152 } 153 154 /* 155 * This reads in a record from the input file 156 */ 157 static int 158 inrec(iop) 159 IOBUF *iop; 160 { 161 char *begin; 162 register int cnt; 163 int retval = 0; 164 165 cnt = get_a_record(&begin, iop, *RS, NULL); 166 if (cnt == EOF) { 167 cnt = 0; 168 retval = 1; 169 } else { 170 NR += 1; 171 FNR += 1; 172 } 173 set_record(begin, cnt, 1); 174 175 return retval; 176 } 177 178 static int 179 iop_close(iop) 180 IOBUF *iop; 181 { 182 int ret; 183 184 if (iop == NULL) 185 return 0; 186 errno = 0; 187 188 #ifdef _CRAY 189 /* Work around bug in UNICOS popen */ 190 if (iop->fd < 3) 191 ret = 0; 192 else 193 #endif 194 /* save these for re-use; don't free the storage */ 195 if ((iop->flag & IOP_IS_INTERNAL) != 0) { 196 iop->off = iop->buf; 197 iop->end = iop->buf + strlen(iop->buf); 198 iop->cnt = 0; 199 iop->secsiz = 0; 200 return 0; 201 } 202 203 /* Don't close standard files or else crufty code elsewhere will lose */ 204 if (iop->fd == fileno(stdin) || 205 iop->fd == fileno(stdout) || 206 iop->fd == fileno(stderr)) 207 ret = 0; 208 else 209 ret = close(iop->fd); 210 if (ret == -1) 211 warning("close of fd %d failed (%s)", iop->fd, strerror(errno)); 212 if ((iop->flag & IOP_NO_FREE) == 0) { 213 /* 214 * be careful -- $0 may still reference the buffer even though 215 * an explicit close is being done; in the future, maybe we 216 * can do this a bit better 217 */ 218 if (iop->buf) { 219 if ((fields_arr[0]->stptr >= iop->buf) 220 && (fields_arr[0]->stptr < iop->end)) { 221 NODE *t; 222 223 t = make_string(fields_arr[0]->stptr, 224 fields_arr[0]->stlen); 225 unref(fields_arr[0]); 226 fields_arr [0] = t; 227 reset_record (); 228 } 229 free(iop->buf); 230 } 231 free((char *)iop); 232 } 233 return ret == -1 ? 1 : 0; 234 } 235 236 void 237 do_input() 238 { 239 IOBUF *iop; 240 extern int exiting; 241 242 if (setjmp(filebuf) != 0) { 243 } 244 while ((iop = nextfile(0)) != NULL) { 245 if (inrec(iop) == 0) 246 while (interpret(expression_value) && inrec(iop) == 0) 247 ; 248 if (exiting) 249 break; 250 } 251 } 252 253 /* Redirection for printf and print commands */ 254 struct redirect * 255 redirect(tree, errflg) 256 NODE *tree; 257 int *errflg; 258 { 259 register NODE *tmp; 260 register struct redirect *rp; 261 register char *str; 262 int tflag = 0; 263 int outflag = 0; 264 char *direction = "to"; 265 char *mode; 266 int fd; 267 char *what = NULL; 268 269 switch (tree->type) { 270 case Node_redirect_append: 271 tflag = RED_APPEND; 272 /* FALL THROUGH */ 273 case Node_redirect_output: 274 outflag = (RED_FILE|RED_WRITE); 275 tflag |= outflag; 276 if (tree->type == Node_redirect_output) 277 what = ">"; 278 else 279 what = ">>"; 280 break; 281 case Node_redirect_pipe: 282 tflag = (RED_PIPE|RED_WRITE); 283 what = "|"; 284 break; 285 case Node_redirect_pipein: 286 tflag = (RED_PIPE|RED_READ); 287 what = "|"; 288 break; 289 case Node_redirect_input: 290 tflag = (RED_FILE|RED_READ); 291 what = "<"; 292 break; 293 default: 294 fatal ("invalid tree type %d in redirect()", tree->type); 295 break; 296 } 297 tmp = tree_eval(tree->subnode); 298 if (do_lint && ! (tmp->flags & STR)) 299 warning("expression in `%s' redirection only has numeric value", 300 what); 301 tmp = force_string(tmp); 302 str = tmp->stptr; 303 if (str == NULL || *str == '\0') 304 fatal("expression for `%s' redirection has null string value", 305 what); 306 if (do_lint 307 && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen))) 308 warning("filename `%s' for `%s' redirection may be result of logical expression", str, what); 309 for (rp = red_head; rp != NULL; rp = rp->next) 310 if (strlen(rp->value) == tmp->stlen 311 && STREQN(rp->value, str, tmp->stlen) 312 && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == tflag 313 || (outflag 314 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) 315 break; 316 if (rp == NULL) { 317 emalloc(rp, struct redirect *, sizeof(struct redirect), 318 "redirect"); 319 emalloc(str, char *, tmp->stlen+1, "redirect"); 320 memcpy(str, tmp->stptr, tmp->stlen); 321 str[tmp->stlen] = '\0'; 322 rp->value = str; 323 rp->flag = tflag; 324 rp->fp = NULL; 325 rp->iop = NULL; 326 rp->pid = 0; /* unlikely that we're worried about init */ 327 rp->status = 0; 328 /* maintain list in most-recently-used first order */ 329 if (red_head) 330 red_head->prev = rp; 331 rp->prev = NULL; 332 rp->next = red_head; 333 red_head = rp; 334 } 335 while (rp->fp == NULL && rp->iop == NULL) { 336 if (rp->flag & RED_EOF) 337 /* encountered EOF on file or pipe -- must be cleared 338 * by explicit close() before reading more 339 */ 340 return rp; 341 mode = NULL; 342 errno = 0; 343 switch (tree->type) { 344 case Node_redirect_output: 345 mode = "w"; 346 if (rp->flag & RED_USED) 347 mode = "a"; 348 break; 349 case Node_redirect_append: 350 mode = "a"; 351 break; 352 case Node_redirect_pipe: 353 if ((rp->fp = popen(str, "w")) == NULL) 354 fatal("can't open pipe (\"%s\") for output (%s)", 355 str, strerror(errno)); 356 rp->flag |= RED_NOBUF; 357 break; 358 case Node_redirect_pipein: 359 direction = "from"; 360 if (gawk_popen(str, rp) == NULL) 361 fatal("can't open pipe (\"%s\") for input (%s)", 362 str, strerror(errno)); 363 break; 364 case Node_redirect_input: 365 direction = "from"; 366 rp->iop = iop_open(str, "r"); 367 break; 368 default: 369 cant_happen(); 370 } 371 if (mode != NULL) { 372 fd = devopen(str, mode); 373 if (fd > INVALID_HANDLE) { 374 if (fd == fileno(stdin)) 375 rp->fp = stdin; 376 else if (fd == fileno(stdout)) 377 rp->fp = stdout; 378 else if (fd == fileno(stderr)) 379 rp->fp = stderr; 380 else 381 rp->fp = fdopen(fd, mode); 382 if (isatty(fd)) 383 rp->flag |= RED_NOBUF; 384 } 385 } 386 if (rp->fp == NULL && rp->iop == NULL) { 387 /* too many files open -- close one and try again */ 388 if (errno == EMFILE) 389 close_one(); 390 else { 391 /* 392 * Some other reason for failure. 393 * 394 * On redirection of input from a file, 395 * just return an error, so e.g. getline 396 * can return -1. For output to file, 397 * complain. The shell will complain on 398 * a bad command to a pipe. 399 */ 400 *errflg = errno; 401 if (tree->type == Node_redirect_output 402 || tree->type == Node_redirect_append) 403 fatal("can't redirect %s `%s' (%s)", 404 direction, str, strerror(errno)); 405 else { 406 free_temp(tmp); 407 return NULL; 408 } 409 } 410 } 411 } 412 free_temp(tmp); 413 return rp; 414 } 415 416 static void 417 close_one() 418 { 419 register struct redirect *rp; 420 register struct redirect *rplast = NULL; 421 422 /* go to end of list first, to pick up least recently used entry */ 423 for (rp = red_head; rp != NULL; rp = rp->next) 424 rplast = rp; 425 /* now work back up through the list */ 426 for (rp = rplast; rp != NULL; rp = rp->prev) 427 if (rp->fp && (rp->flag & RED_FILE)) { 428 rp->flag |= RED_USED; 429 errno = 0; 430 if (fclose(rp->fp)) 431 warning("close of \"%s\" failed (%s).", 432 rp->value, strerror(errno)); 433 rp->fp = NULL; 434 break; 435 } 436 if (rp == NULL) 437 /* surely this is the only reason ??? */ 438 fatal("too many pipes or input files open"); 439 } 440 441 NODE * 442 do_close(tree) 443 NODE *tree; 444 { 445 NODE *tmp; 446 register struct redirect *rp; 447 448 tmp = force_string(tree_eval(tree->subnode)); 449 for (rp = red_head; rp != NULL; rp = rp->next) { 450 if (strlen(rp->value) == tmp->stlen 451 && STREQN(rp->value, tmp->stptr, tmp->stlen)) 452 break; 453 } 454 free_temp(tmp); 455 if (rp == NULL) /* no match */ 456 return tmp_number((AWKNUM) 0.0); 457 fflush(stdout); /* synchronize regular output */ 458 tmp = tmp_number((AWKNUM)close_redir(rp)); 459 rp = NULL; 460 return tmp; 461 } 462 463 static int 464 close_redir(rp) 465 register struct redirect *rp; 466 { 467 int status = 0; 468 469 if (rp == NULL) 470 return 0; 471 if (rp->fp == stdout || rp->fp == stderr) 472 return 0; 473 errno = 0; 474 if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) 475 status = pclose(rp->fp); 476 else if (rp->fp) 477 status = fclose(rp->fp); 478 else if (rp->iop) { 479 if (rp->flag & RED_PIPE) 480 status = gawk_pclose(rp); 481 else { 482 status = iop_close(rp->iop); 483 rp->iop = NULL; 484 } 485 } 486 /* SVR4 awk checks and warns about status of close */ 487 if (status) { 488 char *s = strerror(errno); 489 490 warning("failure status (%d) on %s close of \"%s\" (%s).", 491 status, 492 (rp->flag & RED_PIPE) ? "pipe" : 493 "file", rp->value, s); 494 495 if (! do_unix) { 496 /* set ERRNO too so that program can get at it */ 497 unref(ERRNO_node->var_value); 498 ERRNO_node->var_value = make_string(s, strlen(s)); 499 } 500 } 501 if (rp->next) 502 rp->next->prev = rp->prev; 503 if (rp->prev) 504 rp->prev->next = rp->next; 505 else 506 red_head = rp->next; 507 free(rp->value); 508 free((char *)rp); 509 return status; 510 } 511 512 int 513 flush_io () 514 { 515 register struct redirect *rp; 516 int status = 0; 517 518 errno = 0; 519 if (fflush(stdout)) { 520 warning("error writing standard output (%s).", strerror(errno)); 521 status++; 522 } 523 if (fflush(stderr)) { 524 warning("error writing standard error (%s).", strerror(errno)); 525 status++; 526 } 527 for (rp = red_head; rp != NULL; rp = rp->next) 528 /* flush both files and pipes, what the heck */ 529 if ((rp->flag & RED_WRITE) && rp->fp != NULL) { 530 if (fflush(rp->fp)) { 531 warning("%s flush of \"%s\" failed (%s).", 532 (rp->flag & RED_PIPE) ? "pipe" : 533 "file", rp->value, strerror(errno)); 534 status++; 535 } 536 } 537 return status; 538 } 539 540 int 541 close_io () 542 { 543 register struct redirect *rp; 544 register struct redirect *next; 545 int status = 0; 546 547 errno = 0; 548 if (fclose(stdout)) { 549 warning("error writing standard output (%s).", strerror(errno)); 550 status++; 551 } 552 if (fclose(stderr)) { 553 warning("error writing standard error (%s).", strerror(errno)); 554 status++; 555 } 556 for (rp = red_head; rp != NULL; rp = next) { 557 next = rp->next; 558 if (close_redir(rp)) 559 status++; 560 rp = NULL; 561 } 562 return status; 563 } 564 565 /* str2mode --- convert a string mode to an integer mode */ 566 567 static int 568 str2mode(mode) 569 char *mode; 570 { 571 int ret; 572 573 switch(mode[0]) { 574 case 'r': 575 ret = O_RDONLY; 576 break; 577 578 case 'w': 579 ret = O_WRONLY|O_CREAT|O_TRUNC; 580 break; 581 582 case 'a': 583 ret = O_WRONLY|O_APPEND|O_CREAT; 584 break; 585 default: 586 cant_happen(); 587 } 588 return ret; 589 } 590 591 /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */ 592 593 /* 594 * This separate version is still needed for output, since file and pipe 595 * output is done with stdio. iop_open() handles input with IOBUFs of 596 * more "special" files. Those files are not handled here since it makes 597 * no sense to use them for output. 598 */ 599 600 int 601 devopen(name, mode) 602 char *name, *mode; 603 { 604 int openfd = INVALID_HANDLE; 605 char *cp, *ptr; 606 int flag = 0; 607 struct stat buf; 608 extern double strtod(); 609 610 flag = str2mode(mode); 611 612 if (do_unix) 613 goto strictopen; 614 615 #ifdef VMS 616 if ((openfd = vms_devopen(name, flag)) >= 0) 617 return openfd; 618 #endif /* VMS */ 619 620 if (STREQ(name, "-")) 621 openfd = fileno(stdin); 622 else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) { 623 cp = name + 5; 624 625 if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY) 626 openfd = fileno(stdin); 627 else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY) 628 openfd = fileno(stdout); 629 else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY) 630 openfd = fileno(stderr); 631 else if (STREQN(cp, "fd/", 3)) { 632 cp += 3; 633 openfd = (int)strtod(cp, &ptr); 634 if (openfd <= INVALID_HANDLE || ptr == cp) 635 openfd = INVALID_HANDLE; 636 } 637 } 638 639 strictopen: 640 if (openfd == INVALID_HANDLE) 641 openfd = open(name, flag, 0666); 642 if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 643 if (S_ISDIR(buf.st_mode)) 644 fatal("file `%s' is a directory", name); 645 return openfd; 646 } 647 648 649 /* spec_setup --- setup an IOBUF for a special internal file */ 650 651 void 652 spec_setup(iop, len, allocate) 653 IOBUF *iop; 654 int len; 655 int allocate; 656 { 657 char *cp; 658 659 if (allocate) { 660 emalloc(cp, char *, len+2, "spec_setup"); 661 iop->buf = cp; 662 } else { 663 len = strlen(iop->buf); 664 iop->buf[len++] = '\n'; /* get_a_record clobbered it */ 665 iop->buf[len] = '\0'; /* just in case */ 666 } 667 iop->off = iop->buf; 668 iop->cnt = 0; 669 iop->secsiz = 0; 670 iop->size = len; 671 iop->end = iop->buf + len; 672 iop->fd = -1; 673 iop->flag = IOP_IS_INTERNAL; 674 } 675 676 /* specfdopen --- open a fd special file */ 677 678 int 679 specfdopen(iop, name, mode) 680 IOBUF *iop; 681 char *name, *mode; 682 { 683 int fd; 684 IOBUF *tp; 685 686 fd = devopen(name, mode); 687 if (fd == INVALID_HANDLE) 688 return INVALID_HANDLE; 689 tp = iop_alloc(fd); 690 if (tp == NULL) 691 return INVALID_HANDLE; 692 *iop = *tp; 693 iop->flag |= IOP_NO_FREE; 694 free(tp); 695 return 0; 696 } 697 698 /* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */ 699 700 int 701 pidopen(iop, name, mode) 702 IOBUF *iop; 703 char *name, *mode; 704 { 705 char tbuf[BUFSIZ]; 706 int i; 707 708 if (name[6] == 'g') 709 /* following #if will improve in 2.16 */ 710 #if defined(__svr4__) || defined(i860) || defined(_AIX) || defined(BSD4_4) 711 sprintf(tbuf, "%d\n", getpgrp()); 712 #else 713 sprintf(tbuf, "%d\n", getpgrp(getpid())); 714 #endif 715 else if (name[6] == 'i') 716 sprintf(tbuf, "%d\n", getpid()); 717 else 718 sprintf(tbuf, "%d\n", getppid()); 719 i = strlen(tbuf); 720 spec_setup(iop, i, 1); 721 strcpy(iop->buf, tbuf); 722 return 0; 723 } 724 725 /* useropen --- "open" /dev/user */ 726 727 /* 728 * /dev/user creates a record as follows: 729 * $1 = getuid() 730 * $2 = geteuid() 731 * $3 = getgid() 732 * $4 = getegid() 733 * If multiple groups are supported, the $5 through $NF are the 734 * supplementary group set. 735 */ 736 737 int 738 useropen(iop, name, mode) 739 IOBUF *iop; 740 char *name, *mode; 741 { 742 char tbuf[BUFSIZ], *cp; 743 int i; 744 #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 745 int groupset[NGROUPS_MAX]; 746 int ngroups; 747 #endif 748 749 sprintf(tbuf, "%d %d %d %d", getuid(), geteuid(), getgid(), getegid()); 750 751 cp = tbuf + strlen(tbuf); 752 #if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 753 ngroups = getgroups(NGROUPS_MAX, groupset); 754 if (ngroups == -1) 755 fatal("could not find groups: %s", strerror(errno)); 756 757 for (i = 0; i < ngroups; i++) { 758 *cp++ = ' '; 759 sprintf(cp, "%d", groupset[i]); 760 cp += strlen(cp); 761 } 762 #endif 763 *cp++ = '\n'; 764 *cp++ = '\0'; 765 766 767 i = strlen(tbuf); 768 spec_setup(iop, i, 1); 769 strcpy(iop->buf, tbuf); 770 return 0; 771 } 772 773 /* iop_open --- handle special and regular files for input */ 774 775 static IOBUF * 776 iop_open(name, mode) 777 char *name, *mode; 778 { 779 int openfd = INVALID_HANDLE; 780 char *cp, *ptr; 781 int flag = 0; 782 int i; 783 struct stat buf; 784 IOBUF *iop; 785 static struct internal { 786 char *name; 787 int compare; 788 int (*fp)(); 789 IOBUF iob; 790 } table[] = { 791 { "/dev/fd/", 8, specfdopen }, 792 { "/dev/stdin", 10, specfdopen }, 793 { "/dev/stdout", 11, specfdopen }, 794 { "/dev/stderr", 11, specfdopen }, 795 { "/dev/pid", 8, pidopen }, 796 { "/dev/ppid", 9, pidopen }, 797 { "/dev/pgrpid", 11, pidopen }, 798 { "/dev/user", 9, useropen }, 799 }; 800 int devcount = sizeof(table) / sizeof(table[0]); 801 802 flag = str2mode(mode); 803 804 if (do_unix) 805 goto strictopen; 806 807 if (STREQ(name, "-")) 808 openfd = fileno(stdin); 809 else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) { 810 int i; 811 812 for (i = 0; i < devcount; i++) { 813 if (STREQN(name, table[i].name, table[i].compare)) { 814 IOBUF *iop = & table[i].iob; 815 816 if (iop->buf != NULL) { 817 spec_setup(iop, 0, 0); 818 return iop; 819 } else if ((*table[i].fp)(iop, name, mode) == 0) 820 return iop; 821 else { 822 warning("could not open %s, mode `%s'", 823 name, mode); 824 return NULL; 825 } 826 } 827 } 828 } 829 830 strictopen: 831 if (openfd == INVALID_HANDLE) 832 openfd = open(name, flag, 0666); 833 if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 834 if ((buf.st_mode & S_IFMT) == S_IFDIR) 835 fatal("file `%s' is a directory", name); 836 iop = iop_alloc(openfd); 837 return iop; 838 } 839 840 #ifndef PIPES_SIMULATED 841 /* real pipes */ 842 static int 843 wait_any(interesting) 844 int interesting; /* pid of interest, if any */ 845 { 846 SIGTYPE (*hstat)(), (*istat)(), (*qstat)(); 847 int pid; 848 int status = 0; 849 struct redirect *redp; 850 extern int errno; 851 852 hstat = signal(SIGHUP, SIG_IGN); 853 istat = signal(SIGINT, SIG_IGN); 854 qstat = signal(SIGQUIT, SIG_IGN); 855 for (;;) { 856 #ifdef NeXT 857 pid = wait((union wait *)&status); 858 #else 859 pid = wait(&status); 860 #endif /* NeXT */ 861 if (interesting && pid == interesting) { 862 break; 863 } else if (pid != -1) { 864 for (redp = red_head; redp != NULL; redp = redp->next) 865 if (pid == redp->pid) { 866 redp->pid = -1; 867 redp->status = status; 868 if (redp->fp) { 869 pclose(redp->fp); 870 redp->fp = 0; 871 } 872 if (redp->iop) { 873 (void) iop_close(redp->iop); 874 redp->iop = 0; 875 } 876 break; 877 } 878 } 879 if (pid == -1 && errno == ECHILD) 880 break; 881 } 882 signal(SIGHUP, hstat); 883 signal(SIGINT, istat); 884 signal(SIGQUIT, qstat); 885 return(status); 886 } 887 888 static IOBUF * 889 gawk_popen(cmd, rp) 890 char *cmd; 891 struct redirect *rp; 892 { 893 int p[2]; 894 register int pid; 895 896 /* used to wait for any children to synchronize input and output, 897 * but this could cause gawk to hang when it is started in a pipeline 898 * and thus has a child process feeding it input (shell dependant) 899 */ 900 /*(void) wait_any(0);*/ /* wait for outstanding processes */ 901 902 if (pipe(p) < 0) 903 fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno)); 904 if ((pid = fork()) == 0) { 905 if (close(1) == -1) 906 fatal("close of stdout in child failed (%s)", 907 strerror(errno)); 908 if (dup(p[1]) != 1) 909 fatal("dup of pipe failed (%s)", strerror(errno)); 910 if (close(p[0]) == -1 || close(p[1]) == -1) 911 fatal("close of pipe failed (%s)", strerror(errno)); 912 if (close(0) == -1) 913 fatal("close of stdin in child failed (%s)", 914 strerror(errno)); 915 execl("/bin/sh", "sh", "-c", cmd, 0); 916 _exit(127); 917 } 918 if (pid == -1) 919 fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno)); 920 rp->pid = pid; 921 if (close(p[1]) == -1) 922 fatal("close of pipe failed (%s)", strerror(errno)); 923 return (rp->iop = iop_alloc(p[0])); 924 } 925 926 static int 927 gawk_pclose(rp) 928 struct redirect *rp; 929 { 930 (void) iop_close(rp->iop); 931 rp->iop = NULL; 932 933 /* process previously found, return stored status */ 934 if (rp->pid == -1) 935 return (rp->status >> 8) & 0xFF; 936 rp->status = wait_any(rp->pid); 937 rp->pid = -1; 938 return (rp->status >> 8) & 0xFF; 939 } 940 941 #else /* PIPES_SIMULATED */ 942 /* use temporary file rather than pipe */ 943 944 #ifdef VMS 945 static IOBUF * 946 gawk_popen(cmd, rp) 947 char *cmd; 948 struct redirect *rp; 949 { 950 FILE *current; 951 952 if ((current = popen(cmd, "r")) == NULL) 953 return NULL; 954 return (rp->iop = iop_alloc(fileno(current))); 955 } 956 957 static int 958 gawk_pclose(rp) 959 struct redirect *rp; 960 { 961 int rval, aval, fd = rp->iop->fd; 962 FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */ 963 964 rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */ 965 rval = iop_close(rp->iop); 966 rp->iop = NULL; 967 aval = pclose(kludge); 968 return (rval < 0 ? rval : aval); 969 } 970 #else /* VMS */ 971 972 static 973 struct { 974 char *command; 975 char *name; 976 } pipes[_NFILE]; 977 978 static IOBUF * 979 gawk_popen(cmd, rp) 980 char *cmd; 981 struct redirect *rp; 982 { 983 extern char *strdup(const char *); 984 int current; 985 char *name; 986 static char cmdbuf[256]; 987 988 /* get a name to use. */ 989 if ((name = tempnam(".", "pip")) == NULL) 990 return NULL; 991 sprintf(cmdbuf,"%s > %s", cmd, name); 992 system(cmdbuf); 993 if ((current = open(name,O_RDONLY)) == INVALID_HANDLE) 994 return NULL; 995 pipes[current].name = name; 996 pipes[current].command = strdup(cmd); 997 rp->iop = iop_alloc(current); 998 return (rp->iop = iop_alloc(current)); 999 } 1000 1001 static int 1002 gawk_pclose(rp) 1003 struct redirect *rp; 1004 { 1005 int cur = rp->iop->fd; 1006 int rval; 1007 1008 rval = iop_close(rp->iop); 1009 rp->iop = NULL; 1010 1011 /* check for an open file */ 1012 if (pipes[cur].name == NULL) 1013 return -1; 1014 unlink(pipes[cur].name); 1015 free(pipes[cur].name); 1016 pipes[cur].name = NULL; 1017 free(pipes[cur].command); 1018 return rval; 1019 } 1020 #endif /* VMS */ 1021 1022 #endif /* PIPES_SIMULATED */ 1023 1024 NODE * 1025 do_getline(tree) 1026 NODE *tree; 1027 { 1028 struct redirect *rp = NULL; 1029 IOBUF *iop; 1030 int cnt = EOF; 1031 char *s = NULL; 1032 int errcode; 1033 1034 while (cnt == EOF) { 1035 if (tree->rnode == NULL) { /* no redirection */ 1036 iop = nextfile(0); 1037 if (iop == NULL) /* end of input */ 1038 return tmp_number((AWKNUM) 0.0); 1039 } else { 1040 int redir_error = 0; 1041 1042 rp = redirect(tree->rnode, &redir_error); 1043 if (rp == NULL && redir_error) { /* failed redirect */ 1044 if (! do_unix) { 1045 char *s = strerror(redir_error); 1046 1047 unref(ERRNO_node->var_value); 1048 ERRNO_node->var_value = 1049 make_string(s, strlen(s)); 1050 } 1051 return tmp_number((AWKNUM) -1.0); 1052 } 1053 iop = rp->iop; 1054 if (iop == NULL) /* end of input */ 1055 return tmp_number((AWKNUM) 0.0); 1056 } 1057 errcode = 0; 1058 cnt = get_a_record(&s, iop, *RS, & errcode); 1059 if (! do_unix && errcode != 0) { 1060 char *s = strerror(errcode); 1061 1062 unref(ERRNO_node->var_value); 1063 ERRNO_node->var_value = make_string(s, strlen(s)); 1064 return tmp_number((AWKNUM) -1.0); 1065 } 1066 if (cnt == EOF) { 1067 if (rp) { 1068 /* 1069 * Don't do iop_close() here if we are 1070 * reading from a pipe; otherwise 1071 * gawk_pclose will not be called. 1072 */ 1073 if (!(rp->flag & RED_PIPE)) { 1074 (void) iop_close(iop); 1075 rp->iop = NULL; 1076 } 1077 rp->flag |= RED_EOF; /* sticky EOF */ 1078 return tmp_number((AWKNUM) 0.0); 1079 } else 1080 continue; /* try another file */ 1081 } 1082 if (!rp) { 1083 NR += 1; 1084 FNR += 1; 1085 } 1086 if (tree->lnode == NULL) /* no optional var. */ 1087 set_record(s, cnt, 1); 1088 else { /* assignment to variable */ 1089 Func_ptr after_assign = NULL; 1090 NODE **lhs; 1091 1092 lhs = get_lhs(tree->lnode, &after_assign); 1093 unref(*lhs); 1094 *lhs = make_string(s, strlen(s)); 1095 (*lhs)->flags |= MAYBE_NUM; 1096 /* we may have to regenerate $0 here! */ 1097 if (after_assign) 1098 (*after_assign)(); 1099 } 1100 } 1101 return tmp_number((AWKNUM) 1.0); 1102 } 1103 1104 int 1105 pathopen (file) 1106 char *file; 1107 { 1108 int fd = do_pathopen(file); 1109 1110 #ifdef DEFAULT_FILETYPE 1111 if (! do_unix && fd <= INVALID_HANDLE) { 1112 char *file_awk; 1113 int save = errno; 1114 #ifdef VMS 1115 int vms_save = vaxc$errno; 1116 #endif 1117 1118 /* append ".awk" and try again */ 1119 emalloc(file_awk, char *, strlen(file) + 1120 sizeof(DEFAULT_FILETYPE) + 1, "pathopen"); 1121 sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE); 1122 fd = do_pathopen(file_awk); 1123 free(file_awk); 1124 if (fd <= INVALID_HANDLE) { 1125 errno = save; 1126 #ifdef VMS 1127 vaxc$errno = vms_save; 1128 #endif 1129 } 1130 } 1131 #endif /*DEFAULT_FILETYPE*/ 1132 1133 return fd; 1134 } 1135 1136 static int 1137 do_pathopen (file) 1138 char *file; 1139 { 1140 static char *savepath = DEFPATH; /* defined in config.h */ 1141 static int first = 1; 1142 char *awkpath, *cp; 1143 char trypath[BUFSIZ]; 1144 int fd; 1145 1146 if (STREQ(file, "-")) 1147 return (0); 1148 1149 if (do_unix) 1150 return (devopen(file, "r")); 1151 1152 if (first) { 1153 first = 0; 1154 if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath) 1155 savepath = awkpath; /* used for restarting */ 1156 } 1157 awkpath = savepath; 1158 1159 /* some kind of path name, no search */ 1160 #ifdef VMS /* (strchr not equal implies either or both not NULL) */ 1161 if (strchr(file, ':') != strchr(file, ']') 1162 || strchr(file, '>') != strchr(file, '/')) 1163 #else /*!VMS*/ 1164 #ifdef MSDOS 1165 if (strchr(file, '/') != strchr(file, '\\') 1166 || strchr(file, ':') != NULL) 1167 #else 1168 if (strchr(file, '/') != NULL) 1169 #endif /*MSDOS*/ 1170 #endif /*VMS*/ 1171 return (devopen(file, "r")); 1172 1173 do { 1174 trypath[0] = '\0'; 1175 /* this should take into account limits on size of trypath */ 1176 for (cp = trypath; *awkpath && *awkpath != ENVSEP; ) 1177 *cp++ = *awkpath++; 1178 1179 if (cp != trypath) { /* nun-null element in path */ 1180 /* add directory punctuation only if needed */ 1181 #ifdef VMS 1182 if (strchr(":]>/", *(cp-1)) == NULL) 1183 #else 1184 #ifdef MSDOS 1185 if (strchr(":\\/", *(cp-1)) == NULL) 1186 #else 1187 if (*(cp-1) != '/') 1188 #endif 1189 #endif 1190 *cp++ = '/'; 1191 /* append filename */ 1192 strcpy (cp, file); 1193 } else 1194 strcpy (trypath, file); 1195 if ((fd = devopen(trypath, "r")) >= 0) 1196 return (fd); 1197 1198 /* no luck, keep going */ 1199 if(*awkpath == ENVSEP && awkpath[1] != '\0') 1200 awkpath++; /* skip colon */ 1201 } while (*awkpath); 1202 /* 1203 * You might have one of the awk 1204 * paths defined, WITHOUT the current working directory in it. 1205 * Therefore try to open the file in the current directory. 1206 */ 1207 return (devopen(file, "r")); 1208 } 1209