new copyright; att/bsd/shared
[unix-history] / usr / src / lib / libc / stdio / freopen.c
CommitLineData
411867e7
KB
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * %sccs.include.redist.c%
586c39b1
DF
9 */
10
2ce81398 11#if defined(LIBC_SCCS) && !defined(lint)
cb631443 12static char sccsid[] = "@(#)freopen.c 5.6 (Berkeley) %G%";
411867e7 13#endif /* LIBC_SCCS and not lint */
586c39b1 14
41e01b3e 15#include <sys/types.h>
411867e7 16#include <sys/stat.h>
cb631443 17#include <fcntl.h>
411867e7 18#include <errno.h>
cb631443 19#include <unistd.h>
41e01b3e 20#include <stdio.h>
411867e7
KB
21#include <stdlib.h>
22#include "local.h"
2de31004 23
411867e7
KB
24/*
25 * Re-direct an existing, open (probably) file to some other file.
26 * ANSI is written such that the original file gets closed if at
27 * all possible, no matter what.
28 */
2de31004 29FILE *
411867e7 30freopen(file, mode, fp)
d25ccb19 31 const char *file, *mode;
411867e7 32 register FILE *fp;
2de31004 33{
411867e7
KB
34 register int f;
35 int flags, isopen, oflags, sverrno, wantfd;
36
37 if ((flags = __sflags(mode, &oflags)) == 0) {
38 (void) fclose(fp);
41e01b3e
S
39 return (NULL);
40 }
41
411867e7
KB
42 if (!__sdidinit)
43 __sinit();
44
45 /*
46 * There are actually programs that depend on being able to "freopen"
47 * descriptors that weren't originally open. Keep this from breaking.
48 * Remember whether the stream was open to begin with, and which file
49 * descriptor (if any) was associated with it. If it was attached to
50 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
51 * should work. This is unnecessary if it was not a Unix file.
52 */
53 if (fp->_flags == 0) {
54 fp->_flags = __SEOF; /* hold on to it */
55 isopen = 0;
56 wantfd = -1;
57 } else {
58 /* flush the stream; ANSI doesn't require this. */
59 if (fp->_flags & __SWR)
1dcadafa 60 (void) __sflush(fp);
411867e7
KB
61 /* if close is NULL, closing is a no-op, hence pointless */
62 isopen = fp->_close != NULL;
63 if ((wantfd = fp->_file) < 0 && isopen) {
64 (void) (*fp->_close)(fp->_cookie);
65 isopen = 0;
66 }
67 }
68
69 /* Get a new descriptor to refer to the new file. */
70 f = open(file, oflags, DEFFILEMODE);
71 if (f < 0 && isopen) {
72 /* If out of fd's close the old one and try again. */
73 if (errno == ENFILE || errno == EMFILE) {
74 (void) (*fp->_close)(fp->_cookie);
75 isopen = 0;
76 f = open(file, oflags, DEFFILEMODE);
77 }
78 }
79 sverrno = errno;
80
81 /*
82 * Finish closing fp. Even if the open succeeded above, we cannot
83 * keep fp->_base: it may be the wrong size. This loses the effect
84 * of any setbuffer calls, but stdio has always done this before.
85 */
86 if (isopen)
87 (void) (*fp->_close)(fp->_cookie);
88 if (fp->_flags & __SMBF)
89 free((char *)fp->_bf._base);
90 fp->_w = 0;
91 fp->_r = 0;
92 fp->_p = NULL;
93 fp->_bf._base = NULL;
94 fp->_bf._size = 0;
95 fp->_lbfsize = 0;
96 if (HASUB(fp))
97 FREEUB(fp);
98 fp->_ub._size = 0;
99 if (HASLB(fp))
100 FREELB(fp);
101 fp->_lb._size = 0;
102
103 if (f < 0) { /* did not get it after all */
104 fp->_flags = 0; /* set it free */
105 errno = sverrno; /* restore in case _close clobbered */
41e01b3e 106 return (NULL);
411867e7
KB
107 }
108
109 /*
110 * If reopening something that was open before on a real file, try
111 * to maintain the descriptor. Various C library routines (perror)
112 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
113 */
114 if (wantfd >= 0 && f != wantfd) {
115 if (dup2(f, wantfd) >= 0) {
116 (void) close(f);
117 f = wantfd;
118 }
119 }
41e01b3e 120
411867e7
KB
121 fp->_flags = flags;
122 fp->_file = f;
123 fp->_cookie = fp;
124 fp->_read = __sread;
125 fp->_write = __swrite;
126 fp->_seek = __sseek;
127 fp->_close = __sclose;
128 return (fp);
2de31004 129}