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