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