1/* 2 * io.c --- routines for dealing with input and output and records 3 */ 4 5/* 6 * Copyright (C) 1986, 1988, 1989, 1991-2003 the Free Software Foundation, Inc. 7 * 8 * This file is part of GAWK, the GNU implementation of the 9 * AWK Programming 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 this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 24 */ 25 26#include "awk.h" 27 28#ifdef HAVE_SYS_PARAM_H 29#undef RE_DUP_MAX /* avoid spurious conflict w/regex.h */ 30#include <sys/param.h> 31#endif /* HAVE_SYS_PARAM_H */ 32 33#ifndef O_RDONLY 34#include <fcntl.h> 35#endif 36#ifndef O_ACCMODE 37#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 38#endif 39 40#ifdef HAVE_TERMIOS_H 41#include <termios.h> 42#endif 43#ifdef HAVE_STROPTS_H 44#include <stropts.h> 45#endif 46 47#ifdef HAVE_SOCKETS 48#ifdef HAVE_SYS_SOCKET_H 49#include <sys/socket.h> 50#else 51#include <socket.h> 52#endif /* HAVE_SYS_SOCKET_H */ 53#ifdef HAVE_NETINET_IN_H 54#include <netinet/in.h> 55#else 56#include <in.h> 57#endif /* HAVE_NETINET_IN_H */ 58#ifdef HAVE_NETDB_H 59#include <netdb.h> 60#endif /* HAVE_NETDB_H */ 61#endif /* HAVE_SOCKETS */ 62 63#ifdef __EMX__ 64#include <process.h> 65#endif 66 67#ifndef ENFILE 68#define ENFILE EMFILE 69#endif 70 71extern int MRL; 72 73#ifdef HAVE_SOCKETS 74enum inet_prot { INET_NONE, INET_TCP, INET_UDP, INET_RAW }; 75 76#ifndef SHUT_RD 77#define SHUT_RD 0 78#endif 79 80#ifndef SHUT_WR 81#define SHUT_WR 1 82#endif 83 84#ifndef SHUT_RDWR 85#define SHUT_RDWR 2 86#endif 87 88#endif /* HAVE_SOCKETS */ 89 90#ifdef atarist 91#include <stddef.h> 92#endif 93 94#if defined(GAWK_AIX) 95#undef TANDEM /* AIX defines this in one of its header files */ 96#undef MSDOS /* For good measure, */ 97#undef WIN32 /* yes, I'm paranoid */ 98#endif 99 100#if defined(MSDOS) || defined(WIN32) || defined(TANDEM) 101#define PIPES_SIMULATED 102#endif 103 104typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type; 105 106/* Several macros make the code a bit clearer: */ 107/* */ 108/* */ 109/* <defines and enums>= */ 110#define at_eof(iop) ((iop->flag & IOP_AT_EOF) != 0) 111#define has_no_data(iop) (iop->dataend == NULL) 112#define no_data_left(iop) (iop->off >= iop->dataend) 113/* The key point to the design is to split out the code that searches through */ 114/* a buffer looking for the record and the terminator into separate routines, */ 115/* with a higher-level routine doing the reading of data and buffer management. */ 116/* This makes the code easier to manage; the buffering code is the same independent */ 117/* of how we find a record. Communication is via the return value: */ 118/* */ 119/* */ 120/* <defines and enums>= */ 121typedef enum recvalues { 122 REC_OK, /* record and terminator found, recmatch struct filled in */ 123 NOTERM, /* no terminator found, give me more input data */ 124 TERMATEND, /* found terminator at end of buffer */ 125 TERMNEAREND, /* found terminator close to end of buffer, for RE might be bigger */ 126} RECVALUE; 127/* Between calls to a scanning routine, the state is stored in */ 128/* an [[enum scanstate]] variable. Not all states apply to all */ 129/* variants, but the higher code doesn't really care. */ 130/* */ 131/* */ 132/* <defines and enums>= */ 133typedef enum scanstate { 134 NOSTATE, /* scanning not started yet (all) */ 135 INLEADER, /* skipping leading data (RS = "") */ 136 INDATA, /* in body of record (all) */ 137 INTERM, /* scanning terminator (RS = "", RS = regexp) */ 138} SCANSTATE; 139/* When a record is seen ([[REC_OK]] or [[TERMATEND]]), the following */ 140/* structure is filled in. */ 141/* */ 142/* */ 143/* <recmatch>= */ 144struct recmatch { 145 char *start; /* record start */ 146 size_t len; /* length of record */ 147 char *rt_start; /* start of terminator */ 148 size_t rt_len; /* length of terminator */ 149}; 150 151static IOBUF *nextfile P((int skipping)); 152static int inrec P((IOBUF *iop)); 153static int iop_close P((IOBUF *iop)); 154struct redirect *redirect P((NODE *tree, int *errflg)); 155static void close_one P((void)); 156static int close_redir P((struct redirect *rp, int exitwarn, two_way_close_type how)); 157#ifndef PIPES_SIMULATED 158static int wait_any P((int interesting)); 159#endif 160static IOBUF *gawk_popen P((const char *cmd, struct redirect *rp)); 161static IOBUF *iop_open P((const char *file, const char *how, IOBUF *buf)); 162static IOBUF *iop_alloc P((int fd, const char *name, IOBUF *buf)); 163static int gawk_pclose P((struct redirect *rp)); 164static int do_pathopen P((const char *file)); 165static int str2mode P((const char *mode)); 166static void spec_setup P((IOBUF *iop, int len, int allocate)); 167static int specfdopen P((IOBUF *iop, const char *name, const char *mode)); 168static int pidopen P((IOBUF *iop, const char *name, const char *mode)); 169static int useropen P((IOBUF *iop, const char *name, const char *mode)); 170static int two_way_open P((const char *str, struct redirect *rp)); 171static int pty_vs_pipe P((const char *command)); 172 173static RECVALUE rs1scan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)); 174static RECVALUE rsnullscan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)); 175static RECVALUE rsrescan P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)); 176 177static RECVALUE (*matchrec) P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)) = rs1scan; 178 179static int get_a_record P((char **out, IOBUF *iop, int *errcode)); 180 181#if defined(HAVE_POPEN_H) 182#include "popen.h" 183#endif 184 185static struct redirect *red_head = NULL; 186static NODE *RS; 187static Regexp *RS_re_yes_case; 188static Regexp *RS_re_no_case; 189static Regexp *RS_regexp; 190 191int RS_is_null; 192 193extern int output_is_tty; 194extern NODE *ARGC_node; 195extern NODE *ARGV_node; 196extern NODE *ARGIND_node; 197extern NODE *ERRNO_node; 198extern NODE **fields_arr; 199 200static jmp_buf filebuf; /* for do_nextfile() */ 201 202#if defined(MSDOS) || defined(OS2) || defined(WIN32) \ 203 || defined(__EMX__) || defined(__CYGWIN__) 204static const char * 205binmode(const char *mode) 206{ 207 switch (mode[0]) { 208 case 'r': 209 if ((BINMODE & 1) != 0) 210 mode = "rb"; 211 break; 212 case 'w': 213 case 'a': 214 if ((BINMODE & 2) != 0) 215 mode = (mode[0] == 'w' ? "wb" : "ab"); 216 break; 217 } 218 return mode; 219} 220#else 221#define binmode(mode) (mode) 222#endif 223 224#ifdef VMS 225/* File pointers have an extra level of indirection, and there are cases where 226 `stdin' can be null. That can crash gawk if fileno() is used as-is. */ 227static int vmsrtl_fileno P((FILE *)); 228static int vmsrtl_fileno(fp) FILE *fp; { return fileno(fp); } 229#undef fileno 230#define fileno(FP) (((FP) && *(FP)) ? vmsrtl_fileno(FP) : -1) 231#endif /* VMS */ 232 233/* do_nextfile --- implement gawk "nextfile" extension */ 234 235void 236do_nextfile() 237{ 238 (void) nextfile(TRUE); 239 longjmp(filebuf, 1); 240} 241 242/* nextfile --- move to the next input data file */ 243 244static IOBUF * 245nextfile(int skipping) 246{ 247 static long i = 1; 248 static int files = 0; 249 NODE *arg; 250 static IOBUF *curfile = NULL; 251 static IOBUF mybuf; 252 const char *fname; 253 254 if (skipping) { 255 if (curfile != NULL) 256 iop_close(curfile); 257 curfile = NULL; 258 return NULL; 259 } 260 if (curfile != NULL) { 261 if (at_eof(curfile)) { 262 (void) iop_close(curfile); 263 curfile = NULL; 264 } else 265 return curfile; 266 } 267 for (; i < (long) (ARGC_node->lnode->numbr); i++) { 268 arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i), FALSE); 269 if (arg->stlen == 0) 270 continue; 271 arg->stptr[arg->stlen] = '\0'; 272 if (! do_traditional) { 273 unref(ARGIND_node->var_value); 274 ARGIND_node->var_value = make_number((AWKNUM) i); 275 } 276 if (! arg_assign(arg->stptr, FALSE)) { 277 files++; 278 fname = arg->stptr; 279 curfile = iop_open(fname, binmode("r"), &mybuf); 280 if (curfile == NULL) 281 goto give_up; 282 curfile->flag |= IOP_NOFREE_OBJ; 283 /* This is a kludge. */ 284 unref(FILENAME_node->var_value); 285 FILENAME_node->var_value = dupnode(arg); 286 FNR = 0; 287 i++; 288 break; 289 } 290 } 291 if (files == 0) { 292 files++; 293 /* no args. -- use stdin */ 294 /* FNR is init'ed to 0 */ 295 FILENAME_node->var_value = make_string("-", 1); 296 fname = "-"; 297 curfile = iop_open(fname, binmode("r"), &mybuf); 298 if (curfile == NULL) 299 goto give_up; 300 curfile->flag |= IOP_NOFREE_OBJ; 301 } 302 return curfile; 303 304 give_up: 305 fatal(_("cannot open file `%s' for reading (%s)"), 306 fname, strerror(errno)); 307 /* NOTREACHED */ 308 return 0; 309} 310 311/* set_FNR --- update internal FNR from awk variable */ 312 313void 314set_FNR() 315{ 316 FNR = (long) FNR_node->var_value->numbr; 317} 318 319/* set_NR --- update internal NR from awk variable */ 320 321void 322set_NR() 323{ 324 NR = (long) NR_node->var_value->numbr; 325} 326 327/* inrec --- This reads in a record from the input file */ 328 329static int 330inrec(IOBUF *iop) 331{ 332 char *begin; 333 register int cnt; 334 int retval = 0; 335 336 if (at_eof(iop) && no_data_left(iop)) 337 cnt = EOF; 338 else if ((iop->flag & IOP_CLOSED) != 0) 339 cnt = EOF; 340 else 341 cnt = get_a_record(&begin, iop, NULL); 342 343 if (cnt == EOF) { 344 cnt = 0; 345 retval = 1; 346 } else { 347 NR += 1; 348 FNR += 1; 349 set_record(begin, cnt); 350 } 351 352 return retval; 353} 354 355/* iop_close --- close an open IOP */ 356 357static int 358iop_close(IOBUF *iop) 359{ 360 int ret; 361 362 if (iop == NULL) 363 return 0; 364 errno = 0; 365 366 iop->flag &= ~IOP_AT_EOF; 367 iop->flag |= IOP_CLOSED; /* there may be dangling pointers */ 368 iop->dataend = NULL; 369#ifdef _CRAY 370 /* Work around bug in UNICOS popen */ 371 if (iop->fd < 3) 372 ret = 0; 373 else 374#endif 375 /* save these for re-use; don't free the storage */ 376 if ((iop->flag & IOP_IS_INTERNAL) != 0) { 377 iop->off = iop->buf; 378 iop->end = iop->buf + strlen(iop->buf); 379 iop->count = 0; 380 return 0; 381 } 382 383 /* Don't close standard files or else crufty code elsewhere will lose */ 384 if (iop->fd == fileno(stdin) 385 || iop->fd == fileno(stdout) 386 || iop->fd == fileno(stderr)) 387 ret = 0; 388 else 389 ret = close(iop->fd); 390 391 if (ret == -1) 392 warning(_("close of fd %d (`%s') failed (%s)"), iop->fd, 393 iop->name, strerror(errno)); 394 if ((iop->flag & IOP_NO_FREE) == 0) { 395 /* 396 * Be careful -- $0 may still reference the buffer even though 397 * an explicit close is being done; in the future, maybe we 398 * can do this a bit better. 399 */ 400 if (iop->buf) { 401 if ((fields_arr[0]->stptr >= iop->buf) 402 && (fields_arr[0]->stptr < (iop->buf + iop->size))) { 403 NODE *t; 404 405 t = make_string(fields_arr[0]->stptr, 406 fields_arr[0]->stlen); 407 unref(fields_arr[0]); 408 fields_arr[0] = t; 409 /* 410 * 1/27/2003: This used to be here: 411 * 412 * reset_record(); 413 * 414 * Don't do that; reset_record() throws away all fields, 415 * saves FS etc. We just need to make sure memory isn't 416 * corrupted and that references to $0 and fields work. 417 */ 418 } 419 free(iop->buf); 420 iop->buf = NULL; 421 } 422 if ((iop->flag & IOP_NOFREE_OBJ) == 0) 423 free((char *) iop); 424 } 425 return ret == -1 ? 1 : 0; 426} 427 428/* do_input --- the main input processing loop */ 429 430void 431do_input() 432{ 433 IOBUF *iop; 434 extern int exiting; 435 int rval1, rval2, rval3; 436 437 (void) setjmp(filebuf); /* for `nextfile' */ 438 439 while ((iop = nextfile(FALSE)) != NULL) { 440 /* 441 * This was: 442 if (inrec(iop) == 0) 443 while (interpret(expression_value) && inrec(iop) == 0) 444 continue; 445 * Now expand it out for ease of debugging. 446 */ 447 rval1 = inrec(iop); 448 if (rval1 == 0) { 449 for (;;) { 450 rval2 = rval3 = -1; /* for debugging */ 451 rval2 = interpret(expression_value); 452 if (rval2 != 0) 453 rval3 = inrec(iop); 454 if (rval2 == 0 || rval3 != 0) 455 break; 456 } 457 } 458 if (exiting) 459 break; 460 } 461} 462 463/* redflags2str --- turn redirection flags into a string, for debugging */ 464 465const char * 466redflags2str(int flags) 467{ 468 static const struct flagtab redtab[] = { 469 { RED_FILE, "RED_FILE" }, 470 { RED_PIPE, "RED_PIPE" }, 471 { RED_READ, "RED_READ" }, 472 { RED_WRITE, "RED_WRITE" }, 473 { RED_APPEND, "RED_APPEND" }, 474 { RED_NOBUF, "RED_NOBUF" }, 475 { RED_EOF, "RED_EOF" }, 476 { RED_TWOWAY, "RED_TWOWAY" }, 477 { RED_PTY, "RED_PTY" }, 478 { RED_SOCKET, "RED_SOCKET" }, 479 { RED_TCP, "RED_TCP" }, 480 { 0, NULL } 481 }; 482 483 return genflags2str(flags, redtab); 484} 485 486/* redirect --- Redirection for printf and print commands */ 487 488struct redirect * 489redirect(NODE *tree, int *errflg) 490{ 491 register NODE *tmp; 492 register struct redirect *rp; 493 register char *str; 494 int tflag = 0; 495 int outflag = 0; 496 const char *direction = "to"; 497 const char *mode; 498 int fd; 499 const char *what = NULL; 500 501 switch (tree->type) { 502 case Node_redirect_append: 503 tflag = RED_APPEND; 504 /* FALL THROUGH */ 505 case Node_redirect_output: 506 outflag = (RED_FILE|RED_WRITE); 507 tflag |= outflag; 508 if (tree->type == Node_redirect_output) 509 what = ">"; 510 else 511 what = ">>"; 512 break; 513 case Node_redirect_pipe: 514 tflag = (RED_PIPE|RED_WRITE); 515 what = "|"; 516 break; 517 case Node_redirect_pipein: 518 tflag = (RED_PIPE|RED_READ); 519 what = "|"; 520 break; 521 case Node_redirect_input: 522 tflag = (RED_FILE|RED_READ); 523 what = "<"; 524 break; 525 case Node_redirect_twoway: 526 tflag = (RED_READ|RED_WRITE|RED_TWOWAY); 527 what = "|&"; 528 break; 529 default: 530 fatal(_("invalid tree type %s in redirect()"), 531 nodetype2str(tree->type)); 532 break; 533 } 534 tmp = tree_eval(tree->subnode); 535 if (do_lint && (tmp->flags & STRCUR) == 0) 536 lintwarn(_("expression in `%s' redirection only has numeric value"), 537 what); 538 tmp = force_string(tmp); 539 str = tmp->stptr; 540 541 if (str == NULL || *str == '\0') 542 fatal(_("expression for `%s' redirection has null string value"), 543 what); 544 545 if (do_lint 546 && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen))) 547 lintwarn(_("filename `%s' for `%s' redirection may be result of logical expression"), str, what); 548 549#ifdef HAVE_SOCKETS 550 if (STREQN(str, "/inet/", 6)) { 551 tflag |= RED_SOCKET; 552 if (STREQN(str + 6, "tcp/", 4)) 553 tflag |= RED_TCP; /* use shutdown when closing */ 554 } 555#endif /* HAVE_SOCKETS */ 556 557 for (rp = red_head; rp != NULL; rp = rp->next) { 558 if (strlen(rp->value) == tmp->stlen 559 && STREQN(rp->value, str, tmp->stlen) 560 && ((rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)) == tflag 561 || (outflag != 0 562 && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) { 563 564 int rpflag = (rp->flag & ~(RED_NOBUF|RED_EOF|RED_PTY)); 565 int newflag = (tflag & ~(RED_NOBUF|RED_EOF|RED_PTY)); 566 567 if (do_lint && rpflag != newflag) 568 lintwarn( 569 _("unnecessary mixing of `>' and `>>' for file `%.*s'"), 570 tmp->stlen, rp->value); 571 572 break; 573 } 574 } 575 576 if (rp == NULL) { 577 emalloc(rp, struct redirect *, sizeof(struct redirect), 578 "redirect"); 579 emalloc(str, char *, tmp->stlen+1, "redirect"); 580 memcpy(str, tmp->stptr, tmp->stlen); 581 str[tmp->stlen] = '\0'; 582 rp->value = str; 583 rp->flag = tflag; 584 rp->fp = NULL; 585 rp->iop = NULL; 586 rp->pid = 0; /* unlikely that we're worried about init */ 587 rp->status = 0; 588 /* maintain list in most-recently-used first order */ 589 if (red_head != NULL) 590 red_head->prev = rp; 591 rp->prev = NULL; 592 rp->next = red_head; 593 red_head = rp; 594 } else 595 str = rp->value; /* get \0 terminated string */ 596 597 while (rp->fp == NULL && rp->iop == NULL) { 598 if (rp->flag & RED_EOF) 599 /* 600 * encountered EOF on file or pipe -- must be cleared 601 * by explicit close() before reading more 602 */ 603 return rp; 604 mode = NULL; 605 errno = 0; 606 switch (tree->type) { 607 case Node_redirect_output: 608 mode = binmode("w"); 609 if ((rp->flag & RED_USED) != 0) 610 mode = (rp->mode[1] == 'b') ? "ab" : "a"; 611 break; 612 case Node_redirect_append: 613 mode = binmode("a"); 614 break; 615 case Node_redirect_pipe: 616 /* synchronize output before new pipe */ 617 (void) flush_io(); 618 619 os_restore_mode(fileno(stdin)); 620 if ((rp->fp = popen(str, binmode("w"))) == NULL) 621 fatal(_("can't open pipe `%s' for output (%s)"), 622 str, strerror(errno)); 623 /* set close-on-exec */ 624 os_close_on_exec(fileno(rp->fp), str, "pipe", "to"); 625 rp->flag |= RED_NOBUF; 626 break; 627 case Node_redirect_pipein: 628 direction = "from"; 629 if (gawk_popen(str, rp) == NULL) 630 fatal(_("can't open pipe `%s' for input (%s)"), 631 str, strerror(errno)); 632 break; 633 case Node_redirect_input: 634 direction = "from"; 635 rp->iop = iop_open(str, binmode("r"), NULL); 636 break; 637 case Node_redirect_twoway: 638 direction = "to/from"; 639 if (! two_way_open(str, rp)) { 640#ifdef HAVE_SOCKETS 641 /* multiple messages make life easier for translators */ 642 if (STREQN(str, "/inet/", 6)) 643 fatal(_("can't open two way socket `%s' for input/output (%s)"), 644 str, strerror(errno)); 645 else 646#endif 647 fatal(_("can't open two way pipe `%s' for input/output (%s)"), 648 str, strerror(errno)); 649 } 650 break; 651 default: 652 cant_happen(); 653 } 654 if (mode != NULL) { 655 errno = 0; 656 fd = devopen(str, mode); 657 if (fd > INVALID_HANDLE) { 658 if (fd == fileno(stdin)) 659 rp->fp = stdin; 660 else if (fd == fileno(stdout)) 661 rp->fp = stdout; 662 else if (fd == fileno(stderr)) 663 rp->fp = stderr; 664 else { 665#if defined(F_GETFL) && defined(O_APPEND) 666 int fd_flags; 667 668 fd_flags = fcntl(fd, F_GETFL); 669 if (fd_flags != -1 && (fd_flags & O_APPEND) == O_APPEND) 670 rp->fp = fdopen(fd, binmode("a")); 671 else 672#endif 673 rp->fp = fdopen(fd, (const char *) mode); 674 rp->mode = (const char *) mode; 675 /* don't leak file descriptors */ 676 if (rp->fp == NULL) 677 close(fd); 678 } 679 if (rp->fp != NULL && isatty(fd)) 680 rp->flag |= RED_NOBUF; 681 /* Move rp to the head of the list. */ 682 if (red_head != rp) { 683 if ((rp->prev->next = rp->next) != NULL) 684 rp->next->prev = rp->prev; 685 red_head->prev = rp; 686 rp->prev = NULL; 687 rp->next = red_head; 688 red_head = rp; 689 } 690 } 691 } 692 if (rp->fp == NULL && rp->iop == NULL) { 693 /* too many files open -- close one and try again */ 694 if (errno == EMFILE || errno == ENFILE) 695 close_one(); 696#if defined __MINGW32__ || defined __sun 697 else if (errno == 0) /* HACK! */ 698 close_one(); 699#endif 700#ifdef VMS 701 /* Alpha/VMS V7.1's C RTL is returning this instead 702 of EMFILE (haven't tried other post-V6.2 systems) */ 703#define SS$_EXQUOTA 0x001C 704 else if (errno == EIO && vaxc$errno == SS$_EXQUOTA) 705 close_one(); 706#endif 707 else { 708 /* 709 * Some other reason for failure. 710 * 711 * On redirection of input from a file, 712 * just return an error, so e.g. getline 713 * can return -1. For output to file, 714 * complain. The shell will complain on 715 * a bad command to a pipe. 716 */ 717 if (errflg != NULL) 718 *errflg = errno; 719 if (tree->type == Node_redirect_output 720 || tree->type == Node_redirect_append) { 721 /* multiple messages make life easier for translators */ 722 if (*direction == 'f') 723 fatal(_("can't redirect from `%s' (%s)"), 724 str, strerror(errno)); 725 else 726 fatal(_("can't redirect to `%s' (%s)"), 727 str, strerror(errno)); 728 } else { 729 free_temp(tmp); 730 return NULL; 731 } 732 } 733 } 734 } 735 free_temp(tmp); 736 return rp; 737} 738 739/* getredirect --- find the struct redirect for this file or pipe */ 740 741struct redirect * 742getredirect(const char *str, int len) 743{ 744 struct redirect *rp; 745 746 for (rp = red_head; rp != NULL; rp = rp->next) 747 if (strlen(rp->value) == len && STREQN(rp->value, str, len)) 748 return rp; 749 750 return NULL; 751} 752 753/* close_one --- temporarily close an open file to re-use the fd */ 754 755static void 756close_one() 757{ 758 register struct redirect *rp; 759 register struct redirect *rplast = NULL; 760 761 static short warned = FALSE; 762 763 if (do_lint && ! warned) { 764 warned = TRUE; 765 lintwarn(_("reached system limit for open files: starting to multiplex file descriptors")); 766 } 767 768 /* go to end of list first, to pick up least recently used entry */ 769 for (rp = red_head; rp != NULL; rp = rp->next) 770 rplast = rp; 771 /* now work back up through the list */ 772 for (rp = rplast; rp != NULL; rp = rp->prev) 773 if (rp->fp != NULL && (rp->flag & RED_FILE) != 0) { 774 rp->flag |= RED_USED; 775 errno = 0; 776 if (/* do_lint && */ fclose(rp->fp) != 0) 777 warning(_("close of `%s' failed (%s)."), 778 rp->value, strerror(errno)); 779 rp->fp = NULL; 780 break; 781 } 782 if (rp == NULL) 783 /* surely this is the only reason ??? */ 784 fatal(_("too many pipes or input files open")); 785} 786 787/* do_close --- completely close an open file or pipe */ 788 789NODE * 790do_close(NODE *tree) 791{ 792 NODE *tmp, *tmp2; 793 register struct redirect *rp; 794 two_way_close_type how = CLOSE_ALL; /* default */ 795 796 tmp = force_string(tree_eval(tree->lnode)); /* 1st arg: redir to close */ 797 798 if (tree->rnode != NULL) { 799 /* 2nd arg if present: "to" or "from" for two-way pipe */ 800 /* DO NOT use _() on the strings here! */ 801 tmp2 = force_string(tree->rnode->lnode); 802 if (strcasecmp(tmp2->stptr, "to") == 0) 803 how = CLOSE_TO; 804 else if (strcasecmp(tmp2->stptr, "from") == 0) 805 how = CLOSE_FROM; 806 else 807 fatal(_("close: second argument must be `to' or `from'")); 808 free_temp(tmp2); 809 } 810 811 for (rp = red_head; rp != NULL; rp = rp->next) { 812 if (strlen(rp->value) == tmp->stlen 813 && STREQN(rp->value, tmp->stptr, tmp->stlen)) 814 break; 815 } 816 817 if (rp == NULL) { /* no match, return -1 */ 818 char *cp; 819 820 if (do_lint) 821 lintwarn(_("close: `%.*s' is not an open file, pipe or co-process"), 822 tmp->stlen, tmp->stptr); 823 824 /* update ERRNO manually, using errno = ENOENT is a stretch. */ 825 cp = _("close of redirection that was never opened"); 826 unref(ERRNO_node->var_value); 827 ERRNO_node->var_value = make_string(cp, strlen(cp)); 828 829 free_temp(tmp); 830 return tmp_number((AWKNUM) -1.0); 831 } 832 free_temp(tmp); 833 fflush(stdout); /* synchronize regular output */ 834 tmp = tmp_number((AWKNUM) close_redir(rp, FALSE, how)); 835 rp = NULL; 836 /* 837 * POSIX says close() returns 0 on success, non-zero otherwise. 838 * For POSIX, at this point we just return 0. Otherwise we 839 * return the exit status of the process or of pclose(), depending. 840 * This whole business is a mess. 841 */ 842 if (do_posix) { 843 free_temp(tmp); 844 return tmp_number((AWKNUM) 0); 845 } 846 return tmp; 847} 848 849/* close_redir --- close an open file or pipe */ 850 851static int 852close_redir(register struct redirect *rp, int exitwarn, two_way_close_type how) 853{ 854 int status = 0; 855 856 if (rp == NULL) 857 return 0; 858 if (rp->fp == stdout || rp->fp == stderr) 859 return 0; 860 861 if (do_lint && (rp->flag & RED_TWOWAY) == 0 && how != CLOSE_ALL) 862 lintwarn(_("close: redirection `%s' not opened with `|&', second argument ignored"), 863 rp->value); 864 865 errno = 0; 866 if ((rp->flag & RED_TWOWAY) != 0) { /* two-way pipe */ 867 /* write end: */ 868 if ((how == CLOSE_ALL || how == CLOSE_TO) && rp->fp != NULL) { 869#ifdef HAVE_SOCKETS 870 if ((rp->flag & RED_TCP) != 0) 871 (void) shutdown(fileno(rp->fp), SHUT_WR); 872#endif /* HAVE_SOCKETS */ 873 874 if ((rp->flag & RED_PTY) != 0) { 875 fwrite("\004\n", sizeof("\004\n") - 1, 1, rp->fp); 876 fflush(rp->fp); 877 } 878 status = fclose(rp->fp); 879 rp->fp = NULL; 880 } 881 882 /* read end: */ 883 if (how == CLOSE_ALL || how == CLOSE_FROM) { 884 if ((rp->flag & RED_SOCKET) != 0 && rp->iop != NULL) { 885#ifdef HAVE_SOCKETS 886 if ((rp->flag & RED_TCP) != 0) 887 (void) shutdown(rp->iop->fd, SHUT_RD); 888#endif /* HAVE_SOCKETS */ 889 (void) iop_close(rp->iop); 890 } else 891 status = gawk_pclose(rp); 892 893 rp->iop = NULL; 894 } 895 } else if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) { /* write to pipe */ 896 status = pclose(rp->fp); 897#ifdef O_BINARY 898 if ((BINMODE & 1) != 0) 899 os_setbinmode(fileno(stdin), O_BINARY); 900#endif 901 rp->fp = NULL; 902 } else if (rp->fp != NULL) { /* write to file */ 903 status = fclose(rp->fp); 904 rp->fp = NULL; 905 } else if (rp->iop != NULL) { /* read from pipe/file */ 906 if ((rp->flag & RED_PIPE) != 0) /* read from pipe */ 907 status = gawk_pclose(rp); 908 /* gawk_pclose sets rp->iop to null */ 909 else { /* read from file */ 910 status = iop_close(rp->iop); 911 rp->iop = NULL; 912 } 913 } 914 915 /* SVR4 awk checks and warns about status of close */ 916 if (status != 0) { 917 char *s = strerror(errno); 918 919 /* 920 * Too many people have complained about this. 921 * As of 2.15.6, it is now under lint control. 922 */ 923 if (do_lint) { 924 if ((rp->flag & RED_PIPE) != 0) 925 lintwarn(_("failure status (%d) on pipe close of `%s' (%s)"), 926 status, rp->value, s); 927 else 928 lintwarn(_("failure status (%d) on file close of `%s' (%s)"), 929 status, rp->value, s); 930 } 931 932 if (! do_traditional) { 933 /* set ERRNO too so that program can get at it */ 934 update_ERRNO(); 935 } 936 } 937 938 if (exitwarn) { 939 /* 940 * Don't use lintwarn() here. If lint warnings are fatal, 941 * doing so prevents us from closing other open redirections. 942 * 943 * Using multiple full messages instead of string parameters 944 * for the types makes message translation easier. 945 */ 946 if ((rp->flag & RED_SOCKET) != 0) 947 warning(_("no explicit close of socket `%s' provided"), 948 rp->value); 949 else if ((rp->flag & RED_TWOWAY) != 0) 950 warning(_("no explicit close of co-process `%s' provided"), 951 rp->value); 952 else if ((rp->flag & RED_PIPE) != 0) 953 warning(_("no explicit close of pipe `%s' provided"), 954 rp->value); 955 else 956 warning(_("no explicit close of file `%s' provided"), 957 rp->value); 958 } 959 960 /* remove it from the list if closing both or both ends have been closed */ 961 if (how == CLOSE_ALL || (rp->iop == NULL && rp->fp == NULL)) { 962 if (rp->next != NULL) 963 rp->next->prev = rp->prev; 964 if (rp->prev != NULL) 965 rp->prev->next = rp->next; 966 else 967 red_head = rp->next; 968 free(rp->value); 969 free((char *) rp); 970 } 971 972 return status; 973} 974 975/* flush_io --- flush all open output files */ 976 977int 978flush_io() 979{ 980 register struct redirect *rp; 981 int status = 0; 982 983 errno = 0; 984 if (fflush(stdout)) { 985 warning(_("error writing standard output (%s)"), strerror(errno)); 986 status++; 987 } 988 if (fflush(stderr)) { 989 warning(_("error writing standard error (%s)"), strerror(errno)); 990 status++; 991 } 992 for (rp = red_head; rp != NULL; rp = rp->next) 993 /* flush both files and pipes, what the heck */ 994 if ((rp->flag & RED_WRITE) && rp->fp != NULL) { 995 if (fflush(rp->fp)) { 996 if (rp->flag & RED_PIPE) 997 warning(_("pipe flush of `%s' failed (%s)."), 998 rp->value, strerror(errno)); 999 else if (rp->flag & RED_TWOWAY) 1000 warning(_("co-process flush of pipe to `%s' failed (%s)."), 1001 rp->value, strerror(errno)); 1002 else 1003 warning(_("file flush of `%s' failed (%s)."), 1004 rp->value, strerror(errno)); 1005 status++; 1006 } 1007 } 1008 if (status != 0) 1009 status = -1; /* canonicalize it */ 1010 return status; 1011} 1012 1013/* close_io --- close all open files, called when exiting */ 1014 1015int 1016close_io() 1017{ 1018 register struct redirect *rp; 1019 register struct redirect *next; 1020 int status = 0; 1021 1022 errno = 0; 1023 for (rp = red_head; rp != NULL; rp = next) { 1024 next = rp->next; 1025 /* 1026 * close_redir() will print a message if needed 1027 * if do_lint, warn about lack of explicit close 1028 */ 1029 if (close_redir(rp, do_lint, CLOSE_ALL)) 1030 status++; 1031 rp = NULL; 1032 } 1033 /* 1034 * Some of the non-Unix os's have problems doing an fclose 1035 * on stdout and stderr. Since we don't really need to close 1036 * them, we just flush them, and do that across the board. 1037 */ 1038 if (fflush(stdout)) { 1039 warning(_("error writing standard output (%s)"), strerror(errno)); 1040 status++; 1041 } 1042 if (fflush(stderr)) { 1043 warning(_("error writing standard error (%s)"), strerror(errno)); 1044 status++; 1045 } 1046 return status; 1047} 1048 1049/* str2mode --- convert a string mode to an integer mode */ 1050 1051static int 1052str2mode(const char *mode) 1053{ 1054 int ret; 1055 const char *second = & mode[1]; 1056 1057 if (*second == 'b') 1058 second++; 1059 1060 switch(mode[0]) { 1061 case 'r': 1062 ret = O_RDONLY; 1063 if (*second == '+' || *second == 'w') 1064 ret = O_RDWR; 1065 break; 1066 1067 case 'w': 1068 ret = O_WRONLY|O_CREAT|O_TRUNC; 1069 if (*second == '+' || *second == 'r') 1070 ret = O_RDWR|O_CREAT|O_TRUNC; 1071 break; 1072 1073 case 'a': 1074 ret = O_WRONLY|O_APPEND|O_CREAT; 1075 if (*second == '+') 1076 ret = O_RDWR|O_APPEND|O_CREAT; 1077 break; 1078 1079 default: 1080 ret = 0; /* lint */ 1081 cant_happen(); 1082 } 1083#ifdef O_BINARY 1084 if (strchr(mode, 'b') != NULL) 1085 ret |= O_BINARY; 1086#endif 1087 return ret; 1088} 1089 1090#ifdef HAVE_SOCKETS 1091/* socketopen --- open a socket and set it into connected state */ 1092 1093static int 1094socketopen(enum inet_prot type, int localport, int remoteport, const char *remotehostname) 1095{ 1096 struct hostent *hp = gethostbyname(remotehostname); 1097 struct sockaddr_in local_addr, remote_addr; 1098 int socket_fd; 1099 int any_remote_host = strcmp(remotehostname, "0"); 1100 1101 socket_fd = INVALID_HANDLE; 1102 switch (type) { 1103 case INET_TCP: 1104 if (localport != 0 || remoteport != 0) { 1105 int on = 1; 1106#ifdef SO_LINGER 1107 struct linger linger; 1108 1109 memset(& linger, '\0', sizeof(linger)); 1110#endif 1111 socket_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 1112 setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, 1113 (char *) & on, sizeof(on)); 1114#ifdef SO_LINGER 1115 linger.l_onoff = 1; 1116 linger.l_linger = 30; /* linger for 30/100 second */ 1117 setsockopt(socket_fd, SOL_SOCKET, SO_LINGER, 1118 (char *) & linger, sizeof(linger)); 1119#endif 1120 } 1121 break; 1122 case INET_UDP: 1123 if (localport != 0 || remoteport != 0) 1124 socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 1125 break; 1126 case INET_RAW: 1127#ifdef SOCK_RAW 1128 if (localport == 0 && remoteport == 0) 1129 socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 1130#endif 1131 break; 1132 case INET_NONE: 1133 /* fall through */ 1134 default: 1135 cant_happen(); 1136 break; 1137 } 1138 1139 if (socket_fd < 0 || socket_fd == INVALID_HANDLE 1140 || (hp == NULL && any_remote_host != 0)) 1141 return INVALID_HANDLE; 1142 1143 local_addr.sin_family = remote_addr.sin_family = AF_INET; 1144 local_addr.sin_addr.s_addr = htonl(INADDR_ANY); 1145 remote_addr.sin_addr.s_addr = htonl(INADDR_ANY); 1146 local_addr.sin_port = htons(localport); 1147 remote_addr.sin_port = htons(remoteport); 1148 if (bind(socket_fd, (struct sockaddr *) &local_addr, sizeof(local_addr)) == 0) { 1149 if (any_remote_host != 0) { /* not ANY => create a client */ 1150 if (type == INET_TCP || type == INET_UDP) { 1151 memcpy(&remote_addr.sin_addr, hp->h_addr, 1152 sizeof(remote_addr.sin_addr)); 1153 if (connect(socket_fd, 1154 (struct sockaddr *) &remote_addr, 1155 sizeof(remote_addr)) != 0) { 1156 close(socket_fd); 1157 if (localport == 0) 1158 socket_fd = INVALID_HANDLE; 1159 else 1160 socket_fd = socketopen(type, localport, 0, "0"); 1161 } 1162 } else { 1163 /* /inet/raw client not ready yet */ 1164 fatal(_("/inet/raw client not ready yet, sorry")); 1165 if (geteuid() != 0) 1166 fatal(_("only root may use `/inet/raw'.")); 1167 } 1168 } else { /* remote host is ANY => create a server */ 1169 if (type == INET_TCP) { 1170 int clientsocket_fd = INVALID_HANDLE; 1171 int namelen = sizeof(remote_addr); 1172 1173 if (listen(socket_fd, 1) >= 0 1174 && (clientsocket_fd = accept(socket_fd, 1175 (struct sockaddr *) &remote_addr, 1176 &namelen)) >= 0) { 1177 close(socket_fd); 1178 socket_fd = clientsocket_fd; 1179 } else { 1180 close(socket_fd); 1181 socket_fd = INVALID_HANDLE; 1182 } 1183 } else if (type == INET_UDP) { 1184 char buf[10]; 1185 int readle; 1186 1187#ifdef MSG_PEEK 1188 if (recvfrom(socket_fd, buf, 1, MSG_PEEK, 1189 (struct sockaddr *) & remote_addr, 1190 & readle) < 1 1191 || readle != sizeof(remote_addr) 1192 || connect(socket_fd, 1193 (struct sockaddr *)& remote_addr, 1194 readle) != 0) { 1195 close(socket_fd); 1196 socket_fd = INVALID_HANDLE; 1197 } 1198#endif 1199 } else { 1200 /* /inet/raw server not ready yet */ 1201 fatal(_("/inet/raw server not ready yet, sorry")); 1202 if (geteuid() != 0) 1203 fatal(_("only root may use `/inet/raw'.")); 1204 } 1205 } 1206 } else { 1207 close(socket_fd); 1208 socket_fd = INVALID_HANDLE; 1209 } 1210 1211 return socket_fd; 1212} 1213#endif /* HAVE_SOCKETS */ 1214 1215/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */ 1216 1217/* 1218 * This separate version is still needed for output, since file and pipe 1219 * output is done with stdio. iop_open() handles input with IOBUFs of 1220 * more "special" files. Those files are not handled here since it makes 1221 * no sense to use them for output. 1222 */ 1223 1224/* 1225 * Strictly speaking, "name" is not a "const char *" because we temporarily 1226 * change the string. 1227 */ 1228 1229int 1230devopen(const char *name, const char *mode) 1231{ 1232 int openfd; 1233 char *cp; 1234 char *ptr; 1235 int flag = 0; 1236 extern double strtod(); 1237 1238 flag = str2mode(mode); 1239 1240 if (STREQ(name, "-")) 1241 return fileno(stdin); 1242 1243 openfd = INVALID_HANDLE; 1244 1245 if (do_traditional) 1246 goto strictopen; 1247 1248 if ((openfd = os_devopen(name, flag)) != INVALID_HANDLE) { 1249 os_close_on_exec(openfd, name, "file", ""); 1250 return openfd; 1251 } 1252 1253 if (STREQN(name, "/dev/", 5)) { 1254 cp = (char *) name + 5; 1255 1256 if (STREQ(cp, "stdin") && (flag & O_ACCMODE) == O_RDONLY) 1257 openfd = fileno(stdin); 1258 else if (STREQ(cp, "stdout") && (flag & O_ACCMODE) == O_WRONLY) 1259 openfd = fileno(stdout); 1260 else if (STREQ(cp, "stderr") && (flag & O_ACCMODE) == O_WRONLY) 1261 openfd = fileno(stderr); 1262 else if (STREQN(cp, "fd/", 3)) { 1263 cp += 3; 1264 openfd = (int) strtod(cp, &ptr); 1265 if (openfd <= INVALID_HANDLE || ptr == cp) 1266 openfd = INVALID_HANDLE; 1267 } 1268 /* do not set close-on-exec for inherited fd's */ 1269 if (openfd != INVALID_HANDLE) 1270 return openfd; 1271 } else if (STREQN(name, "/inet/", 6)) { 1272#ifdef HAVE_SOCKETS 1273 /* /inet/protocol/localport/hostname/remoteport */ 1274 enum inet_prot protocol = INET_NONE; 1275 int localport, remoteport; 1276 char *hostname; 1277 char *hostnameslastcharp; 1278 char *localpname; 1279 char proto[4]; 1280 struct servent *service; 1281 1282 cp = (char *) name + 6; 1283 /* which protocol? */ 1284 if (STREQN(cp, "tcp/", 4)) 1285 protocol = INET_TCP; 1286 else if (STREQN(cp, "udp/", 4)) 1287 protocol = INET_UDP; 1288 else if (STREQN(cp, "raw/", 4)) 1289 protocol = INET_RAW; 1290 else 1291 fatal(_("no (known) protocol supplied in special filename `%s'"), 1292 name); 1293 1294 proto[0] = cp[0]; 1295 proto[1] = cp[1]; 1296 proto[2] = cp[2]; 1297 proto[3] = '\0'; 1298 cp += 4; 1299 1300 /* which localport? */ 1301 localpname = cp; 1302 while (*cp != '/' && *cp != '\0') 1303 cp++; 1304 /* 1305 * Require a port, let them explicitly put 0 if 1306 * they don't care. 1307 */ 1308 if (*cp != '/' || cp == localpname) 1309 fatal(_("special file name `%s' is incomplete"), name); 1310 /* We change the special file name temporarily because we 1311 * need a 0-terminated string here for conversion with atoi(). 1312 * By using atoi() the use of decimal numbers is enforced. 1313 */ 1314 *cp = '\0'; 1315 1316 localport = atoi(localpname); 1317 if (strcmp(localpname, "0") != 0 1318 && (localport <= 0 || localport > 65535)) { 1319 service = getservbyname(localpname, proto); 1320 if (service == NULL) 1321 fatal(_("local port invalid in `%s'"), name); 1322 else 1323 localport = ntohs(service->s_port); 1324 } 1325 *cp = '/'; 1326 1327 /* which hostname? */ 1328 cp++; 1329 hostname = cp; 1330 while (*cp != '/' && *cp != '\0') 1331 cp++; 1332 if (*cp != '/' || cp == hostname) 1333 fatal(_("must supply a remote hostname to `/inet'")); 1334 *cp = '\0'; 1335 hostnameslastcharp = cp; 1336 1337 /* which remoteport? */ 1338 cp++; 1339 /* 1340 * The remote port ends the special file name. 1341 * This means there already is a 0 at the end of the string. 1342 * Therefore no need to patch any string ending. 1343 * 1344 * Here too, require a port, let them explicitly put 0 if 1345 * they don't care. 1346 */ 1347 if (*cp == '\0') 1348 fatal(_("must supply a remote port to `/inet'")); 1349 remoteport = atoi(cp); 1350 if (strcmp(cp, "0") != 0 1351 && (remoteport <= 0 || remoteport > 65535)) { 1352 service = getservbyname(cp, proto); 1353 if (service == NULL) 1354 fatal(_("remote port invalid in `%s'"), name); 1355 else 1356 remoteport = ntohs(service->s_port); 1357 } 1358 1359 /* Open Sesame! */ 1360 openfd = socketopen(protocol, localport, remoteport, hostname); 1361 *hostnameslastcharp = '/'; 1362 1363#else /* ! HAVE_SOCKETS */ 1364 fatal(_("TCP/IP communications are not supported")); 1365#endif /* HAVE_SOCKETS */ 1366 } 1367 1368strictopen: 1369 if (openfd == INVALID_HANDLE) 1370 openfd = open(name, flag, 0666); 1371 if (openfd != INVALID_HANDLE) { 1372 if (os_isdir(openfd)) 1373 fatal(_("file `%s' is a directory"), name); 1374 1375 os_close_on_exec(openfd, name, "file", ""); 1376 } 1377 return openfd; 1378} 1379 1380 1381/* spec_setup --- setup an IOBUF for a special internal file */ 1382 1383static void 1384spec_setup(IOBUF *iop, int len, int allocate) 1385{ 1386 char *cp; 1387 1388 if (allocate) { 1389 emalloc(cp, char *, len+2, "spec_setup"); 1390 iop->buf = cp; 1391 } else { 1392 len = strlen(iop->buf); 1393 iop->buf[len++] = '\n'; /* get_a_record clobbered it */ 1394 iop->buf[len] = '\0'; /* just in case */ 1395 } 1396 iop->off = iop->buf; 1397 iop->count = 0; 1398 iop->size = len; 1399 iop->end = iop->buf + len; 1400 iop->dataend = iop->end; 1401 iop->fd = -1; 1402 iop->flag = IOP_IS_INTERNAL; 1403} 1404 1405/* specfdopen --- open an fd special file */ 1406 1407static int 1408specfdopen(IOBUF *iop, const char *name, const char *mode) 1409{ 1410 int fd; 1411 IOBUF *tp; 1412 1413 fd = devopen(name, mode); 1414 if (fd == INVALID_HANDLE) 1415 return INVALID_HANDLE; 1416 tp = iop_alloc(fd, name, NULL); 1417 if (tp == NULL) { 1418 /* don't leak fd's */ 1419 close(fd); 1420 return INVALID_HANDLE; 1421 } 1422 *iop = *tp; 1423 iop->flag |= IOP_NO_FREE; 1424 free(tp); 1425 return 0; 1426} 1427 1428#ifdef GETPGRP_VOID 1429#define getpgrp_arg() /* nothing */ 1430#else 1431#define getpgrp_arg() getpid() 1432#endif 1433 1434/* pidopen --- "open" /dev/pid, /dev/ppid, and /dev/pgrpid */ 1435 1436static int 1437pidopen(IOBUF *iop, const char *name, const char *mode ATTRIBUTE_UNUSED) 1438{ 1439 char tbuf[BUFSIZ]; 1440 int i; 1441 const char *cp = name + 5; 1442 1443 warning(_("use `PROCINFO[\"%s\"]' instead of `%s'"), cp, name); 1444 1445 if (name[6] == 'g') 1446 sprintf(tbuf, "%d\n", (int) getpgrp(getpgrp_arg())); 1447 else if (name[6] == 'i') 1448 sprintf(tbuf, "%d\n", (int) getpid()); 1449 else 1450 sprintf(tbuf, "%d\n", (int) getppid()); 1451 i = strlen(tbuf); 1452 spec_setup(iop, i, TRUE); 1453 strcpy(iop->buf, tbuf); 1454 return 0; 1455} 1456 1457/* useropen --- "open" /dev/user */ 1458 1459/* 1460 * /dev/user creates a record as follows: 1461 * $1 = getuid() 1462 * $2 = geteuid() 1463 * $3 = getgid() 1464 * $4 = getegid() 1465 * If multiple groups are supported, then $5 through $NF are the 1466 * supplementary group set. 1467 */ 1468 1469static int 1470useropen(IOBUF *iop, const char *name ATTRIBUTE_UNUSED, const char *mode ATTRIBUTE_UNUSED) 1471{ 1472 char tbuf[BUFSIZ], *cp; 1473 int i; 1474 1475 warning(_("use `PROCINFO[...]' instead of `/dev/user'")); 1476 1477 sprintf(tbuf, "%d %d %d %d", (int) getuid(), (int) geteuid(), (int) getgid(), (int) getegid()); 1478 1479 cp = tbuf + strlen(tbuf); 1480#if defined(NGROUPS_MAX) && NGROUPS_MAX > 0 1481 for (i = 0; i < ngroups; i++) { 1482 *cp++ = ' '; 1483 sprintf(cp, "%d", (int) groupset[i]); 1484 cp += strlen(cp); 1485 } 1486#endif 1487 *cp++ = '\n'; 1488 *cp++ = '\0'; 1489 1490 i = strlen(tbuf); 1491 spec_setup(iop, i, TRUE); 1492 strcpy(iop->buf, tbuf); 1493 return 0; 1494} 1495 1496/* iop_open --- handle special and regular files for input */ 1497 1498static IOBUF * 1499iop_open(const char *name, const char *mode, IOBUF *iop) 1500{ 1501 int openfd = INVALID_HANDLE; 1502 int flag = 0; 1503 static struct internal { 1504 const char *name; 1505 int compare; 1506 int (*fp) P((IOBUF *, const char *, const char *)); 1507 IOBUF iob; 1508 } table[] = { 1509 { "/dev/fd/", 8, specfdopen }, 1510 { "/dev/stdin", 10, specfdopen }, 1511 { "/dev/stdout", 11, specfdopen }, 1512 { "/dev/stderr", 11, specfdopen }, 1513 { "/inet/", 6, specfdopen }, 1514 { "/dev/pid", 8, pidopen }, 1515 { "/dev/ppid", 9, pidopen }, 1516 { "/dev/pgrpid", 11, pidopen }, 1517 { "/dev/user", 9, useropen }, 1518 }; 1519 int devcount = sizeof(table) / sizeof(table[0]); 1520 1521 flag = str2mode(mode); 1522 1523 if (STREQ(name, "-")) 1524 openfd = fileno(stdin); 1525 else if (do_traditional) 1526 goto strictopen; 1527 else if (STREQN(name, "/dev/", 5) || STREQN(name, "/inet/", 6)) { 1528 int i; 1529 1530 for (i = 0; i < devcount; i++) { 1531 if (STREQN(name, table[i].name, table[i].compare)) { 1532 iop = & table[i].iob; 1533 1534 if (iop->buf != NULL) { 1535 spec_setup(iop, 0, FALSE); 1536 return iop; 1537 } else if ((*table[i].fp)(iop, name, mode) == 0) 1538 return iop; 1539 else { 1540 warning(_("could not open `%s', mode `%s'"), 1541 name, mode); 1542 return NULL; 1543 } 1544 } 1545 } 1546 /* not in table, fall through to regular code */ 1547 } 1548 1549strictopen: 1550 if (openfd == INVALID_HANDLE) 1551 openfd = open(name, flag, 0666); 1552 if (openfd != INVALID_HANDLE) { 1553 if (os_isdir(openfd)) 1554 fatal(_("file `%s' is a directory"), name); 1555 1556 if (openfd > fileno(stderr)) 1557 os_close_on_exec(openfd, name, "file", ""); 1558 } 1559 return iop_alloc(openfd, name, iop); 1560} 1561 1562/* two_way_open --- open a two way communications channel */ 1563 1564static int 1565two_way_open(const char *str, struct redirect *rp) 1566{ 1567 static int no_ptys = FALSE; 1568 1569#ifdef HAVE_SOCKETS 1570 /* case 1: socket */ 1571 if (STREQN(str, "/inet/", 6)) { 1572 int fd, newfd; 1573 1574 fd = devopen(str, "rw"); 1575 if (fd == INVALID_HANDLE) 1576 return FALSE; 1577 rp->fp = fdopen(fd, "w"); 1578 if (rp->fp == NULL) { 1579 close(fd); 1580 return FALSE; 1581 } 1582 newfd = dup(fd); 1583 if (newfd < 0) { 1584 fclose(rp->fp); 1585 return FALSE; 1586 } 1587 os_close_on_exec(newfd, str, "socket", "to/from"); 1588 rp->iop = iop_alloc(newfd, str, NULL); 1589 if (rp->iop == NULL) { 1590 fclose(rp->fp); 1591 return FALSE; 1592 } 1593 rp->flag |= RED_SOCKET; 1594 return TRUE; 1595 } 1596#endif /* HAVE_SOCKETS */ 1597 1598#ifdef HAVE_PORTALS 1599 /* case 1.5: portal */ 1600 if (STREQN(str, "/p/", 3)) { 1601 int fd, newfd; 1602 1603 fd = open(str, O_RDWR); 1604 if (fd == INVALID_HANDLE) 1605 return FALSE; 1606 rp->fp = fdopen(fd, "w"); 1607 if (rp->fp == NULL) { 1608 close(fd); 1609 return FALSE; 1610 } 1611 newfd = dup(fd); 1612 if (newfd < 0) { 1613 fclose(rp->fp); 1614 return FALSE; 1615 } 1616 os_close_on_exec(newfd, str, "portal", "to/from"); 1617 rp->iop = iop_alloc(newfd, str, NULL); 1618 if (rp->iop == NULL) { 1619 fclose(rp->fp); 1620 return FALSE; 1621 } 1622 rp->flag |= RED_SOCKET; 1623 return TRUE; 1624 } 1625#endif /* HAVE_PORTALS */ 1626 1627#ifdef HAVE_TERMIOS_H 1628 /* case 2: use ptys for two-way communications to child */ 1629 if (! no_ptys && pty_vs_pipe(str)) { 1630 static int initialized = FALSE; 1631 static char first_pty_letter; 1632#ifdef HAVE_GRANTPT 1633 static int have_dev_ptmx; 1634#endif 1635 char slavenam[32]; 1636 char c; 1637 int master, dup_master; 1638 int slave; 1639 int save_errno; 1640 pid_t pid; 1641 struct stat statb; 1642 struct termios st; 1643 1644 if (! initialized) { 1645 initialized = TRUE; 1646#ifdef HAVE_GRANTPT 1647 have_dev_ptmx = (stat("/dev/ptmx", &statb) >= 0); 1648#endif 1649 c = 'p'; 1650 do { 1651 sprintf(slavenam, "/dev/pty%c0", c); 1652 if (stat(slavenam, &statb) >= 0) { 1653 first_pty_letter = c; 1654 break; 1655 } 1656 if (++c > 'z') 1657 c = 'a'; 1658 } while (c != 'p'); 1659 } 1660 1661#ifdef HAVE_GRANTPT 1662 if (have_dev_ptmx) { 1663 master = open("/dev/ptmx", O_RDWR); 1664 if (master >= 0) { 1665 char *tem; 1666 1667 grantpt(master); 1668 unlockpt(master); 1669 tem = ptsname(master); 1670 if (tem != NULL) { 1671 strcpy(slavenam, tem); 1672 goto got_the_pty; 1673 } 1674 (void) close(master); 1675 } 1676 } 1677#endif 1678 1679 if (first_pty_letter) { 1680 /* 1681 * Assume /dev/ptyXNN and /dev/ttyXN naming system. 1682 * The FIRST_PTY_LETTER gives the first X to try. We try in the 1683 * sequence FIRST_PTY_LETTER, .., 'z', 'a', .., FIRST_PTY_LETTER. 1684 * Is this worthwhile, or just over-zealous? 1685 */ 1686 c = first_pty_letter; 1687 do { 1688 int i; 1689 for (i = 0; i < 16; i++) { 1690 sprintf(slavenam, "/dev/pty%c%x", c, i); 1691 if (stat(slavenam, &statb) < 0) { 1692 no_ptys = TRUE; /* bypass all this next time */ 1693 goto use_pipes; 1694 } 1695 1696 if ((master = open(slavenam, O_RDWR)) >= 0) { 1697 slavenam[sizeof("/dev/") - 1] = 't'; 1698 if (access(slavenam, R_OK | W_OK) == 0) 1699 goto got_the_pty; 1700 close(master); 1701 } 1702 } 1703 if (++c > 'z') 1704 c = 'a'; 1705 } while (c != first_pty_letter); 1706 } else 1707 no_ptys = TRUE; 1708 1709 /* Couldn't find a pty. Fall back to using pipes. */ 1710 goto use_pipes; 1711 1712 got_the_pty: 1713 if ((slave = open(slavenam, O_RDWR)) < 0) { 1714 fatal(_("could not open `%s', mode `%s'"), 1715 slavenam, "r+"); 1716 } 1717 1718#ifdef I_PUSH 1719 /* 1720 * Push the necessary modules onto the slave to 1721 * get terminal semantics. 1722 */ 1723 ioctl(slave, I_PUSH, "ptem"); 1724 ioctl(slave, I_PUSH, "ldterm"); 1725#endif 1726 1727#ifdef TIOCSCTTY 1728 ioctl(slave, TIOCSCTTY, 0); 1729#endif 1730 tcgetattr(slave, &st); 1731 st.c_iflag &= ~(ISTRIP | IGNCR | INLCR | IXOFF); 1732 st.c_iflag |= (ICRNL | IGNPAR | BRKINT | IXON); 1733 st.c_oflag &= ~OPOST; 1734 st.c_cflag &= ~CSIZE; 1735 st.c_cflag |= CREAD | CS8 | CLOCAL; 1736 st.c_lflag &= ~(ECHO | ECHOE | ECHOK | NOFLSH | TOSTOP); 1737 st.c_lflag |= ISIG; 1738#if 0 1739 st.c_cc[VMIN] = 1; 1740 st.c_cc[VTIME] = 0; 1741#endif 1742 1743 /* Set some control codes to default values */ 1744#ifdef VINTR 1745 st.c_cc[VINTR] = '\003'; /* ^c */ 1746#endif 1747#ifdef VQUIT 1748 st.c_cc[VQUIT] = '\034'; /* ^| */ 1749#endif 1750#ifdef VERASE 1751 st.c_cc[VERASE] = '\177'; /* ^? */ 1752#endif 1753#ifdef VKILL 1754 st.c_cc[VKILL] = '\025'; /* ^u */ 1755#endif 1756#ifdef VEOF 1757 st.c_cc[VEOF] = '\004'; /* ^d */ 1758#endif 1759 tcsetattr(slave, TCSANOW, &st); 1760 1761 switch (pid = fork ()) { 1762 case 0: 1763 /* Child process */ 1764 if (close(master) == -1) 1765 fatal(_("close of master pty failed (%s)"), strerror(errno)); 1766 if (close(1) == -1) 1767 fatal(_("close of stdout in child failed (%s)"), 1768 strerror(errno)); 1769 if (dup(slave) != 1) 1770 fatal(_("moving slave pty to stdout in child failed (dup: %s)"), strerror(errno)); 1771 if (close(0) == -1) 1772 fatal(_("close of stdin in child failed (%s)"), 1773 strerror(errno)); 1774 if (dup(slave) != 0) 1775 fatal(_("moving slave pty to stdin in child failed (dup: %s)"), strerror(errno)); 1776 if (close(slave)) 1777 fatal(_("close of slave pty failed (%s)"), strerror(errno)); 1778 1779 /* stderr does NOT get dup'ed onto child's stdout */ 1780 1781 signal(SIGPIPE, SIG_DFL); 1782 1783 execl("/bin/sh", "sh", "-c", str, NULL); 1784 _exit(127); 1785 1786 case -1: 1787 save_errno = errno; 1788 close(master); 1789 errno = save_errno; 1790 return FALSE; 1791 1792 } 1793 1794 /* parent */ 1795 if (close(slave)) 1796 fatal(_("close of slave pty failed (%s)"), strerror(errno)); 1797 1798 rp->pid = pid; 1799 rp->iop = iop_alloc(master, str, NULL); 1800 if (rp->iop == NULL) { 1801 (void) close(master); 1802 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */ 1803 return FALSE; 1804 } 1805 1806 /* 1807 * Force read and write ends of two-way connection to 1808 * be different fd's so they can be closed independently. 1809 */ 1810 if ((dup_master = dup(master)) < 0 1811 || (rp->fp = fdopen(dup_master, "w")) == NULL) { 1812 iop_close(rp->iop); 1813 rp->iop = NULL; 1814 (void) close(master); 1815 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */ 1816 if (dup_master > 0) 1817 (void) close(dup_master); 1818 return FALSE; 1819 } 1820 rp->flag |= RED_PTY; 1821 os_close_on_exec(master, str, "pipe", "from"); 1822 os_close_on_exec(dup_master, str, "pipe", "to"); 1823 first_pty_letter = '\0'; /* reset for next command */ 1824 return TRUE; 1825 } 1826#endif /* HAVE_TERMIOS_H */ 1827 1828use_pipes: 1829#ifndef PIPES_SIMULATED /* real pipes */ 1830 /* case 3: two way pipe to a child process */ 1831 { 1832 int ptoc[2], ctop[2]; 1833 int pid; 1834 int save_errno; 1835#ifdef __EMX__ 1836 int save_stdout, save_stdin; 1837#endif 1838 1839 if (pipe(ptoc) < 0) 1840 return FALSE; /* errno set, diagnostic from caller */ 1841 1842 if (pipe(ctop) < 0) { 1843 save_errno = errno; 1844 close(ptoc[0]); 1845 close(ptoc[1]); 1846 errno = save_errno; 1847 return FALSE; 1848 } 1849 1850#ifdef __EMX__ 1851 save_stdin = dup(0); /* duplicate stdin */ 1852 save_stdout = dup(1); /* duplicate stdout */ 1853 1854 if (save_stdout == -1 || save_stdin == -1) { 1855 /* if an error occurrs close all open file handles */ 1856 save_errno = errno; 1857 if (save_stdin != -1) 1858 close(save_stdin); 1859 if (save_stdout != -1) 1860 close(save_stdout); 1861 close(ptoc[0]); close(ptoc[1]); 1862 close(ctop[0]); close(ctop[1]); 1863 errno = save_errno; 1864 return FALSE; 1865 } 1866 1867 /* connect pipes to stdin and stdout */ 1868 close(1); /* close stdout */ 1869 if (dup(ctop[1]) != 1) /* connect pipe input to stdout */ 1870 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno)); 1871 1872 close(0); /* close stdin */ 1873 if (dup(ptoc[0]) != 0) /* connect pipe output to stdin */ 1874 fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno)); 1875 1876 /* none of these handles must be inherited by the child process */ 1877 (void) close(ptoc[0]); /* close pipe output, child will use stdin instead */ 1878 (void) close(ctop[1]); /* close pipe input, child will use stdout instead */ 1879 1880 os_close_on_exec(ptoc[1], str, "pipe", "from"); /* pipe input: output of the parent process */ 1881 os_close_on_exec(ctop[0], str, "pipe", "from"); /* pipe output: input of the parent process */ 1882 os_close_on_exec(save_stdin, str, "pipe", "from"); /* saved stdin of the parent process */ 1883 os_close_on_exec(save_stdout, str, "pipe", "from"); /* saved stdout of the parent process */ 1884 1885 /* stderr does NOT get dup'ed onto child's stdout */ 1886 pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", str, NULL); 1887 1888 /* restore stdin and stdout */ 1889 close(1); 1890 if (dup(save_stdout) != 1) 1891 fatal(_("restoring stdout in parent process failed\n")); 1892 close(save_stdout); 1893 1894 close(0); 1895 if (dup(save_stdin) != 0) 1896 fatal(_("restoring stdin in parent process failed\n")); 1897 close(save_stdin); 1898 1899 if (pid < 0) { /* spawnl() failed */ 1900 save_errno = errno; 1901 close(ptoc[1]); 1902 close(ctop[0]); 1903 1904 errno = save_errno; 1905 return FALSE; 1906 } 1907 1908#else /* NOT __EMX__ */ 1909 if ((pid = fork()) < 0) { 1910 save_errno = errno; 1911 close(ptoc[0]); close(ptoc[1]); 1912 close(ctop[0]); close(ctop[1]); 1913 errno = save_errno; 1914 return FALSE; 1915 } 1916 1917 if (pid == 0) { /* child */ 1918 if (close(1) == -1) 1919 fatal(_("close of stdout in child failed (%s)"), 1920 strerror(errno)); 1921 if (dup(ctop[1]) != 1) 1922 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno)); 1923 if (close(0) == -1) 1924 fatal(_("close of stdin in child failed (%s)"), 1925 strerror(errno)); 1926 if (dup(ptoc[0]) != 0) 1927 fatal(_("moving pipe to stdin in child failed (dup: %s)"), strerror(errno)); 1928 if ( close(ptoc[0]) == -1 || close(ptoc[1]) == -1 1929 || close(ctop[0]) == -1 || close(ctop[1]) == -1) 1930 fatal(_("close of pipe failed (%s)"), strerror(errno)); 1931 /* stderr does NOT get dup'ed onto child's stdout */ 1932 execl("/bin/sh", "sh", "-c", str, NULL); 1933 _exit(errno == ENOENT ? 127 : 126); 1934 } 1935#endif /* NOT __EMX__ */ 1936 1937 /* parent */ 1938 rp->pid = pid; 1939 rp->iop = iop_alloc(ctop[0], str, NULL); 1940 if (rp->iop == NULL) { 1941 (void) close(ctop[0]); 1942 (void) close(ctop[1]); 1943 (void) close(ptoc[0]); 1944 (void) close(ptoc[1]); 1945 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */ 1946 1947 return FALSE; 1948 } 1949 rp->fp = fdopen(ptoc[1], "w"); 1950 if (rp->fp == NULL) { 1951 iop_close(rp->iop); 1952 rp->iop = NULL; 1953 (void) close(ctop[0]); 1954 (void) close(ctop[1]); 1955 (void) close(ptoc[0]); 1956 (void) close(ptoc[1]); 1957 (void) kill(pid, SIGKILL); /* overkill? (pardon pun) */ 1958 1959 return FALSE; 1960 } 1961 1962#ifndef __EMX__ 1963 os_close_on_exec(ctop[0], str, "pipe", "from"); 1964 os_close_on_exec(ptoc[1], str, "pipe", "from"); 1965 1966 (void) close(ptoc[0]); 1967 (void) close(ctop[1]); 1968#endif 1969 1970 return TRUE; 1971 } 1972 1973#else /*PIPES_SIMULATED*/ 1974 1975 fatal(_("`|&' not supported")); 1976 /*NOTREACHED*/ 1977 return FALSE; 1978 1979#endif 1980} 1981 1982#ifndef PIPES_SIMULATED /* real pipes */ 1983 1984/* wait_any --- wait for a child process, close associated pipe */ 1985 1986static int 1987wait_any(int interesting) /* pid of interest, if any */ 1988{ 1989 RETSIGTYPE (*hstat) P((int)), (*istat) P((int)), (*qstat) P((int)); 1990 int pid; 1991 int status = 0; 1992 struct redirect *redp; 1993 extern int errno; 1994 1995 hstat = signal(SIGHUP, SIG_IGN); 1996 istat = signal(SIGINT, SIG_IGN); 1997 qstat = signal(SIGQUIT, SIG_IGN); 1998 for (;;) { 1999#ifdef HAVE_SYS_WAIT_H /* Posix compatible sys/wait.h */ 2000 pid = wait(&status); 2001#else 2002 pid = wait((union wait *)&status); 2003#endif /* NeXT */ 2004 if (interesting && pid == interesting) { 2005 break; 2006 } else if (pid != -1) { 2007 for (redp = red_head; redp != NULL; redp = redp->next) 2008 if (pid == redp->pid) { 2009 redp->pid = -1; 2010 redp->status = status; 2011 break; 2012 } 2013 } 2014 if (pid == -1 && errno == ECHILD) 2015 break; 2016 } 2017 signal(SIGHUP, hstat); 2018 signal(SIGINT, istat); 2019 signal(SIGQUIT, qstat); 2020 return(status); 2021} 2022 2023/* gawk_popen --- open an IOBUF on a child process */ 2024 2025static IOBUF * 2026gawk_popen(const char *cmd, struct redirect *rp) 2027{ 2028 int p[2]; 2029 register int pid; 2030#ifdef __EMX__ 2031 int save_stdout; 2032#endif 2033 2034 /* 2035 * used to wait for any children to synchronize input and output, 2036 * but this could cause gawk to hang when it is started in a pipeline 2037 * and thus has a child process feeding it input (shell dependant) 2038 */ 2039 /*(void) wait_any(0);*/ /* wait for outstanding processes */ 2040 2041 if (pipe(p) < 0) 2042 fatal(_("cannot open pipe `%s' (%s)"), cmd, strerror(errno)); 2043 2044#ifdef __EMX__ 2045 save_stdout = dup(1); /* save stdout */ 2046 rp->iop = NULL; 2047 if (save_stdout == -1) 2048 return rp->iop; /* failed */ 2049 2050 close(1); /* close stdout */ 2051 if (dup(p[1]) != 1) 2052 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno)); 2053 2054 /* none of these handles must be inherited by the child process */ 2055 close(p[1]); /* close pipe input */ 2056 2057 os_close_on_exec(p[0], cmd, "pipe", "from"); /* pipe output: input of the parent process */ 2058 os_close_on_exec(save_stdout, cmd, "pipe", "from"); /* saved stdout of the parent process */ 2059 2060 pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", cmd, NULL); 2061 2062 /* restore stdout */ 2063 close(1); 2064 if (dup(save_stdout) != 1) 2065 fatal(_("restoring stdout in parent process failed\n")); 2066 close(save_stdout); 2067 2068#else /* NOT __EMX__ */ 2069 if ((pid = fork()) == 0) { 2070 if (close(1) == -1) 2071 fatal(_("close of stdout in child failed (%s)"), 2072 strerror(errno)); 2073 if (dup(p[1]) != 1) 2074 fatal(_("moving pipe to stdout in child failed (dup: %s)"), strerror(errno)); 2075 if (close(p[0]) == -1 || close(p[1]) == -1) 2076 fatal(_("close of pipe failed (%s)"), strerror(errno)); 2077 execl("/bin/sh", "sh", "-c", cmd, NULL); 2078 _exit(errno == ENOENT ? 127 : 126); 2079 } 2080#endif /* NOT __EMX__ */ 2081 2082 if (pid == -1) 2083 fatal(_("cannot create child process for `%s' (fork: %s)"), cmd, strerror(errno)); 2084 rp->pid = pid; 2085#ifndef __EMX__ 2086 if (close(p[1]) == -1) 2087 fatal(_("close of pipe failed (%s)"), strerror(errno)); 2088#endif 2089 os_close_on_exec(p[0], cmd, "pipe", "from"); 2090 rp->iop = iop_alloc(p[0], cmd, NULL); 2091 if (rp->iop == NULL) 2092 (void) close(p[0]); 2093 2094 return (rp->iop); 2095} 2096 2097/* gawk_pclose --- close an open child pipe */ 2098 2099static int 2100gawk_pclose(struct redirect *rp) 2101{ 2102 if (rp->iop != NULL) 2103 (void) iop_close(rp->iop); 2104 rp->iop = NULL; 2105 2106 /* process previously found, return stored status */ 2107 if (rp->pid == -1) 2108 return rp->status; 2109 rp->status = wait_any(rp->pid); 2110 rp->pid = -1; 2111 return rp->status; 2112} 2113 2114#else /* PIPES_SIMULATED */ 2115 2116/* 2117 * use temporary file rather than pipe 2118 * except if popen() provides real pipes too 2119 */ 2120 2121#if defined(VMS) || defined(OS2) || defined (MSDOS) || defined(WIN32) || defined(TANDEM) || defined(__EMX__) 2122 2123/* gawk_popen --- open an IOBUF on a child process */ 2124 2125static IOBUF * 2126gawk_popen(const char *cmd, struct redirect *rp) 2127{ 2128 FILE *current; 2129 2130 os_restore_mode(fileno(stdin)); 2131 current = popen(cmd, binmode("r")); 2132#ifdef O_BINARY 2133 if ((BINMODE & 1) != 0) 2134 os_setbinmode(fileno(stdin), O_BINARY); 2135#endif 2136 if (current == NULL) 2137 return NULL; 2138 os_close_on_exec(fileno(current), cmd, "pipe", "from"); 2139 rp->iop = iop_alloc(fileno(current), cmd, NULL); 2140 if (rp->iop == NULL) { 2141 (void) pclose(current); 2142 current = NULL; 2143 } 2144 rp->ifp = current; 2145 return (rp->iop); 2146} 2147 2148/* gawk_pclose --- close an open child pipe */ 2149 2150static int 2151gawk_pclose(struct redirect *rp) 2152{ 2153 int rval, aval, fd = rp->iop->fd; 2154 2155 if (rp->iop != NULL) { 2156 rp->iop->fd = dup(fd); /* kludge to allow close() + pclose() */ 2157 rval = iop_close(rp->iop); 2158 } 2159 rp->iop = NULL; 2160 aval = pclose(rp->ifp); 2161 rp->ifp = NULL; 2162 return (rval < 0 ? rval : aval); 2163} 2164#else /* not (VMS || OS2 || MSDOS || TANDEM) */ 2165 2166static struct pipeinfo { 2167 char *command; 2168 char *name; 2169} pipes[_NFILE]; 2170 2171/* gawk_popen --- open an IOBUF on a child process */ 2172 2173static IOBUF * 2174gawk_popen(const char *cmd, struct redirect *rp) 2175{ 2176 extern char *strdup P((const char *)); 2177 int current; 2178 char *name; 2179 static char cmdbuf[256]; 2180 2181 /* get a name to use */ 2182 if ((name = tempnam(".", "pip")) == NULL) 2183 return NULL; 2184 sprintf(cmdbuf, "%s > %s", cmd, name); 2185 system(cmdbuf); 2186 if ((current = open(name, O_RDONLY)) == INVALID_HANDLE) 2187 return NULL; 2188 pipes[current].name = name; 2189 pipes[current].command = strdup(cmd); 2190 os_close_on_exec(current, cmd, "pipe", "from"); 2191 rp->iop = iop_alloc(current, name, NULL); 2192 if (rp->iop == NULL) 2193 (void) close(current); 2194 return (rp->iop); 2195} 2196 2197/* gawk_pclose --- close an open child pipe */ 2198 2199static int 2200gawk_pclose(struct redirect *rp) 2201{ 2202 int cur = rp->iop->fd; 2203 int rval = 0; 2204 2205 if (rp->iop != NULL) 2206 rval = iop_close(rp->iop); 2207 rp->iop = NULL; 2208 2209 /* check for an open file */ 2210 if (pipes[cur].name == NULL) 2211 return -1; 2212 unlink(pipes[cur].name); 2213 free(pipes[cur].name); 2214 pipes[cur].name = NULL; 2215 free(pipes[cur].command); 2216 return rval; 2217} 2218#endif /* not (VMS || OS2 || MSDOS || TANDEM) */ 2219 2220#endif /* PIPES_SIMULATED */ 2221 2222/* do_getline --- read in a line, into var and with redirection, as needed */ 2223 2224NODE * 2225do_getline(NODE *tree) 2226{ 2227 struct redirect *rp = NULL; 2228 IOBUF *iop; 2229 int cnt = EOF; 2230 char *s = NULL; 2231 int errcode; 2232 2233 while (cnt == EOF) { 2234 if (tree->rnode == NULL) { /* no redirection */ 2235 iop = nextfile(FALSE); 2236 if (iop == NULL) /* end of input */ 2237 return tmp_number((AWKNUM) 0.0); 2238 } else { 2239 int redir_error = 0; 2240 2241 rp = redirect(tree->rnode, &redir_error); 2242 if (rp == NULL && redir_error) { /* failed redirect */ 2243 if (! do_traditional) 2244 update_ERRNO(); 2245 2246 return tmp_number((AWKNUM) -1.0); 2247 } 2248 iop = rp->iop; 2249 if (iop == NULL) /* end of input */ 2250 return tmp_number((AWKNUM) 0.0); 2251 } 2252 errcode = 0; 2253 cnt = get_a_record(&s, iop, &errcode); 2254 if (errcode != 0) { 2255 if (! do_traditional) 2256 update_ERRNO(); 2257 2258 return tmp_number((AWKNUM) -1.0); 2259 } 2260 if (cnt == EOF) { 2261 if (rp != NULL) { 2262 /* 2263 * Don't do iop_close() here if we are 2264 * reading from a pipe; otherwise 2265 * gawk_pclose will not be called. 2266 */ 2267 if ((rp->flag & (RED_PIPE|RED_TWOWAY)) == 0) { 2268 (void) iop_close(iop); 2269 rp->iop = NULL; 2270 } 2271 rp->flag |= RED_EOF; /* sticky EOF */ 2272 return tmp_number((AWKNUM) 0.0); 2273 } else 2274 continue; /* try another file */ 2275 } 2276 if (rp == NULL) { 2277 NR++; 2278 FNR++; 2279 } 2280 if (tree->lnode == NULL) /* no optional var. */ 2281 set_record(s, cnt); 2282 else { /* assignment to variable */ 2283 Func_ptr after_assign = NULL; 2284 NODE **lhs; 2285 2286 lhs = get_lhs(tree->lnode, &after_assign, FALSE); 2287 unref(*lhs); 2288 *lhs = make_string(s, cnt); 2289 (*lhs)->flags |= MAYBE_NUM; 2290 /* we may have to regenerate $0 here! */ 2291 if (after_assign != NULL) 2292 (*after_assign)(); 2293 } 2294 } 2295 return tmp_number((AWKNUM) 1.0); 2296} 2297 2298/* pathopen --- pathopen with default file extension handling */ 2299 2300int 2301pathopen(const char *file) 2302{ 2303 int fd = do_pathopen(file); 2304 2305#ifdef DEFAULT_FILETYPE 2306 if (! do_traditional && fd <= INVALID_HANDLE) { 2307 char *file_awk; 2308 int save = errno; 2309#ifdef VMS 2310 int vms_save = vaxc$errno; 2311#endif 2312 2313 /* append ".awk" and try again */ 2314 emalloc(file_awk, char *, strlen(file) + 2315 sizeof(DEFAULT_FILETYPE) + 1, "pathopen"); 2316 sprintf(file_awk, "%s%s", file, DEFAULT_FILETYPE); 2317 fd = do_pathopen(file_awk); 2318 free(file_awk); 2319 if (fd <= INVALID_HANDLE) { 2320 errno = save; 2321#ifdef VMS 2322 vaxc$errno = vms_save; 2323#endif 2324 } 2325 } 2326#endif /*DEFAULT_FILETYPE*/ 2327 2328 return fd; 2329} 2330 2331/* do_pathopen --- search $AWKPATH for source file */ 2332 2333static int 2334do_pathopen(const char *file) 2335{ 2336 static const char *savepath = NULL; 2337 static int first = TRUE; 2338 const char *awkpath; 2339 char *cp, *trypath; 2340 int fd; 2341 int len; 2342 2343 if (STREQ(file, "-")) 2344 return (0); 2345 2346 if (do_traditional) 2347 return (devopen(file, "r")); 2348 2349 if (first) { 2350 first = FALSE; 2351 if ((awkpath = getenv("AWKPATH")) != NULL && *awkpath) 2352 savepath = awkpath; /* used for restarting */ 2353 else 2354 savepath = defpath; 2355 } 2356 awkpath = savepath; 2357 2358 /* some kind of path name, no search */ 2359 if (ispath(file)) 2360 return (devopen(file, "r")); 2361 2362 /* no arbitrary limits: */ 2363 len = strlen(awkpath) + strlen(file) + 2; 2364 emalloc(trypath, char *, len, "do_pathopen"); 2365 2366 do { 2367 trypath[0] = '\0'; 2368 2369 for (cp = trypath; *awkpath && *awkpath != envsep; ) 2370 *cp++ = *awkpath++; 2371 2372 if (cp != trypath) { /* nun-null element in path */ 2373 /* add directory punctuation only if needed */ 2374 if (! isdirpunct(*(cp-1))) 2375 *cp++ = '/'; 2376 /* append filename */ 2377 strcpy(cp, file); 2378 } else 2379 strcpy(trypath, file); 2380 if ((fd = devopen(trypath, "r")) > INVALID_HANDLE) { 2381 free(trypath); 2382 return (fd); 2383 } 2384 2385 /* no luck, keep going */ 2386 if(*awkpath == envsep && awkpath[1] != '\0') 2387 awkpath++; /* skip colon */ 2388 } while (*awkpath != '\0'); 2389 free(trypath); 2390 2391 /* 2392 * You might have one of the awk paths defined, WITHOUT the current 2393 * working directory in it. Therefore try to open the file in the 2394 * current directory. 2395 */ 2396 return (devopen(file, "r")); 2397} 2398 2399#ifdef TEST 2400int bufsize = 8192; 2401 2402void 2403fatal(const char *s) 2404{ 2405 printf("%s\n", s); 2406 exit(1); 2407} 2408#endif 2409 2410/* iop_alloc --- allocate an IOBUF structure for an open fd */ 2411 2412static IOBUF * 2413iop_alloc(int fd, const char *name, IOBUF *iop) 2414{ 2415 struct stat sbuf; 2416 2417 if (fd == INVALID_HANDLE) 2418 return NULL; 2419 if (iop == NULL) 2420 emalloc(iop, IOBUF *, sizeof(IOBUF), "iop_alloc"); 2421 memset(iop, '\0', sizeof(IOBUF)); 2422 iop->flag = 0; 2423 if (isatty(fd)) 2424 iop->flag |= IOP_IS_TTY; 2425 iop->readsize = iop->size = optimal_bufsize(fd, & sbuf); 2426 iop->sbuf = sbuf; 2427 if (do_lint && S_ISREG(sbuf.st_mode) && sbuf.st_size == 0) 2428 lintwarn(_("data file `%s' is empty"), name); 2429 errno = 0; 2430 iop->fd = fd; 2431 iop->count = iop->scanoff = 0; 2432 iop->name = name; 2433 emalloc(iop->buf, char *, iop->size += 2, "iop_alloc"); 2434 iop->off = iop->buf; 2435 iop->dataend = NULL; 2436 iop->end = iop->buf + iop->size; 2437 iop->flag = 0; 2438 return iop; 2439} 2440 2441#define set_RT_to_null() \ 2442 (void)(! do_traditional && (unref(RT_node->var_value), \ 2443 RT_node->var_value = Nnull_string)) 2444 2445#define set_RT(str, len) \ 2446 (void)(! do_traditional && (unref(RT_node->var_value), \ 2447 RT_node->var_value = make_string(str, len))) 2448 2449/* grow must increase size of buffer, set end, make sure off and dataend point at */ 2450/* right spot. */ 2451/* */ 2452/* */ 2453/* <growbuffer>= */ 2454/* grow_iop_buffer --- grow the buffer */ 2455 2456static void 2457grow_iop_buffer(IOBUF *iop) 2458{ 2459 size_t valid = iop->dataend - iop->off; 2460 size_t off = iop->off - iop->buf; 2461 size_t newsize; 2462 2463 /* 2464 * Lop off original extra two bytes, double the size, 2465 * add them back. 2466 */ 2467 newsize = ((iop->size - 2) * 2) + 2; 2468 2469 /* Check for overflow */ 2470 if (newsize <= iop->size) 2471 fatal(_("could not allocate more input memory")); 2472 2473 /* Make sure there's room for a disk block */ 2474 if (newsize - valid < iop->readsize) 2475 newsize += iop->readsize + 2; 2476 2477 /* Check for overflow, again */ 2478 if (newsize <= iop->size) 2479 fatal(_("could not allocate more input memory")); 2480 2481 iop->size = newsize; 2482 erealloc(iop->buf, char *, iop->size, "grow_iop_buffer"); 2483 iop->off = iop->buf + off; 2484 iop->dataend = iop->off + valid; 2485 iop->end = iop->buf + iop->size; 2486} 2487 2488/* Here are the routines. */ 2489/* */ 2490/* */ 2491/* <rs1scan>= */ 2492/* rs1scan --- scan for a single character record terminator */ 2493 2494static RECVALUE 2495rs1scan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state) 2496{ 2497 register char *bp; 2498 register char rs; 2499#ifdef MBS_SUPPORT 2500 size_t mbclen = 0; 2501 mbstate_t mbs; 2502#endif 2503 2504 memset(recm, '\0', sizeof(struct recmatch)); 2505 rs = RS->stptr[0]; 2506 *(iop->dataend) = rs; /* set sentinel */ 2507 recm->start = iop->off; /* beginning of record */ 2508 2509 bp = iop->off; 2510 if (*state == INDATA) /* skip over data we've already seen */ 2511 bp += iop->scanoff; 2512 2513#ifdef MBS_SUPPORT 2514 /* 2515 * From: Bruno Haible <bruno@clisp.org> 2516 * To: Aharon Robbins <arnold@skeeve.com>, gnits@gnits.org 2517 * Subject: Re: multibyte locales: any way to find if a character isn't multibyte? 2518 * Date: Mon, 23 Jun 2003 12:20:16 +0200 2519 * Cc: isamu@yamato.ibm.com 2520 * 2521 * Hi, 2522 * 2523 * > Is there any way to make the following query to the current locale? 2524 * > 2525 * > Given an 8-bit value, can this value ever appear as part of 2526 * > a multibyte character? 2527 * 2528 * There is no simple answer here. The easiest solution I see is to 2529 * get the current locale's codeset (via locale_charset() which is a 2530 * wrapper around nl_langinfo(CODESET)), and then perform a case-by-case 2531 * treatment of the known multibyte encodings, from GB2312 to EUC-JISX0213; 2532 * for the unibyte encodings, a single btowc() call will tell you. 2533 * 2534 * > This is particularly critical for me for ASCII newline ('\n'). If I 2535 * > can be guaranteed that it never shows up as part of a multibyte character, 2536 * > I can speed up gawk considerably in mulitbyte locales. 2537 * 2538 * This is much simpler to answer! 2539 * In all ASCII based multibyte encodings used for locales today (this 2540 * excludes EBCDIC based doublebyte encodings from IBM, and also excludes 2541 * ISO-2022-JP which is used for email exchange but not as a locale encoding) 2542 * ALL bytes in the range 0x00..0x2F occur only as a single character, not 2543 * as part of a multibyte character. 2544 * 2545 * So it's safe to assume, but deserves a comment in the source. 2546 * 2547 * Bruno 2548 *************************************************************** 2549 * From: Bruno Haible <bruno@clisp.org> 2550 * To: Aharon Robbins <arnold@skeeve.com> 2551 * Subject: Re: multibyte locales: any way to find if a character isn't multibyte? 2552 * Date: Mon, 23 Jun 2003 14:27:49 +0200 2553 * 2554 * On Monday 23 June 2003 14:11, you wrote: 2555 * 2556 * > if (rs != '\n' && MB_CUR_MAX > 1) { 2557 * 2558 * If you assume ASCII, you can even write 2559 * 2560 * if (rs >= 0x30 && MB_CUR_MAX > 1) { 2561 * 2562 * (this catches also the space character) but if portability to EBCDIC 2563 * systems is desired, your code is fine as is. 2564 * 2565 * Bruno 2566 */ 2567 /* Thus, the check for \n here; big speedup ! */ 2568 if (rs != '\n' && gawk_mb_cur_max > 1) { 2569 int len = iop->dataend - bp; 2570 int found = 0; 2571 memset(&mbs, 0, sizeof(mbstate_t)); 2572 do { 2573 if (*bp == rs) 2574 found = 1; 2575 mbclen = mbrlen(bp, len, &mbs); 2576 if ((mbclen == 1) || (mbclen == (size_t) -1) 2577 || (mbclen == (size_t) -2) || (mbclen == 0)) { 2578 /* We treat it as a singlebyte character. */ 2579 mbclen = 1; 2580 } 2581 len -= mbclen; 2582 bp += mbclen; 2583 } while (len > 0 && ! found); 2584 2585 /* Check that newline found isn't the sentinel. */ 2586 if (found && (bp - mbclen) < iop->dataend) { 2587 /* 2588 * set len to what we have so far, in case this is 2589 * all there is 2590 */ 2591 recm->len = bp - recm->start - mbclen; 2592 recm->rt_start = bp - mbclen; 2593 recm->rt_len = mbclen; 2594 *state = NOSTATE; 2595 return REC_OK; 2596 } else { 2597 /* also set len */ 2598 recm->len = bp - recm->start; 2599 *state = INDATA; 2600 iop->scanoff = bp - iop->off; 2601 return NOTERM; 2602 } 2603 } 2604#endif 2605 while (*bp != rs) 2606 bp++; 2607 2608 /* set len to what we have so far, in case this is all there is */ 2609 recm->len = bp - recm->start; 2610 2611 if (bp < iop->dataend) { /* found it in the buffer */ 2612 recm->rt_start = bp; 2613 recm->rt_len = 1; 2614 *state = NOSTATE; 2615 return REC_OK; 2616 } else { 2617 *state = INDATA; 2618 iop->scanoff = bp - iop->off; 2619 return NOTERM; 2620 } 2621} 2622 2623/* <rsrescan>= */ 2624/* rsrescan --- search for a regex match in the buffer */ 2625 2626static RECVALUE 2627rsrescan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state) 2628{ 2629 register char *bp; 2630 size_t restart = 0, reend = 0; 2631 Regexp *RSre = RS_regexp; 2632 2633 memset(recm, '\0', sizeof(struct recmatch)); 2634 recm->start = iop->off; 2635 2636 bp = iop->off; 2637 if (*state == INDATA) 2638 bp += iop->scanoff; 2639 2640again: 2641 /* case 1, no match */ 2642 if (research(RSre, bp, 0, iop->dataend - bp, TRUE) == -1) { 2643 /* set len, in case this all there is. */ 2644 recm->len = iop->dataend - iop->off - 1; 2645 return NOTERM; 2646 } 2647 2648 /* ok, we matched within the buffer, set start and end */ 2649 restart = RESTART(RSre, iop->off); 2650 reend = REEND(RSre, iop->off); 2651 2652 /* case 2, null regex match, grow buffer, try again */ 2653 if (restart == reend) { 2654 *state = INDATA; 2655 iop->scanoff = reend + 1; 2656 /* 2657 * If still room in buffer, skip over null match 2658 * and restart search. Otherwise, return. 2659 */ 2660 if (bp + iop->scanoff < iop->dataend) { 2661 bp += iop->scanoff; 2662 goto again; 2663 } 2664 recm->len = (bp - iop->off) + restart; 2665 return NOTERM; 2666 } 2667 2668 /* 2669 * At this point, we have a non-empty match. 2670 * 2671 * First, fill in rest of data. The rest of the cases return 2672 * a record and terminator. 2673 */ 2674 recm->len = restart; 2675 recm->rt_start = bp + restart; 2676 recm->rt_len = reend - restart; 2677 *state = NOSTATE; 2678 2679 /* 2680 * 3. Match exactly at end: 2681 * if re is a simple string match 2682 * found a simple string match at end, return REC_OK 2683 * else 2684 * grow buffer, add more data, try again 2685 * fi 2686 */ 2687 if (iop->off + reend >= iop->dataend) { 2688 if (reisstring(RS->stptr, RS->stlen, RSre, iop->off)) 2689 return REC_OK; 2690 else 2691 return TERMATEND; 2692 } 2693 2694 /* 2695 * 4. Match within xxx bytes of end & maybe islong re: 2696 * return TERMNEAREND 2697 */ 2698 2699 /* 2700 * case 4, match succeeded, but there may be more in 2701 * the next input buffer. 2702 * 2703 * Consider an RS of xyz(abc)? where the 2704 * exact end of the buffer is xyza and the 2705 * next two, unread, characters are bc. 2706 * 2707 * This matches the "xyz" and ends up putting the 2708 * "abc" into the front of the next record. Ooops. 2709 * 2710 * The remaybelong() function looks to see if the 2711 * regex contains one of: + * ? |. This is a very 2712 * simple heuristic, but in combination with the 2713 * "end of match within a few bytes of end of buffer" 2714 * check, should keep things reasonable. 2715 */ 2716 2717 /* 2718 * XXX: The reisstring and remaybelong tests should 2719 * really be done once when RS is assigned to and 2720 * then tested as flags here. Maybe one day. 2721 */ 2722 2723 /* succession of tests is easier to trace in GDB. */ 2724 if (remaybelong(RS->stptr, RS->stlen)) { 2725 char *matchend = iop->off + reend; 2726 2727 if (iop->dataend - matchend < RS->stlen) 2728 return TERMNEAREND; 2729 } 2730 2731 return REC_OK; 2732} 2733 2734/* <rsnullscan>= */ 2735/* rsnullscan --- handle RS = "" */ 2736 2737static RECVALUE 2738rsnullscan(IOBUF *iop, struct recmatch *recm, SCANSTATE *state) 2739{ 2740 register char *bp; 2741 2742 if (*state == NOSTATE || *state == INLEADER) 2743 memset(recm, '\0', sizeof(struct recmatch)); 2744 2745 recm->start = iop->off; 2746 2747 bp = iop->off; 2748 if (*state != NOSTATE) 2749 bp += iop->scanoff; 2750 2751 /* set sentinel */ 2752 *(iop->dataend) = '\n'; 2753 2754 if (*state == INTERM) 2755 goto find_longest_terminator; 2756 else if (*state == INDATA) 2757 goto scan_data; 2758 /* else 2759 fall into things from beginning, 2760 either NOSTATE or INLEADER */ 2761 2762/* skip_leading: */ 2763 /* leading newlines are ignored */ 2764 while (*bp == '\n' && bp < iop->dataend) 2765 bp++; 2766 2767 if (bp >= iop->dataend) { /* LOTS of leading newlines, sheesh. */ 2768 *state = INLEADER; 2769 iop->scanoff = bp - iop->off; 2770 return NOTERM; 2771 } 2772 2773 iop->off = recm->start = bp; /* real start of record */ 2774scan_data: 2775 while (*bp++ != '\n') 2776 continue; 2777 2778 if (bp >= iop->dataend) { /* no terminator */ 2779 iop->scanoff = recm->len = bp - iop->off - 1; 2780 *state = INDATA; 2781 return NOTERM; 2782 } 2783 2784 /* found one newline before end of buffer, check next char */ 2785 if (*bp != '\n') 2786 goto scan_data; 2787 2788 /* we've now seen at least two newlines */ 2789 *state = INTERM; 2790 recm->len = bp - iop->off - 1; 2791 recm->rt_start = bp - 1; 2792 2793find_longest_terminator: 2794 /* find as many newlines as we can, to set RT */ 2795 while (*bp == '\n' && bp < iop->dataend) 2796 bp++; 2797 2798 recm->rt_len = bp - recm->rt_start; 2799 iop->scanoff = bp - iop->off; 2800 2801 if (bp >= iop->dataend) 2802 return TERMATEND; 2803 2804 return REC_OK; 2805} 2806 2807/* <getarecord>= */ 2808/* get_a_record --- read a record from IOP into out, return length of EOF, set RT */ 2809 2810int 2811get_a_record(char **out, /* pointer to pointer to data */ 2812 IOBUF *iop, /* input IOP */ 2813 int *errcode) /* pointer to error variable */ 2814{ 2815 struct recmatch recm; 2816 SCANSTATE state; 2817 RECVALUE ret; 2818 int retval; 2819 NODE *rtval = NULL; 2820 static RECVALUE (*lastmatchrec)P((IOBUF *iop, struct recmatch *recm, SCANSTATE *state)) = NULL; 2821 2822 if (at_eof(iop) && no_data_left(iop)) 2823 return EOF; 2824 2825 /* <fill initial buffer>= */ 2826 if (has_no_data(iop) || no_data_left(iop)) { 2827 iop->count = read(iop->fd, iop->buf, iop->readsize); 2828 if (iop->count == 0) { 2829 iop->flag |= IOP_AT_EOF; 2830 return EOF; 2831 } else if (iop->count == -1) { 2832 if (! do_traditional && errcode != NULL) { 2833 *errcode = errno; 2834 iop->flag |= IOP_AT_EOF; 2835 return EOF; 2836 } else 2837 fatal(_("error reading input file `%s': %s"), 2838 iop->name, strerror(errno)); 2839 } else { 2840 iop->dataend = iop->buf + iop->count; 2841 iop->off = iop->buf; 2842 } 2843 } 2844 2845 2846 2847 /* <loop through file to find a record>= */ 2848 state = NOSTATE; 2849 for (;;) { 2850 size_t dataend_off; 2851 2852 ret = (*matchrec)(iop, & recm, & state); 2853 2854 if (ret == REC_OK) 2855 break; 2856 2857 /* need to add more data to buffer */ 2858 /* <shift data down in buffer>= */ 2859 dataend_off = iop->dataend - iop->off; 2860 memmove(iop->buf, iop->off, dataend_off); 2861 iop->off = iop->buf; 2862 iop->dataend = iop->buf + dataend_off; 2863 2864 /* <adjust recm contents>= */ 2865 recm.start = iop->off; 2866 if (recm.rt_start != NULL) 2867 recm.rt_start = iop->off + recm.len; 2868 2869 /* <read more data, break if EOF>= */ 2870 if ((iop->flag & IOP_IS_INTERNAL) != 0) { 2871 iop->flag |= IOP_AT_EOF; 2872 break; 2873 } else { 2874#define min(x, y) (x < y ? x : y) 2875 /* subtract one in read count to leave room for sentinel */ 2876 size_t room_left = iop->end - iop->dataend - 1; 2877 size_t amt_to_read = min(iop->readsize, room_left); 2878 2879 if (amt_to_read < iop->readsize) { 2880 grow_iop_buffer(iop); 2881 /* <adjust recm contents>= */ 2882 recm.start = iop->off; 2883 if (recm.rt_start != NULL) 2884 recm.rt_start = iop->off + recm.len; 2885 2886 /* recalculate amt_to_read */ 2887 room_left = iop->end - iop->dataend - 1; 2888 amt_to_read = min(iop->readsize, room_left); 2889 } 2890 while (amt_to_read + iop->readsize < room_left) 2891 amt_to_read += iop->readsize; 2892 2893 iop->count = read(iop->fd, iop->dataend, amt_to_read); 2894 if (iop->count == -1) { 2895 if (! do_traditional && errcode != NULL) { 2896 *errcode = errno; 2897 iop->flag |= IOP_AT_EOF; 2898 break; 2899 } else 2900 fatal(_("error reading input file `%s': %s"), 2901 iop->name, strerror(errno)); 2902 } else if (iop->count == 0) { 2903 /* 2904 * hit EOF before matching RS, so end 2905 * the record and set RT to "" 2906 */ 2907 iop->flag |= IOP_AT_EOF; 2908 break; 2909 } else 2910 iop->dataend += iop->count; 2911 } 2912 2913 2914 } 2915 2916 2917 2918 /* <set record, RT, return right value>= */ 2919 2920 /* 2921 * rtval is not a static pointer to avoid dangling pointer problems 2922 * in case awk code assigns to RT. A remote possibility, to be sure, 2923 * but Bitter Experience teaches us not to make ``that'll never 2924 * happen'' kinds of assumptions. 2925 */ 2926 rtval = RT_node->var_value; 2927 2928 if (recm.rt_len == 0) { 2929 set_RT_to_null(); 2930 lastmatchrec = NULL; 2931 } else { 2932 assert(recm.rt_start != NULL); 2933 /* 2934 * Optimization. For rs1 case, don't set RT if 2935 * character is same as last time. This knocks a 2936 * chunk of time off something simple like 2937 * 2938 * gawk '{ print }' /some/big/file 2939 * 2940 * Similarly, for rsnull case, if length of new RT is 2941 * shorter than current RT, just bump length down in RT. 2942 * 2943 * Make sure that matchrec didn't change since the last 2944 * check. (Ugh, details, details, details.) 2945 */ 2946 if (lastmatchrec == NULL || lastmatchrec != matchrec) { 2947 lastmatchrec = matchrec; 2948 set_RT(recm.rt_start, recm.rt_len); 2949 } else if (matchrec == rs1scan) { 2950 if (rtval->stlen != 1 || rtval->stptr[0] != recm.rt_start[0]) 2951 set_RT(recm.rt_start, recm.rt_len); 2952 /* else 2953 leave it alone */ 2954 } else if (matchrec == rsnullscan) { 2955 if (rtval->stlen <= recm.rt_len) 2956 rtval->stlen = recm.rt_len; 2957 else 2958 set_RT(recm.rt_start, recm.rt_len); 2959 } else 2960 set_RT(recm.rt_start, recm.rt_len); 2961 } 2962 2963 if (recm.len == 0) { 2964 *out = NULL; 2965 retval = 0; 2966 } else { 2967 assert(recm.start != NULL); 2968 *out = recm.start; 2969 retval = recm.len; 2970 } 2971 2972 iop->off += recm.len + recm.rt_len; 2973 2974 if (recm.len == 0 && recm.rt_len == 0 && at_eof(iop)) 2975 return EOF; 2976 else 2977 return retval; 2978 2979} 2980 2981/* set_RS --- update things as appropriate when RS is set */ 2982 2983void 2984set_RS() 2985{ 2986 static NODE *save_rs = NULL; 2987 2988 /* 2989 * Don't use cmp_nodes(), which pays attention to IGNORECASE. 2990 */ 2991 if (save_rs 2992 && RS_node->var_value->stlen == save_rs->stlen 2993 && STREQN(RS_node->var_value->stptr, save_rs->stptr, save_rs->stlen)) { 2994 /* 2995 * It could be that just IGNORECASE changed. If so, 2996 * update the regex and then do the same for FS. 2997 * set_IGNORECASE() relies on this routine to call 2998 * set_FS(). 2999 */ 3000 RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case); 3001 goto set_FS; 3002 } 3003 unref(save_rs); 3004 save_rs = dupnode(RS_node->var_value); 3005 RS_is_null = FALSE; 3006 RS = force_string(RS_node->var_value); 3007 if (RS_regexp != NULL) { 3008 refree(RS_re_yes_case); 3009 refree(RS_re_no_case); 3010 RS_re_yes_case = RS_re_no_case = RS_regexp = NULL; 3011 } 3012 if (RS->stlen == 0) { 3013 RS_is_null = TRUE; 3014 matchrec = rsnullscan; 3015 } else if (RS->stlen > 1) { 3016 static int warned = FALSE; 3017 3018 RS_re_yes_case = make_regexp(RS->stptr, RS->stlen, FALSE); 3019 RS_re_no_case = make_regexp(RS->stptr, RS->stlen, TRUE); 3020 RS_regexp = (IGNORECASE ? RS_re_no_case : RS_re_yes_case); 3021 3022 matchrec = rsrescan; 3023 3024 if (do_lint && ! warned) { 3025 lintwarn(_("multicharacter value of `RS' is a gawk extension")); 3026 warned = TRUE; 3027 } 3028 } else 3029 matchrec = rs1scan; 3030set_FS: 3031 if (! using_fieldwidths()) 3032 set_FS(); 3033} 3034 3035/* pty_vs_pipe --- return true if should use pty instead of pipes for `|&' */ 3036 3037/* 3038 * This works by checking if PROCINFO["command", "pty"] exists and is true. 3039 */ 3040 3041static int 3042pty_vs_pipe(const char *command) 3043{ 3044#ifdef HAVE_TERMIOS_H 3045 char *full_index; 3046 size_t full_len; 3047 NODE *val; 3048 NODE *sub; 3049 3050 if (PROCINFO_node == NULL) 3051 return FALSE; 3052 3053 full_len = strlen(command) 3054 + SUBSEP_node->var_value->stlen 3055 + 3 /* strlen("pty") */ 3056 + 1; /* string terminator */ 3057 emalloc(full_index, char *, full_len, "pty_vs_pipe"); 3058 sprintf(full_index, "%s%.*spty", command, 3059 (int) SUBSEP_node->var_value->stlen, SUBSEP_node->var_value->stptr); 3060 3061 sub = tmp_string(full_index, strlen(full_index)); 3062 val = in_array(PROCINFO_node, sub); 3063 free_temp(sub); 3064 free(full_index); 3065 3066 if (val) { 3067 if (val->flags & MAYBE_NUM) 3068 (void) force_number(val); 3069 if (val->flags & NUMBER) 3070 return (val->numbr != 0.0); 3071 else 3072 return (val->stlen != 0); 3073 } 3074#endif /* HAVE_TERMIOS_H */ 3075 return FALSE; 3076} 3077 3078/* iopflags2str --- make IOP flags printable */ 3079 3080const char * 3081iopflags2str(int flag) 3082{ 3083 static const struct flagtab values[] = { 3084 { IOP_IS_TTY, "IOP_IS_TTY" }, 3085 { IOP_IS_INTERNAL, "IOP_IS_INTERNAL" }, 3086 { IOP_NO_FREE, "IOP_NO_FREE" }, 3087 { IOP_NOFREE_OBJ, "IOP_NOFREE_OBJ" }, 3088 { IOP_AT_EOF, "IOP_AT_EOF" }, 3089 { 0, NULL } 3090 }; 3091 3092 return genflags2str(flag, values); 3093} 3094