146085Sbostic /*- 246085Sbostic * Copyright (c) 1990 The Regents of the University of California. 346085Sbostic * 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*46611Sbostic static char sccsid[] = "@(#)freopen.c 5.6 (Berkeley) 02/24/91"; 1346085Sbostic #endif /* LIBC_SCCS and not lint */ 1421407Sdist 1517951Sserge #include <sys/types.h> 1646085Sbostic #include <sys/stat.h> 17*46611Sbostic #include <fcntl.h> 1846085Sbostic #include <errno.h> 19*46611Sbostic #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 * 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