146085Sbostic /*-
2*61180Sbostic * Copyright (c) 1990, 1993
3*61180Sbostic * The Regents of the University of California. All rights reserved.
446085Sbostic *
546085Sbostic * This code is derived from software contributed to Berkeley by
646085Sbostic * Chris Torek.
746085Sbostic *
846085Sbostic * %sccs.include.redist.c%
921407Sdist */
1021407Sdist
1126652Sdonn #if defined(LIBC_SCCS) && !defined(lint)
12*61180Sbostic static char sccsid[] = "@(#)freopen.c 8.1 (Berkeley) 06/04/93";
1346085Sbostic #endif /* LIBC_SCCS and not lint */
1421407Sdist
1517951Sserge #include <sys/types.h>
1646085Sbostic #include <sys/stat.h>
1746611Sbostic #include <fcntl.h>
1846085Sbostic #include <errno.h>
1946611Sbostic #include <unistd.h>
2017951Sserge #include <stdio.h>
2146085Sbostic #include <stdlib.h>
2246085Sbostic #include "local.h"
232008Swnj
2446085Sbostic /*
2546085Sbostic * Re-direct an existing, open (probably) file to some other file.
2646085Sbostic * ANSI is written such that the original file gets closed if at
2746085Sbostic * all possible, no matter what.
2846085Sbostic */
292008Swnj FILE *
freopen(file,mode,fp)3046085Sbostic freopen(file, mode, fp)
3146271Storek const char *file, *mode;
3246085Sbostic register FILE *fp;
332008Swnj {
3446085Sbostic register int f;
3546085Sbostic int flags, isopen, oflags, sverrno, wantfd;
362008Swnj
3746085Sbostic if ((flags = __sflags(mode, &oflags)) == 0) {
3846085Sbostic (void) fclose(fp);
3946085Sbostic return (NULL);
4046085Sbostic }
413163Stoy
4246085Sbostic if (!__sdidinit)
4346085Sbostic __sinit();
4417951Sserge
4546085Sbostic /*
4646085Sbostic * There are actually programs that depend on being able to "freopen"
4746085Sbostic * descriptors that weren't originally open. Keep this from breaking.
4846085Sbostic * Remember whether the stream was open to begin with, and which file
4946085Sbostic * descriptor (if any) was associated with it. If it was attached to
5046085Sbostic * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
5146085Sbostic * should work. This is unnecessary if it was not a Unix file.
5246085Sbostic */
5346085Sbostic if (fp->_flags == 0) {
5446085Sbostic fp->_flags = __SEOF; /* hold on to it */
5546085Sbostic isopen = 0;
5646085Sbostic wantfd = -1;
5746085Sbostic } else {
5846085Sbostic /* flush the stream; ANSI doesn't require this. */
5946085Sbostic if (fp->_flags & __SWR)
6046213Sbostic (void) __sflush(fp);
6146085Sbostic /* if close is NULL, closing is a no-op, hence pointless */
6246085Sbostic isopen = fp->_close != NULL;
6346085Sbostic if ((wantfd = fp->_file) < 0 && isopen) {
6446085Sbostic (void) (*fp->_close)(fp->_cookie);
6546085Sbostic isopen = 0;
6646085Sbostic }
6717951Sserge }
6817951Sserge
6946085Sbostic /* Get a new descriptor to refer to the new file. */
7046085Sbostic f = open(file, oflags, DEFFILEMODE);
7146085Sbostic if (f < 0 && isopen) {
7246085Sbostic /* If out of fd's close the old one and try again. */
7346085Sbostic if (errno == ENFILE || errno == EMFILE) {
7446085Sbostic (void) (*fp->_close)(fp->_cookie);
7546085Sbostic isopen = 0;
7646085Sbostic f = open(file, oflags, DEFFILEMODE);
7746085Sbostic }
7846085Sbostic }
7946085Sbostic sverrno = errno;
8046085Sbostic
8146085Sbostic /*
8246085Sbostic * Finish closing fp. Even if the open succeeded above, we cannot
8346085Sbostic * keep fp->_base: it may be the wrong size. This loses the effect
8446085Sbostic * of any setbuffer calls, but stdio has always done this before.
8546085Sbostic */
8646085Sbostic if (isopen)
8746085Sbostic (void) (*fp->_close)(fp->_cookie);
8846085Sbostic if (fp->_flags & __SMBF)
8946085Sbostic free((char *)fp->_bf._base);
9046085Sbostic fp->_w = 0;
9146085Sbostic fp->_r = 0;
9246085Sbostic fp->_p = NULL;
9346085Sbostic fp->_bf._base = NULL;
9446085Sbostic fp->_bf._size = 0;
9546085Sbostic fp->_lbfsize = 0;
9646085Sbostic if (HASUB(fp))
9746085Sbostic FREEUB(fp);
9846085Sbostic fp->_ub._size = 0;
9946085Sbostic if (HASLB(fp))
10046085Sbostic FREELB(fp);
10146085Sbostic fp->_lb._size = 0;
10246085Sbostic
10346085Sbostic if (f < 0) { /* did not get it after all */
10446085Sbostic fp->_flags = 0; /* set it free */
10546085Sbostic errno = sverrno; /* restore in case _close clobbered */
10617951Sserge return (NULL);
10746085Sbostic }
10817951Sserge
10946085Sbostic /*
11046085Sbostic * If reopening something that was open before on a real file, try
11146085Sbostic * to maintain the descriptor. Various C library routines (perror)
11246085Sbostic * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
11346085Sbostic */
11446085Sbostic if (wantfd >= 0 && f != wantfd) {
11546085Sbostic if (dup2(f, wantfd) >= 0) {
11646085Sbostic (void) close(f);
11746085Sbostic f = wantfd;
11846085Sbostic }
11946085Sbostic }
12017951Sserge
12146085Sbostic fp->_flags = flags;
12246085Sbostic fp->_file = f;
12346085Sbostic fp->_cookie = fp;
12446085Sbostic fp->_read = __sread;
12546085Sbostic fp->_write = __swrite;
12646085Sbostic fp->_seek = __sseek;
12746085Sbostic fp->_close = __sclose;
12846085Sbostic return (fp);
1292008Swnj }
130