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