/********************************************
copyright 1991, Michael D. Brennan
This is a source file for mawk, an implementation of
the AWK programming language.
Mawk is distributed without warranty under the terms of
the GNU General Public License, version 2, 1991.
********************************************/
* Revision 5.1 91/12/05 07:56:00 brennan
#include <sgtty.h> /* defines FIOCLEX */
#define CLOSE_ON_EXEC(fd) (void) fcntl(fd, F_SETFD, 1)
#define CLOSE_ON_EXEC(fd) ioctl(fd, FIOCLEX, (PTR) 0)
/* We store dynamically created files on a linked linear
list with move to the front (big surprise) */
int pid
; /* we need to wait() when we close an out pipe */
/* holds temp file index under MSDOS */
PTR ptr
; /* FIN* or FILE* */
static FILE_NODE
*file_list
;
file_list
= ZMALLOC(FILE_NODE
) ;
file_list
->link
= (FILE_NODE
*) 0 ;
file_list
->type
= F_TRUNC
;
file_list
->name
= new_STRING("/dev/stderr") ;
file_list
->ptr
= (PTR
) stderr
;
PTR
file_find( sval
, type
)
{ register FILE_NODE
*p
= file_list
;
FILE_NODE
*q
= (FILE_NODE
*) 0 ;
if ( !p
) /* open a new one */
p
= (FILE_NODE
*) zmalloc(sizeof(FILE_NODE
)) ;
#if MSDOS && NO_BINMODE==0
ostr
= (binmode()&2) ? "wb" : "w" ;
if ( !(p
->ptr
= (PTR
) fopen(name
, ostr
)) )
#if MSDOS && NO_BINMODE==0
ostr
= (binmode()&2) ? "ab" : "a" ;
if ( !(p
->ptr
= (PTR
) fopen(name
, ostr
)) )
if ( !(p
->ptr
= (PTR
) FINopen(name
, 0)) )
{ zfree(p
, sizeof(FILE_NODE
)) ; return (PTR
) 0 ; }
#if HAVE_REAL_PIPES || HAVE_FAKE_PIPES
if ( !(p
->ptr
= get_pipe(name
, type
, &p
->pid
)) )
if ( type
== PIPE_OUT
) goto out_failure
;
{ zfree(p
, sizeof(FILE_NODE
) ) ;
rt_error("pipes not supported") ;
if ( strcmp(name
, p
->name
->str
) == 0 )
{ /* no distinction between F_APPEND and F_TRUNC here */
(p
->type
< F_APPEND
|| type
< F_APPEND
)) goto type_failure
;
if ( !q
) /*at front of list */
/* delete from list for move to front */
/* put p at the front of the list */
return (PTR
) (file_list
= p
)->ptr
;
errmsg(errno
, "cannot open \"%s\" for output", name
) ;
rt_error("use of file \"%s\"\n\tis inconsistent with previous use",
/* close a file and delete it's node from the file_list */
{ register FILE_NODE
*p
= file_list
;
FILE_NODE
*q
= (FILE_NODE
*) 0 ; /* trails p */
if ( strcmp(name
,p
->name
->str
) == 0 ) /* found */
(void) fclose((FILE *) p
->ptr
) ;
(void) fclose((FILE *) p
->ptr
) ;
retval
= wait_for(p
->pid
) ;
retval
= close_fake_outpipe(p
->name
->str
,p
->pid
) ;
FINclose((FIN
*) p
->ptr
) ;
FINclose((FIN
*) p
->ptr
) ;
retval
= wait_for(p
->pid
) ;
(void) unlink(tmp_file_name(p
->pid
)) ;
if ( q
) q
->link
= p
->link
;
else file_list
= p
->link
;
zfree(p
, sizeof(FILE_NODE
)) ;
else { q
= p
; p
= p
->link
; }
/* its not on the list */
/* When we exit, we need to close and wait for all output pipes */
{ register FILE_NODE
*p
= file_list
;
{ if ( p
->type
== PIPE_OUT
)
{ (void) fclose((FILE *) p
->ptr
) ; (void) wait_for(p
->pid
) ; }
#if HAVE_FAKE_PIPES /* pipes are faked with temp files */
{ register FILE_NODE
*p
= file_list
;
/* close input pipes first to free descriptors for children */
if ( p
->type
== PIPE_IN
)
{ FINclose((FIN
*) p
->ptr
) ;
(void) unlink(tmp_file_name(p
->pid
)) ;
if ( p
->type
== PIPE_OUT
)
(void) close_fake_outpipe(p
->name
->str
,p
->pid
) ;
/* hardwire to /bin/sh for portability of programs */
char *shell
= "/bin/sh" ;
PTR
get_pipe( name
, type
, pid_ptr
)
{ int the_pipe
[2], local_fd
, remote_fd
;
if ( pipe(the_pipe
) == -1 ) return (PTR
) 0 ;
local_fd
= the_pipe
[type
== PIPE_OUT
] ;
remote_fd
= the_pipe
[type
== PIPE_IN
] ;
/* to keep output ordered correctly */
fflush(stdout
) ; fflush(stderr
) ;
switch( *pid_ptr
= fork() )
(void) close(remote_fd
) ;
(void) close(type
== PIPE_IN
) ;
(void) dup( remote_fd
) ;
(void) close( remote_fd
) ;
(void) execl(shell
, shell
, "-c", name
, (char *) 0 ) ;
errmsg(errno
, "failed to exec %s -c %s" , shell
, name
) ;
(void) close(remote_fd
) ;
/* we could deadlock if future child inherit the local fd ,
set close on exec flag */
CLOSE_ON_EXEC(local_fd
) ;
return type
== PIPE_IN
? (PTR
) FINdopen(local_fd
, 0) :
(PTR
) fdopen(local_fd
, "w") ;
/*------------ children ------------------*/
/* we need to wait for children at the end of output pipes to
complete so we know any files they have created are complete */
/* dead children are kept on this list */
static void add_to_child_list(pid
, exit_status
)
{ register struct child
*p
=
(struct child
*) zmalloc(sizeof(struct child
)) ;
p
->pid
= pid
; p
->exit_status
= exit_status
;
p
->link
= child_list
; child_list
= p
;
static struct child
*remove_from_child_list(pid
)
{ register struct child
*p
= child_list
;
struct child
*q
= (struct child
*) 0 ;
if ( q
) q
->link
= p
->link
;
else child_list
= p
->link
;
else { q
= p
; p
= p
->link
; }
return p
; /* null return if not in the list */
/* wait for a specific child to complete and return its
If pid is zero, wait for any single child
id
= wait(&exit_status
) ;
add_to_child_list(id
, exit_status
) ;
/* see if an earlier wait() caught our child */
if ( p
= remove_from_child_list(pid
) )
{ exit_status
= p
->exit_status
;
else /* need to really wait */
while ( (id
= wait(&exit_status
)) != pid
)
if ( id
== -1 ) /* can't happen */ bozo("wait_for") ;
{ /* we got the exit status of another child
put it on the child list and try again */
add_to_child_list(id
, exit_status
) ;
if ( exit_status
& 0xff )
exit_status
= 128 + (exit_status
& 0xff) ;
else exit_status
= (exit_status
& 0xff00)>>8 ;
#endif /* HAVE_REAL_PIPES */