2 /********************************************
4 copyright 1991-94. Michael D. Brennan
6 This is a source file for mawk, an implementation of
7 the AWK programming language.
9 Mawk is distributed without warranty under the terms of
10 the GNU General Public License, version 2, 1991.
11 ********************************************/
14 * Revision 1.9 1996/01/14 17:14:10 mike
17 * Revision 1.8 1995/06/06 00:18:27 mike
18 * change mawk_exit(1) to mawk_exit(2)
20 * Revision 1.7 1994/12/11 20:48:50 mike
23 * Revision 1.6 1994/10/08 19:15:40 mike
26 * Revision 1.5 1994/04/17 20:01:37 mike
27 * recognize filename "/dev/stdout"
29 * Revision 1.4 1994/02/21 00:11:07 mike
32 * Revision 1.3 1993/07/16 01:00:36 mike
35 * Revision 5.5 1992/12/17 02:48:01 mike
36 * 1.1.2d changes for DOS
38 * Revision 5.4 1992/07/10 16:10:30 brennan
40 * MsDOS: remove useless NO_BINMODE macro
41 * get process exit code on in pipes
43 * Revision 5.3 1992/04/07 20:21:17 brennan
45 * unbuffered output to a tty
47 * Revision 5.2 1992/04/07 16:03:08 brennan
49 * allow same filename for output and input, but use different descriptors
50 * E.g. < "/dev/tty" and > "/dev/tty"
52 * Revision 5.1 91/12/05 07:56:00 brennan
64 #include <sys/types.h>
69 #include <sgtty.h> /* defines FIOCLEX */
75 #define CLOSE_ON_EXEC(fd) fcntl(fd, F_SETFD, 1)
78 #define CLOSE_ON_EXEC(fd) ioctl(fd, FIOCLEX, (PTR) 0)
82 /* We store dynamically created files on a linked linear
83 list with move to the front (big surprise) */
90 int pid ; /* we need to wait() when we close a pipe */
91 /* holds temp file index under MSDOS */
97 PTR ptr ; /* FIN* or FILE* */
101 static FILE_NODE *file_list ;
103 /* Prototypes for local functions */
105 static FILE *PROTO(tfopen, (char *, char *)) ;
106 static void PROTO(efflush, (FILE*)) ;
107 static void PROTO(add_to_child_list, (int, int)) ;
108 static struct child *PROTO(remove_from_child_list, (int)) ;
109 extern int PROTO(isatty, (int)) ;
110 static void PROTO(close_error, (FILE_NODE *p));
112 /* find a file on file_list */
114 file_find(sval, type)
118 register FILE_NODE *p = file_list ;
119 FILE_NODE *q = (FILE_NODE *) 0 ;
120 char *name = sval->str ;
128 p = ZMALLOC(FILE_NODE) ;
130 switch (p->type = type)
134 ostr = (binmode() & 2) ? "wb" : "w" ;
138 if (!(p->ptr = (PTR) tfopen(name, ostr)))
144 ostr = (binmode() & 2) ? "ab" : "a" ;
148 if (!(p->ptr = (PTR) tfopen(name, ostr)))
153 if (!(p->ptr = (PTR) FINopen(name, 0)))
155 zfree(p, sizeof(FILE_NODE)) ;
163 #if HAVE_REAL_PIPES || HAVE_FAKE_PIPES
165 if (!(p->ptr = get_pipe(name, type, &p->pid)))
167 if (type == PIPE_OUT) goto out_failure ;
170 zfree(p, sizeof(FILE_NODE)) ;
175 rt_error("pipes not supported") ;
181 bozo("bad file type") ;
184 /* successful open */
187 break ; /* while loop */
190 /* search is by name and type */
191 if (strcmp(name, p->name->str) == 0 &&
193 /* no distinction between F_APPEND and F_TRUNC here */
194 (p->type >= F_APPEND && type >= F_APPEND)))
198 if (!q) /*at front of list */
200 /* delete from list for move to front */
202 break ; /* while loop */
205 q = p ; p = p->link ;
206 } /* end while loop */
208 /* put p at the front of the list */
209 p->link = file_list ;
210 return (PTR) (file_list = p)->ptr ;
213 errmsg(errno, "cannot open \"%s\" for output", name) ;
219 /* Close a file and delete it's node from the file_list.
220 Walk the whole list, in case a name has two nodes,
221 e.g. < "/dev/tty" and > "/dev/tty"
229 register FILE_NODE *p ;
230 FILE_NODE *q = &dummy ; /* trails p */
232 char *name = sval->str ;
235 dummy.link = p = file_list ;
238 if (strcmp(name, p->name->str) == 0)
242 /* Remove it from the list first because we might be called
243 again if an error occurs leading to an infinite loop.
245 Note that we don't have to consider the list corruption
246 caused by a recursive call because it will never return. */
249 file_list = dummy.link ; /* maybe it was the first file */
255 if( fclose((FILE *) p->ptr) != 0 )
261 if( fclose((FILE *) p->ptr) != 0 )
265 retval = wait_for(p->pid) ;
268 retval = close_fake_outpipe(p->name->str, p->pid) ;
273 FINclose((FIN *) p->ptr) ;
278 FINclose((FIN *) p->ptr) ;
281 retval = wait_for(p->pid) ;
286 unlink(tmp_file_name(p->pid, xbuff)) ;
287 retval = p->inpipe_exit ;
293 free_STRING(p->name) ;
300 q = p ; p = p->link ;
308 find an output file with name == sval and fflush it
316 register FILE_NODE *p = file_list ;
317 unsigned len = sval->len ;
318 char *str = sval->str ;
322 /* for consistency with gawk */
329 if ( IS_OUTPUT(p->type) &&
330 len == p->name->len &&
331 strcmp(str,p->name->str) == 0 )
334 efflush((FILE*)p->ptr) ;
335 /* it's possible for a command and a file to have the same
336 name -- so keep looking */
348 for(p=file_list; p ; p = p->link)
349 if (IS_OUTPUT(p->type)) efflush((FILE*)p->ptr) ;
358 errmsg(errno, "unexpected write error") ;
364 /* When we exit, we need to close and wait for all output pipes */
368 /* work around for bug in AIX 4.1 -- If there are exactly 16 or
369 32 or 48 ..., open files then the last one doesn't get flushed on
370 exit. So the following is now a misnomer as we'll really close
377 register FILE_NODE *p = file_list ;
381 if (IS_OUTPUT(p->type))
383 if( fclose((FILE *) p->ptr) != 0 )
385 /* if another error occurs we do not want to be called
386 for the same file again */
388 file_list = p->link ;
391 if (p->type == PIPE_OUT) wait_for(p->pid) ;
399 #if HAVE_FAKE_PIPES /* pipes are faked with temp files */
404 register FILE_NODE *p = file_list ;
407 /* close input pipes first to free descriptors for children */
410 if (p->type == PIPE_IN)
412 FINclose((FIN *) p->ptr) ;
413 unlink(tmp_file_name(p->pid, xbuff)) ;
421 if (p->type == PIPE_OUT)
423 if( fclose(p->ptr) != 0 )
425 close_fake_outpipe(p->name->str, p->pid) ;
430 #endif /* HAVE_FAKE_PIPES */
431 #endif /* ! HAVE_REAL_PIPES */
433 /* hardwire to /bin/sh for portability of programs */
434 char *shell = "/bin/sh" ;
439 get_pipe(name, type, pid_ptr)
444 int the_pipe[2], local_fd, remote_fd ;
446 if (pipe(the_pipe) == -1) return (PTR) 0 ;
447 local_fd = the_pipe[type == PIPE_OUT] ;
448 remote_fd = the_pipe[type == PIPE_IN] ;
449 /* to keep output ordered correctly */
450 fflush(stdout) ; fflush(stderr) ;
452 switch (*pid_ptr = fork())
461 close(type == PIPE_IN) ;
464 execl(shell, shell, "-c", name, (char *) 0) ;
465 errmsg(errno, "failed to exec %s -c %s", shell, name) ;
471 /* we could deadlock if future child inherit the local fd ,
472 set close on exec flag */
473 CLOSE_ON_EXEC(local_fd) ;
477 return type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) :
478 (PTR) fdopen(local_fd, "w") ;
483 /*------------ children ------------------*/
485 /* we need to wait for children at the end of output pipes to
486 complete so we know any files they have created are complete */
488 /* dead children are kept on this list */
498 add_to_child_list(pid, exit_status)
499 int pid, exit_status ;
501 register struct child *p = ZMALLOC(struct child) ;
503 p->pid = pid ; p->exit_status = exit_status ;
504 p->link = child_list ; child_list = p ;
507 static struct child *
508 remove_from_child_list(pid)
512 register struct child *p ;
513 struct child *q = &dummy ;
515 dummy.link = p = child_list ;
525 q = p ; p = p->link ;
529 child_list = dummy.link ;
531 /* null return if not in the list */
535 /* wait for a specific child to complete and return its
538 If pid is zero, wait for any single child and
539 put it on the dead children list
552 id = wait(&exit_status) ;
553 add_to_child_list(id, exit_status) ;
555 /* see if an earlier wait() caught our child */
556 else if ((p = remove_from_child_list(pid)))
558 exit_status = p->exit_status ;
563 /* need to really wait */
564 while ((id = wait(&exit_status)) != pid)
566 if (id == -1) /* can't happen */
570 /* we got the exit status of another child
571 put it on the child list and try again */
572 add_to_child_list(id, exit_status) ;
577 if (exit_status & 0xff) exit_status = 128 + (exit_status & 0xff) ;
578 else exit_status = (exit_status & 0xff00) >> 8 ;
583 #endif /* HAVE_REAL_PIPES */
587 set_stderr() /* and stdout */
591 /* We insert stderr first to get it at the end of the list. This is
592 needed because we want to output errors encountered on closing
595 q = ZMALLOC(FILE_NODE);
596 q->link = (FILE_NODE*) 0 ;
598 q->name = new_STRING("/dev/stderr") ;
599 q->ptr = (PTR) stderr ;
601 p = ZMALLOC(FILE_NODE) ;
604 p->name = new_STRING("/dev/stdout") ;
605 p->ptr = (PTR) stdout ;
610 /* fopen() but no buffering to ttys */
615 FILE *retval = fopen(name, mode) ;
619 if (isatty(fileno(retval))) setbuf(retval, (char *) 0) ;
623 enlarge_output_buffer(retval) ;
632 enlarge_output_buffer(fp)
635 if (setvbuf(fp, (char *) 0, _IOFBF, BUFFSZ) < 0)
637 errmsg(errno, "setvbuf failed on fileno %d", fileno(fp)) ;
645 if (!isatty(1)) enlarge_output_buffer(stdout) ;
648 setmode(1,O_BINARY) ; setmode(2,O_BINARY) ;
653 /* An error occured closing the file referred to by P. We tell the
654 user and terminate the program. */
656 static void close_error(p)
659 errmsg(errno, "close failed on file %s", p->name->str) ;