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
static FILE *PROTO(tfopen, (char *, char *)) ;
65
static void PROTO(efflush, (FILE*)) ;
66
static void PROTO(add_to_child_list, (int, int)) ;
67
static struct child *PROTO(remove_from_child_list, (int)) ;
68
extern int PROTO(isatty, (int)) ;
71
#include <sgtty.h> /* defines FIOCLEX */
78
#define CLOSE_ON_EXEC(fd) fcntl(fd, F_SETFD, 1)
81
#define CLOSE_ON_EXEC(fd) ioctl(fd, FIOCLEX, (PTR) 0)
85
/* We store dynamically created files on a linked linear
86
list with move to the front (big surprise) */
93
int pid ; /* we need to wait() when we close a pipe */
94
/* holds temp file index under MSDOS */
100
PTR ptr ; /* FIN* or FILE* */
104
static FILE_NODE *file_list ;
107
/* find a file on file_list */
109
file_find(sval, type)
113
register FILE_NODE *p = file_list ;
114
FILE_NODE *q = (FILE_NODE *) 0 ;
115
char *name = sval->str ;
123
p = ZMALLOC(FILE_NODE) ;
125
switch (p->type = type)
129
ostr = (binmode() & 2) ? "wb" : "w" ;
133
if (!(p->ptr = (PTR) tfopen(name, ostr)))
139
ostr = (binmode() & 2) ? "ab" : "a" ;
143
if (!(p->ptr = (PTR) tfopen(name, ostr)))
148
if (!(p->ptr = (PTR) FINopen(name, 0)))
150
zfree(p, sizeof(FILE_NODE)) ;
158
#if HAVE_REAL_PIPES || HAVE_FAKE_PIPES
160
if (!(p->ptr = get_pipe(name, type, &p->pid)))
162
if (type == PIPE_OUT) goto out_failure ;
165
zfree(p, sizeof(FILE_NODE)) ;
170
rt_error("pipes not supported") ;
176
bozo("bad file type") ;
179
/* successful open */
182
break ; /* while loop */
185
/* search is by name and type */
186
if (strcmp(name, p->name->str) == 0 &&
188
/* no distinction between F_APPEND and F_TRUNC here */
189
p->type >= F_APPEND && type >= F_APPEND))
193
if (!q) /*at front of list */
195
/* delete from list for move to front */
197
break ; /* while loop */
200
q = p ; p = p->link ;
201
} /* end while loop */
203
/* put p at the front of the list */
204
p->link = file_list ;
205
return (PTR) (file_list = p)->ptr ;
208
errmsg(errno, "cannot open \"%s\" for output", name) ;
214
/* Close a file and delete it's node from the file_list.
215
Walk the whole list, in case a name has two nodes,
216
e.g. < "/dev/tty" and > "/dev/tty"
224
register FILE_NODE *p ;
225
FILE_NODE *q = &dummy ; /* trails p */
227
char *name = sval->str ;
230
dummy.link = p = file_list ;
233
if (strcmp(name, p->name->str) == 0)
240
fclose((FILE *) p->ptr) ;
245
fclose((FILE *) p->ptr) ;
248
retval = wait_for(p->pid) ;
251
retval = close_fake_outpipe(p->name->str, p->pid) ;
256
FINclose((FIN *) p->ptr) ;
261
FINclose((FIN *) p->ptr) ;
264
retval = wait_for(p->pid) ;
269
unlink(tmp_file_name(p->pid, xbuff)) ;
270
retval = p->inpipe_exit ;
276
free_STRING(p->name) ;
278
q->link = p = p->link ;
283
q = p ; p = p->link ;
287
file_list = dummy.link ;
292
find an output file with name == sval and fflush it
300
register FILE_NODE *p = file_list ;
301
unsigned len = sval->len ;
302
char *str = sval->str ;
306
/* for consistency with gawk */
313
if ( IS_OUTPUT(p->type) &&
314
len == p->name->len &&
315
strcmp(str,p->name->str) == 0 )
318
efflush((FILE*)p->ptr) ;
319
/* it's possible for a command and a file to have the same
320
name -- so keep looking */
332
for(p=file_list; p ; p = p->link)
333
if (IS_OUTPUT(p->type)) efflush((FILE*)p->ptr) ;
342
errmsg(errno, "unexpected write error") ;
348
/* When we exit, we need to close and wait for all output pipes */
352
/* work around for bug in AIX 4.1 -- If there are exactly 16 or
353
32 or 48 ..., open files then the last one doesn't get flushed on
354
exit. So the following is now a misnomer as we'll really close
361
register FILE_NODE *p = file_list ;
365
if (IS_OUTPUT(p->type))
367
fclose((FILE *) p->ptr) ;
368
if (p->type == PIPE_OUT) wait_for(p->pid) ;
376
#if HAVE_FAKE_PIPES /* pipes are faked with temp files */
381
register FILE_NODE *p = file_list ;
384
/* close input pipes first to free descriptors for children */
387
if (p->type == PIPE_IN)
389
FINclose((FIN *) p->ptr) ;
390
unlink(tmp_file_name(p->pid, xbuff)) ;
398
if (p->type == PIPE_OUT)
401
close_fake_outpipe(p->name->str, p->pid) ;
406
#endif /* HAVE_FAKE_PIPES */
407
#endif /* ! HAVE_REAL_PIPES */
409
/* hardwire to /bin/sh for portability of programs */
410
char *shell = "/bin/sh" ;
415
get_pipe(name, type, pid_ptr)
420
int the_pipe[2], local_fd, remote_fd ;
422
if (pipe(the_pipe) == -1) return (PTR) 0 ;
423
local_fd = the_pipe[type == PIPE_OUT] ;
424
remote_fd = the_pipe[type == PIPE_IN] ;
425
/* to keep output ordered correctly */
426
fflush(stdout) ; fflush(stderr) ;
428
switch (*pid_ptr = fork())
437
close(type == PIPE_IN) ;
440
execl(shell, shell, "-c", name, (char *) 0) ;
441
errmsg(errno, "failed to exec %s -c %s", shell, name) ;
447
/* we could deadlock if future child inherit the local fd ,
448
set close on exec flag */
449
CLOSE_ON_EXEC(local_fd) ;
453
return type == PIPE_IN ? (PTR) FINdopen(local_fd, 0) :
454
(PTR) fdopen(local_fd, "w") ;
459
/*------------ children ------------------*/
461
/* we need to wait for children at the end of output pipes to
462
complete so we know any files they have created are complete */
464
/* dead children are kept on this list */
474
add_to_child_list(pid, exit_status)
475
int pid, exit_status ;
477
register struct child *p = ZMALLOC(struct child) ;
479
p->pid = pid ; p->exit_status = exit_status ;
480
p->link = child_list ; child_list = p ;
483
static struct child *
484
remove_from_child_list(pid)
488
register struct child *p ;
489
struct child *q = &dummy ;
491
dummy.link = p = child_list ;
501
q = p ; p = p->link ;
505
child_list = dummy.link ;
507
/* null return if not in the list */
511
/* wait for a specific child to complete and return its
514
If pid is zero, wait for any single child and
515
put it on the dead children list
528
id = wait(&exit_status) ;
529
add_to_child_list(id, exit_status) ;
531
/* see if an earlier wait() caught our child */
532
else if (p = remove_from_child_list(pid))
534
exit_status = p->exit_status ;
539
/* need to really wait */
540
while ((id = wait(&exit_status)) != pid)
542
if (id == -1) /* can't happen */
546
/* we got the exit status of another child
547
put it on the child list and try again */
548
add_to_child_list(id, exit_status) ;
553
if (exit_status & 0xff) exit_status = 128 + (exit_status & 0xff) ;
554
else exit_status = (exit_status & 0xff00) >> 8 ;
559
#endif /* HAVE_REAL_PIPES */
563
set_stderr() /* and stdout */
567
p = ZMALLOC(FILE_NODE) ;
568
p->link = (FILE_NODE*) 0 ;
570
p->name = new_STRING("/dev/stdout") ;
571
p->ptr = (PTR) stdout ;
572
q = ZMALLOC(FILE_NODE);
575
q->name = new_STRING("/dev/stderr") ;
576
q->ptr = (PTR) stderr ;
580
/* fopen() but no buffering to ttys */
585
FILE *retval = fopen(name, mode) ;
589
if (isatty(fileno(retval))) setbuf(retval, (char *) 0) ;
593
enlarge_output_buffer(retval) ;
602
enlarge_output_buffer(fp)
605
if (setvbuf(fp, (char *) 0, _IOFBF, BUFFSZ) < 0)
607
errmsg(errno, "setvbuf failed on fileno %d", fileno(fp)) ;
615
if (!isatty(1)) enlarge_output_buffer(stdout) ;
618
setmode(1,O_BINARY) ; setmode(2,O_BINARY) ;