fopen.c revision 90792
190792Sgshapiro/*
290792Sgshapiro * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
390792Sgshapiro *      All rights reserved.
490792Sgshapiro * Copyright (c) 1990, 1993
590792Sgshapiro *	The Regents of the University of California.  All rights reserved.
690792Sgshapiro *
790792Sgshapiro * This code is derived from software contributed to Berkeley by
890792Sgshapiro * Chris Torek.
990792Sgshapiro *
1090792Sgshapiro * By using this file, you agree to the terms and conditions set
1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of
1290792Sgshapiro * the sendmail distribution.
1390792Sgshapiro */
1490792Sgshapiro
1590792Sgshapiro#include <sm/gen.h>
1690792SgshapiroSM_RCSID("@(#)$Id: fopen.c,v 1.60 2002/01/07 21:41:35 ca Exp $")
1790792Sgshapiro#include <errno.h>
1890792Sgshapiro#include <setjmp.h>
1990792Sgshapiro#include <sys/time.h>
2090792Sgshapiro#include <sm/heap.h>
2190792Sgshapiro#include <sm/signal.h>
2290792Sgshapiro#include <sm/assert.h>
2390792Sgshapiro#include <sm/io.h>
2490792Sgshapiro#include <sm/clock.h>
2590792Sgshapiro#include "local.h"
2690792Sgshapiro
2790792Sgshapiroextern int      sm_io_fclose __P((SM_FILE_T *));
2890792Sgshapiro
2990792Sgshapirostatic jmp_buf OpenTimeOut, ReopenTimeOut;
3090792Sgshapiro
3190792Sgshapiro/*
3290792Sgshapiro**  OPENALRM -- handler when timeout activated for sm_io_open()
3390792Sgshapiro**
3490792Sgshapiro**  Returns flow of control to where setjmp(OpenTimeOut) was set.
3590792Sgshapiro**
3690792Sgshapiro**	Parameters:
3790792Sgshapiro**		sig -- unused
3890792Sgshapiro**
3990792Sgshapiro**	Returns:
4090792Sgshapiro**		does not return
4190792Sgshapiro**
4290792Sgshapiro**	Side Effects:
4390792Sgshapiro**		returns flow of control to setjmp(OpenTimeOut).
4490792Sgshapiro**
4590792Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
4690792Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
4790792Sgshapiro**		DOING.
4890792Sgshapiro*/
4990792Sgshapiro
5090792Sgshapiro/* ARGSUSED0 */
5190792Sgshapirostatic void
5290792Sgshapiroopenalrm(sig)
5390792Sgshapiro	int sig;
5490792Sgshapiro{
5590792Sgshapiro	longjmp(OpenTimeOut, 1);
5690792Sgshapiro}
5790792Sgshapiro/*
5890792Sgshapiro**  REOPENALRM -- handler when timeout activated for sm_io_reopen()
5990792Sgshapiro**
6090792Sgshapiro**  Returns flow of control to where setjmp(ReopenTimeOut) was set.
6190792Sgshapiro**
6290792Sgshapiro**	Parameters:
6390792Sgshapiro**		sig -- unused
6490792Sgshapiro**
6590792Sgshapiro**	Returns:
6690792Sgshapiro**		does not return
6790792Sgshapiro**
6890792Sgshapiro**	Side Effects:
6990792Sgshapiro**		returns flow of control to setjmp(ReopenTimeOut).
7090792Sgshapiro**
7190792Sgshapiro**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
7290792Sgshapiro**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
7390792Sgshapiro**		DOING.
7490792Sgshapiro*/
7590792Sgshapiro
7690792Sgshapiro/* ARGSUSED0 */
7790792Sgshapirostatic void
7890792Sgshapiroreopenalrm(sig)
7990792Sgshapiro	int sig;
8090792Sgshapiro{
8190792Sgshapiro	longjmp(ReopenTimeOut, 1);
8290792Sgshapiro}
8390792Sgshapiro
8490792Sgshapiro/*
8590792Sgshapiro**  SM_IO_OPEN -- open a file of a specific type
8690792Sgshapiro**
8790792Sgshapiro**	Parameters:
8890792Sgshapiro**		type -- type of file to open
8990792Sgshapiro**		timeout -- time to complete the open
9090792Sgshapiro**		info -- info describing what is to be opened (type dependant)
9190792Sgshapiro**		flags -- user selected flags
9290792Sgshapiro**		rpool -- pointer to rpool to be used for this open
9390792Sgshapiro**
9490792Sgshapiro**	Returns:
9590792Sgshapiro**		Raises exception on heap exhaustion.
9690792Sgshapiro**		Aborts if type is invalid.
9790792Sgshapiro**		Returns NULL and sets errno
9890792Sgshapiro**			- when the type specific open fails
9990792Sgshapiro**			- when open vector errors
10090792Sgshapiro**			- when flags not set or invalid
10190792Sgshapiro**		Success returns a file pointer to the opened file type.
10290792Sgshapiro*/
10390792Sgshapiro
10490792SgshapiroSM_FILE_T *
10590792Sgshapirosm_io_open(type, timeout, info, flags, rpool)
10690792Sgshapiro	const SM_FILE_T *type;
10790792Sgshapiro	int SM_NONVOLATILE timeout;	/* this is not the file type timeout */
10890792Sgshapiro	const void *info;
10990792Sgshapiro	int flags;
11090792Sgshapiro	const void *rpool;
11190792Sgshapiro{
11290792Sgshapiro	register SM_FILE_T *fp;
11390792Sgshapiro	int ioflags;
11490792Sgshapiro	SM_EVENT *evt = NULL;
11590792Sgshapiro
11690792Sgshapiro	ioflags = sm_flags(flags);
11790792Sgshapiro
11890792Sgshapiro	if (ioflags == 0)
11990792Sgshapiro	{
12090792Sgshapiro		/* must give some indication/intent */
12190792Sgshapiro		errno = EINVAL;
12290792Sgshapiro		return NULL;
12390792Sgshapiro	}
12490792Sgshapiro
12590792Sgshapiro	if (timeout == SM_TIME_DEFAULT)
12690792Sgshapiro		timeout = SM_TIME_FOREVER;
12790792Sgshapiro	if (timeout == SM_TIME_IMMEDIATE)
12890792Sgshapiro	{
12990792Sgshapiro		errno = EAGAIN;
13090792Sgshapiro		return NULL;
13190792Sgshapiro	}
13290792Sgshapiro
13390792Sgshapiro	fp = sm_fp(type, ioflags, NULL);
13490792Sgshapiro
13590792Sgshapiro	/*  Okay, this is where we set the timeout.  */
13690792Sgshapiro	if (timeout != SM_TIME_FOREVER)
13790792Sgshapiro	{
13890792Sgshapiro		if (setjmp(OpenTimeOut) != 0)
13990792Sgshapiro		{
14090792Sgshapiro			errno = EAGAIN;
14190792Sgshapiro			return NULL;
14290792Sgshapiro		}
14390792Sgshapiro		evt = sm_seteventm(timeout, openalrm, 0);
14490792Sgshapiro	}
14590792Sgshapiro
14690792Sgshapiro	if ((*fp->f_open)(fp, info, flags, rpool) < 0)
14790792Sgshapiro	{
14890792Sgshapiro		fp->f_flags = 0;	/* release */
14990792Sgshapiro		fp->sm_magic = NULL;	/* release */
15090792Sgshapiro		return NULL;
15190792Sgshapiro	}
15290792Sgshapiro
15390792Sgshapiro	/*  We're back. So undo our timeout and handler */
15490792Sgshapiro	if (evt != NULL)
15590792Sgshapiro		sm_clrevent(evt);
15690792Sgshapiro
15790792Sgshapiro#if SM_RPOOL
15890792Sgshapiro	if (rpool != NULL)
15990792Sgshapiro		sm_rpool_attach_x(rpool, sm_io_fclose, fp);
16090792Sgshapiro#endif /* SM_RPOOL */
16190792Sgshapiro
16290792Sgshapiro	return fp;
16390792Sgshapiro}
16490792Sgshapiro/*
16590792Sgshapiro**  SM_IO_DUP -- duplicate a file pointer
16690792Sgshapiro**
16790792Sgshapiro**	Parameters:
16890792Sgshapiro**		fp -- file pointer to duplicate
16990792Sgshapiro**
17090792Sgshapiro**	Returns:
17190792Sgshapiro**		Success - the duplicated file pointer
17290792Sgshapiro**		Failure - NULL (was an invalid file pointer or too many open)
17390792Sgshapiro**
17490792Sgshapiro**	Increments the duplicate counter (dup_cnt) for the open file pointer.
17590792Sgshapiro**	The counter counts the number of duplicates. When the duplicate
17690792Sgshapiro**	counter is 0 (zero) then the file pointer is the only one left
17790792Sgshapiro**	(no duplicates, it is the only one).
17890792Sgshapiro*/
17990792Sgshapiro
18090792SgshapiroSM_FILE_T *
18190792Sgshapirosm_io_dup(fp)
18290792Sgshapiro	SM_FILE_T *fp;
18390792Sgshapiro{
18490792Sgshapiro
18590792Sgshapiro	SM_REQUIRE_ISA(fp, SmFileMagic);
18690792Sgshapiro	if (fp->sm_magic != SmFileMagic)
18790792Sgshapiro	{
18890792Sgshapiro		errno = EBADF;
18990792Sgshapiro		return NULL;
19090792Sgshapiro	}
19190792Sgshapiro	if (fp->f_dup_cnt >= INT_MAX - 1)
19290792Sgshapiro	{
19390792Sgshapiro		/* Can't let f_dup_cnt wrap! */
19490792Sgshapiro		errno = EMFILE;
19590792Sgshapiro		return NULL;
19690792Sgshapiro	}
19790792Sgshapiro	fp->f_dup_cnt++;
19890792Sgshapiro	return fp;
19990792Sgshapiro}
20090792Sgshapiro/*
20190792Sgshapiro**  SM_IO_REOPEN -- open a new file using the old file pointer
20290792Sgshapiro**
20390792Sgshapiro**	Parameters:
20490792Sgshapiro**		type -- file type to be opened
20590792Sgshapiro**		timeout -- time to complete the reopen
20690792Sgshapiro**		info -- infomation about what is to be "re-opened" (type dep.)
20790792Sgshapiro**		flags -- user flags to map to internal flags
20890792Sgshapiro**		rpool -- rpool file to be associated with
20990792Sgshapiro**		fp -- the file pointer to reuse
21090792Sgshapiro**
21190792Sgshapiro**	Returns:
21290792Sgshapiro**		Raises an exception on heap exhaustion.
21390792Sgshapiro**		Aborts if type is invalid.
21490792Sgshapiro**		Failure: returns NULL
21590792Sgshapiro**		Success: returns "reopened" file pointer
21690792Sgshapiro*/
21790792Sgshapiro
21890792SgshapiroSM_FILE_T *
21990792Sgshapirosm_io_reopen(type, timeout, info, flags, rpool, fp)
22090792Sgshapiro	const SM_FILE_T *type;
22190792Sgshapiro	int SM_NONVOLATILE timeout;
22290792Sgshapiro	const void *info;
22390792Sgshapiro	int flags;
22490792Sgshapiro	const void *rpool;
22590792Sgshapiro	SM_FILE_T *fp;
22690792Sgshapiro{
22790792Sgshapiro	int ioflags, ret;
22890792Sgshapiro	SM_FILE_T *fp2;
22990792Sgshapiro	SM_EVENT *evt = NULL;
23090792Sgshapiro
23190792Sgshapiro	if ((ioflags = sm_flags(flags)) == 0)
23290792Sgshapiro	{
23390792Sgshapiro		(void) sm_io_close(fp, timeout);
23490792Sgshapiro		return NULL;
23590792Sgshapiro	}
23690792Sgshapiro
23790792Sgshapiro	if (!Sm_IO_DidInit)
23890792Sgshapiro		sm_init();
23990792Sgshapiro
24090792Sgshapiro	if (timeout == SM_TIME_DEFAULT)
24190792Sgshapiro		timeout = SM_TIME_FOREVER;
24290792Sgshapiro	if (timeout == SM_TIME_IMMEDIATE)
24390792Sgshapiro	{
24490792Sgshapiro		/*
24590792Sgshapiro		**  Filling the buffer will take time and we are wanted to
24690792Sgshapiro		**  return immediately. So...
24790792Sgshapiro		*/
24890792Sgshapiro
24990792Sgshapiro		errno = EAGAIN;
25090792Sgshapiro		return NULL;
25190792Sgshapiro	}
25290792Sgshapiro	/*  Okay, this is where we set the timeout.  */
25390792Sgshapiro	if (timeout != SM_TIME_FOREVER)
25490792Sgshapiro	{
25590792Sgshapiro		if (setjmp(ReopenTimeOut) != 0)
25690792Sgshapiro		{
25790792Sgshapiro			errno = EAGAIN;
25890792Sgshapiro			return NULL;
25990792Sgshapiro		}
26090792Sgshapiro
26190792Sgshapiro		evt = sm_seteventm(timeout, reopenalrm, 0);
26290792Sgshapiro	}
26390792Sgshapiro
26490792Sgshapiro	/*
26590792Sgshapiro	**  There are actually programs that depend on being able to "reopen"
26690792Sgshapiro	**  descriptors that weren't originally open.  Keep this from breaking.
26790792Sgshapiro	**  Remember whether the stream was open to begin with, and which file
26890792Sgshapiro	**  descriptor (if any) was associated with it.  If it was attached to
26990792Sgshapiro	**  a descriptor, defer closing it; reopen("/dev/stdin", "r", stdin)
27090792Sgshapiro	**  should work.  This is unnecessary if it was not a Unix file.
27190792Sgshapiro	*/
27290792Sgshapiro
27390792Sgshapiro	if (fp != NULL)
27490792Sgshapiro	{
27590792Sgshapiro		if (fp->sm_magic != SmFileMagic)
27690792Sgshapiro			fp->f_flags = SMFEOF;	/* hold on to it */
27790792Sgshapiro		else
27890792Sgshapiro		{
27990792Sgshapiro			/* flush the stream; ANSI doesn't require this. */
28090792Sgshapiro			(void) sm_io_flush(fp, SM_TIME_FOREVER);
28190792Sgshapiro			(void) sm_io_close(fp, SM_TIME_FOREVER);
28290792Sgshapiro		}
28390792Sgshapiro	}
28490792Sgshapiro
28590792Sgshapiro	fp2 = sm_fp(type, ioflags, fp);
28690792Sgshapiro	ret = (*fp2->f_open)(fp2, info, flags, rpool);
28790792Sgshapiro
28890792Sgshapiro	/*  We're back. So undo our timeout and handler */
28990792Sgshapiro	if (evt != NULL)
29090792Sgshapiro		sm_clrevent(evt);
29190792Sgshapiro
29290792Sgshapiro	if (ret < 0)
29390792Sgshapiro	{
29490792Sgshapiro		fp2->f_flags = 0;	/* release */
29590792Sgshapiro		fp2->sm_magic = NULL;	/* release */
29690792Sgshapiro		return NULL;
29790792Sgshapiro	}
29890792Sgshapiro
29990792Sgshapiro	/*
30090792Sgshapiro	**  We're not preserving this logic (below) for sm_io because it is now
30190792Sgshapiro	**  abstracted at least one "layer" away. By closing and reopening
30290792Sgshapiro	**  the 1st fd used should be the just released one (when Unix
30390792Sgshapiro	**  behavior followed). Old comment::
30490792Sgshapiro	**  If reopening something that was open before on a real file, try
30590792Sgshapiro	**  to maintain the descriptor.  Various C library routines (perror)
30690792Sgshapiro	**  assume stderr is always fd STDERR_FILENO, even if being reopen'd.
30790792Sgshapiro	*/
30890792Sgshapiro
30990792Sgshapiro#if SM_RPOOL
31090792Sgshapiro	if (rpool != NULL)
31190792Sgshapiro		sm_rpool_attach_x(rpool, sm_io_close, fp2);
31290792Sgshapiro#endif /* SM_RPOOL */
31390792Sgshapiro
31490792Sgshapiro	return fp2;
31590792Sgshapiro}
31690792Sgshapiro/*
31790792Sgshapiro**  SM_IO_AUTOFLUSH -- link another file to this for auto-flushing
31890792Sgshapiro**
31990792Sgshapiro**	When a read occurs on fp, fp2 will be flushed iff there is no
32090792Sgshapiro**	data waiting on fp.
32190792Sgshapiro**
32290792Sgshapiro**	Parameters:
32390792Sgshapiro**		fp -- the file opened for reading.
32490792Sgshapiro**		fp2 -- the file opened for writing.
32590792Sgshapiro**
32690792Sgshapiro**	Returns:
32790792Sgshapiro**		The old flush file pointer.
32890792Sgshapiro*/
32990792Sgshapiro
33090792SgshapiroSM_FILE_T *
33190792Sgshapirosm_io_autoflush(fp, fp2)
33290792Sgshapiro	SM_FILE_T *fp;
33390792Sgshapiro	SM_FILE_T *fp2;
33490792Sgshapiro{
33590792Sgshapiro	SM_FILE_T *savefp;
33690792Sgshapiro
33790792Sgshapiro	SM_REQUIRE_ISA(fp, SmFileMagic);
33890792Sgshapiro	if (fp2 != NULL)
33990792Sgshapiro		SM_REQUIRE_ISA(fp2, SmFileMagic);
34090792Sgshapiro
34190792Sgshapiro	savefp = fp->f_flushfp;
34290792Sgshapiro	fp->f_flushfp = fp2;
34390792Sgshapiro	return savefp;
34490792Sgshapiro}
34590792Sgshapiro/*
34690792Sgshapiro**  SM_IO_AUTOMODE -- link another file to this for auto-moding
34790792Sgshapiro**
34890792Sgshapiro**	When the mode (blocking or non-blocking) changes for fp1 then
34990792Sgshapiro**	update fp2's mode at the same time. This is to be used when
35090792Sgshapiro**	a system dup() has generated a second file descriptor for
35190792Sgshapiro**	another sm_io_open() by file descriptor. The modes have been
35290792Sgshapiro**	linked in the system and this formalizes it for sm_io internally.
35390792Sgshapiro**
35490792Sgshapiro**	Parameters:
35590792Sgshapiro**		fp1 -- the first file
35690792Sgshapiro**		fp2 -- the second file
35790792Sgshapiro**
35890792Sgshapiro**	Returns:
35990792Sgshapiro**		nothing
36090792Sgshapiro*/
36190792Sgshapiro
36290792Sgshapirovoid
36390792Sgshapirosm_io_automode(fp1, fp2)
36490792Sgshapiro	SM_FILE_T *fp1;
36590792Sgshapiro	SM_FILE_T *fp2;
36690792Sgshapiro{
36790792Sgshapiro	SM_REQUIRE_ISA(fp1, SmFileMagic);
36890792Sgshapiro	SM_REQUIRE_ISA(fp2, SmFileMagic);
36990792Sgshapiro
37090792Sgshapiro	fp1->f_modefp = fp2;
37190792Sgshapiro	fp2->f_modefp = fp1;
37290792Sgshapiro}
373