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*46213Sbostic static char sccsid[] = "@(#)freopen.c 5.4 (Berkeley) 02/01/91"; 1346085Sbostic #endif /* LIBC_SCCS and not lint */ 1421407Sdist 1517951Sserge #include <sys/types.h> 1617951Sserge #include <sys/file.h> 1746085Sbostic #include <sys/stat.h> 1846085Sbostic #include <errno.h> 1917951Sserge #include <stdio.h> 2046085Sbostic #include <stdlib.h> 2146085Sbostic #include "local.h" 222008Swnj 2346085Sbostic /* 2446085Sbostic * Re-direct an existing, open (probably) file to some other file. 2546085Sbostic * ANSI is written such that the original file gets closed if at 2646085Sbostic * all possible, no matter what. 2746085Sbostic */ 282008Swnj FILE * 2946085Sbostic freopen(file, mode, fp) 3046085Sbostic char *file, *mode; 3146085Sbostic register FILE *fp; 322008Swnj { 3346085Sbostic register int f; 3446085Sbostic int flags, isopen, oflags, sverrno, wantfd; 352008Swnj 3646085Sbostic if ((flags = __sflags(mode, &oflags)) == 0) { 3746085Sbostic (void) fclose(fp); 3846085Sbostic return (NULL); 3946085Sbostic } 403163Stoy 4146085Sbostic if (!__sdidinit) 4246085Sbostic __sinit(); 4317951Sserge 4446085Sbostic /* 4546085Sbostic * There are actually programs that depend on being able to "freopen" 4646085Sbostic * descriptors that weren't originally open. Keep this from breaking. 4746085Sbostic * Remember whether the stream was open to begin with, and which file 4846085Sbostic * descriptor (if any) was associated with it. If it was attached to 4946085Sbostic * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin) 5046085Sbostic * should work. This is unnecessary if it was not a Unix file. 5146085Sbostic */ 5246085Sbostic if (fp->_flags == 0) { 5346085Sbostic fp->_flags = __SEOF; /* hold on to it */ 5446085Sbostic isopen = 0; 5546085Sbostic wantfd = -1; 5646085Sbostic } else { 5746085Sbostic /* flush the stream; ANSI doesn't require this. */ 5846085Sbostic if (fp->_flags & __SWR) 59*46213Sbostic (void) __sflush(fp); 6046085Sbostic /* if close is NULL, closing is a no-op, hence pointless */ 6146085Sbostic isopen = fp->_close != NULL; 6246085Sbostic if ((wantfd = fp->_file) < 0 && isopen) { 6346085Sbostic (void) (*fp->_close)(fp->_cookie); 6446085Sbostic isopen = 0; 6546085Sbostic } 6617951Sserge } 6717951Sserge 6846085Sbostic /* Get a new descriptor to refer to the new file. */ 6946085Sbostic f = open(file, oflags, DEFFILEMODE); 7046085Sbostic if (f < 0 && isopen) { 7146085Sbostic /* If out of fd's close the old one and try again. */ 7246085Sbostic if (errno == ENFILE || errno == EMFILE) { 7346085Sbostic (void) (*fp->_close)(fp->_cookie); 7446085Sbostic isopen = 0; 7546085Sbostic f = open(file, oflags, DEFFILEMODE); 7646085Sbostic } 7746085Sbostic } 7846085Sbostic sverrno = errno; 7946085Sbostic 8046085Sbostic /* 8146085Sbostic * Finish closing fp. Even if the open succeeded above, we cannot 8246085Sbostic * keep fp->_base: it may be the wrong size. This loses the effect 8346085Sbostic * of any setbuffer calls, but stdio has always done this before. 8446085Sbostic */ 8546085Sbostic if (isopen) 8646085Sbostic (void) (*fp->_close)(fp->_cookie); 8746085Sbostic if (fp->_flags & __SMBF) 8846085Sbostic free((char *)fp->_bf._base); 8946085Sbostic fp->_w = 0; 9046085Sbostic fp->_r = 0; 9146085Sbostic fp->_p = NULL; 9246085Sbostic fp->_bf._base = NULL; 9346085Sbostic fp->_bf._size = 0; 9446085Sbostic fp->_lbfsize = 0; 9546085Sbostic if (HASUB(fp)) 9646085Sbostic FREEUB(fp); 9746085Sbostic fp->_ub._size = 0; 9846085Sbostic if (HASLB(fp)) 9946085Sbostic FREELB(fp); 10046085Sbostic fp->_lb._size = 0; 10146085Sbostic 10246085Sbostic if (f < 0) { /* did not get it after all */ 10346085Sbostic fp->_flags = 0; /* set it free */ 10446085Sbostic errno = sverrno; /* restore in case _close clobbered */ 10517951Sserge return (NULL); 10646085Sbostic } 10717951Sserge 10846085Sbostic /* 10946085Sbostic * If reopening something that was open before on a real file, try 11046085Sbostic * to maintain the descriptor. Various C library routines (perror) 11146085Sbostic * assume stderr is always fd STDERR_FILENO, even if being freopen'd. 11246085Sbostic */ 11346085Sbostic if (wantfd >= 0 && f != wantfd) { 11446085Sbostic if (dup2(f, wantfd) >= 0) { 11546085Sbostic (void) close(f); 11646085Sbostic f = wantfd; 11746085Sbostic } 11846085Sbostic } 11917951Sserge 12046085Sbostic fp->_flags = flags; 12146085Sbostic fp->_file = f; 12246085Sbostic fp->_cookie = fp; 12346085Sbostic fp->_read = __sread; 12446085Sbostic fp->_write = __swrite; 12546085Sbostic fp->_seek = __sseek; 12646085Sbostic fp->_close = __sclose; 12746085Sbostic return (fp); 1282008Swnj } 129