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