11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*	$OpenBSD: freopen.c,v 1.9 2005/08/08 08:05:36 espie Exp $ */
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*-
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (c) 1990, 1993
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *	The Regents of the University of California.  All rights reserved.
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This code is derived from software contributed to Berkeley by
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Chris Torek.
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    documentation and/or other materials provided with the distribution.
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 3. Neither the name of the University nor the names of its contributors
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    may be used to endorse or promote products derived from this software
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    without specific prior written permission.
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/types.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/stat.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <fcntl.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <errno.h>
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <unistd.h>
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "local.h"
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
43a910abcd194830d2d113b3e183eb7df4d36cd92eAndré Goddard Rosa/*
44a910abcd194830d2d113b3e183eb7df4d36cd92eAndré Goddard Rosa * Re-direct an existing, open (probably) file to some other file.
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ANSI is written such that the original file gets closed if at
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * all possible, no matter what.
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source ProjectFILE *
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfreopen(const char *file, const char *mode, FILE *fp)
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int f;
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int flags, isopen, oflags, sverrno, wantfd;
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if ((flags = __sflags(mode, &oflags)) == 0) {
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void) fclose(fp);
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		return (NULL);
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (!__sdidinit)
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		__sinit();
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * There are actually programs that depend on being able to "freopen"
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * descriptors that weren't originally open.  Keep this from breaking.
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * Remember whether the stream was open to begin with, and which file
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * descriptor (if any) was associated with it.  If it was attached to
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * should work.  This is unnecessary if it was not a Unix file.
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (fp->_flags == 0) {
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		fp->_flags = __SEOF;	/* hold on to it */
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		isopen = 0;
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		wantfd = -1;
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	} else {
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		/* flush the stream; ANSI doesn't require this. */
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (fp->_flags & __SWR)
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			(void) __sflush(fp);
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		/* if close is NULL, closing is a no-op, hence pointless */
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		isopen = fp->_close != NULL;
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if ((wantfd = fp->_file) < 0 && isopen) {
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			(void) (*fp->_close)(fp->_cookie);
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			isopen = 0;
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Get a new descriptor to refer to the new file. */
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	f = open(file, oflags, DEFFILEMODE);
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (f < 0 && isopen) {
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		/* If out of fd's close the old one and try again. */
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (errno == ENFILE || errno == EMFILE) {
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			(void) (*fp->_close)(fp->_cookie);
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			isopen = 0;
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			f = open(file, oflags, DEFFILEMODE);
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	sverrno = errno;
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * Finish closing fp.  Even if the open succeeded above, we cannot
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * keep fp->_base: it may be the wrong size.  This loses the effect
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * of any setbuffer calls, but stdio has always done this before.
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (isopen && f != wantfd)
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void) (*fp->_close)(fp->_cookie);
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (fp->_flags & __SMBF)
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		free((char *)fp->_bf._base);
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_w = 0;
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_r = 0;
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_p = NULL;
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_bf._base = NULL;
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_bf._size = 0;
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_lbfsize = 0;
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (HASUB(fp))
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		FREEUB(fp);
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	_UB(fp)._size = 0;
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	WCIO_FREE(fp);
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (HASLB(fp))
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		FREELB(fp);
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_lb._size = 0;
1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (f < 0) {			/* did not get it after all */
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		fp->_flags = 0;		/* set it free */
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		errno = sverrno;	/* restore in case _close clobbered */
1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		return (NULL);
1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * If reopening something that was open before on a real file, try
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * to maintain the descriptor.  Various C library routines (perror)
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * assume stderr is always fd STDERR_FILENO, even if being freopen'd.
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (wantfd >= 0 && f != wantfd) {
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (dup2(f, wantfd) >= 0) {
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			(void) close(f);
1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			f = wantfd;
1361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_flags = flags;
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_file = f;
1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_cookie = fp;
1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_read = __sread;
1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_write = __swrite;
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_seek = __sseek;
1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_close = __sclose;
1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * When opening in append mode, even though we use O_APPEND,
1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * we need to seek to the end so that ftell() gets the right
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * answer.  If the user then alters the seek pointer, or
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * the file extends, this will fail, but there is not much
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * we can do about this.  (We could set __SAPP and check in
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * fseek and ftell.)
1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (oflags & O_APPEND)
1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void) __sseek((void *)fp, (fpos_t)0, SEEK_END);
1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	return (fp);
1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
159