fopen.c revision 261194
1230557Sjimharris/* 2230557Sjimharris * Copyright (c) 2000-2002, 2004 Proofpoint, Inc. and its suppliers. 3230557Sjimharris * All rights reserved. 4230557Sjimharris * Copyright (c) 1990, 1993 5230557Sjimharris * The Regents of the University of California. All rights reserved. 6230557Sjimharris * 7230557Sjimharris * This code is derived from software contributed to Berkeley by 8230557Sjimharris * Chris Torek. 9230557Sjimharris * 10230557Sjimharris * By using this file, you agree to the terms and conditions set 11230557Sjimharris * forth in the LICENSE file which can be found at the top level of 12230557Sjimharris * the sendmail distribution. 13230557Sjimharris */ 14230557Sjimharris 15230557Sjimharris#include <sm/gen.h> 16230557SjimharrisSM_RCSID("@(#)$Id: fopen.c,v 1.63 2013/11/22 20:51:42 ca Exp $") 17230557Sjimharris#include <errno.h> 18230557Sjimharris#include <setjmp.h> 19230557Sjimharris#include <sm/time.h> 20230557Sjimharris#include <sm/heap.h> 21230557Sjimharris#include <sm/signal.h> 22230557Sjimharris#include <sm/assert.h> 23230557Sjimharris#include <sm/io.h> 24230557Sjimharris#include <sm/clock.h> 25230557Sjimharris#include "local.h" 26230557Sjimharris 27230557Sjimharrisstatic void openalrm __P((int)); 28230557Sjimharrisstatic void reopenalrm __P((int)); 29230557Sjimharrisextern int sm_io_fclose __P((SM_FILE_T *)); 30230557Sjimharris 31230557Sjimharrisstatic jmp_buf OpenTimeOut, ReopenTimeOut; 32230557Sjimharris 33230557Sjimharris/* 34230557Sjimharris** OPENALRM -- handler when timeout activated for sm_io_open() 35230557Sjimharris** 36230557Sjimharris** Returns flow of control to where setjmp(OpenTimeOut) was set. 37230557Sjimharris** 38230557Sjimharris** Parameters: 39230557Sjimharris** sig -- unused 40230557Sjimharris** 41230557Sjimharris** Returns: 42230557Sjimharris** does not return 43230557Sjimharris** 44230557Sjimharris** Side Effects: 45230557Sjimharris** returns flow of control to setjmp(OpenTimeOut). 46230557Sjimharris** 47230557Sjimharris** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 48230557Sjimharris** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 49230557Sjimharris** DOING. 50230557Sjimharris*/ 51230557Sjimharris 52230557Sjimharris/* ARGSUSED0 */ 53230557Sjimharrisstatic void 54230557Sjimharrisopenalrm(sig) 55230557Sjimharris int sig; 56230557Sjimharris{ 57230557Sjimharris longjmp(OpenTimeOut, 1); 58230557Sjimharris} 59230557Sjimharris/* 60230557Sjimharris** REOPENALRM -- handler when timeout activated for sm_io_reopen() 61230557Sjimharris** 62230557Sjimharris** Returns flow of control to where setjmp(ReopenTimeOut) was set. 63230557Sjimharris** 64230557Sjimharris** Parameters: 65230557Sjimharris** sig -- unused 66230557Sjimharris** 67230557Sjimharris** Returns: 68230557Sjimharris** does not return 69230557Sjimharris** 70230557Sjimharris** Side Effects: 71230557Sjimharris** returns flow of control to setjmp(ReopenTimeOut). 72230557Sjimharris** 73230557Sjimharris** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 74230557Sjimharris** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 75230557Sjimharris** DOING. 76230557Sjimharris*/ 77230557Sjimharris 78230557Sjimharris/* ARGSUSED0 */ 79230557Sjimharrisstatic void 80230557Sjimharrisreopenalrm(sig) 81230557Sjimharris int sig; 82230557Sjimharris{ 83230557Sjimharris longjmp(ReopenTimeOut, 1); 84230557Sjimharris} 85230557Sjimharris 86230557Sjimharris/* 87230557Sjimharris** SM_IO_OPEN -- open a file of a specific type 88230557Sjimharris** 89230557Sjimharris** Parameters: 90230557Sjimharris** type -- type of file to open 91230557Sjimharris** timeout -- time to complete the open 92230557Sjimharris** info -- info describing what is to be opened (type dependant) 93230557Sjimharris** flags -- user selected flags 94230557Sjimharris** rpool -- pointer to rpool to be used for this open 95230557Sjimharris** 96230557Sjimharris** Returns: 97230557Sjimharris** Raises exception on heap exhaustion. 98230557Sjimharris** Aborts if type is invalid. 99230557Sjimharris** Returns NULL and sets errno 100230557Sjimharris** - when the type specific open fails 101230557Sjimharris** - when open vector errors 102230557Sjimharris** - when flags not set or invalid 103230557Sjimharris** Success returns a file pointer to the opened file type. 104230557Sjimharris*/ 105230557Sjimharris 106230557SjimharrisSM_FILE_T * 107230557Sjimharrissm_io_open(type, timeout, info, flags, rpool) 108230557Sjimharris const SM_FILE_T *type; 109230557Sjimharris int SM_NONVOLATILE timeout; /* this is not the file type timeout */ 110230557Sjimharris const void *info; 111230557Sjimharris int flags; 112230557Sjimharris const void *rpool; 113230557Sjimharris{ 114230557Sjimharris register SM_FILE_T *fp; 115230557Sjimharris int ioflags; 116230557Sjimharris SM_EVENT *evt = NULL; 117230557Sjimharris 118230557Sjimharris ioflags = sm_flags(flags); 119230557Sjimharris 120230557Sjimharris if (ioflags == 0) 121230557Sjimharris { 122230557Sjimharris /* must give some indication/intent */ 123230557Sjimharris errno = EINVAL; 124230557Sjimharris return NULL; 125230557Sjimharris } 126230557Sjimharris 127230557Sjimharris if (timeout == SM_TIME_DEFAULT) 128230557Sjimharris timeout = SM_TIME_FOREVER; 129230557Sjimharris if (timeout == SM_TIME_IMMEDIATE) 130 { 131 errno = EAGAIN; 132 return NULL; 133 } 134 135 fp = sm_fp(type, ioflags, NULL); 136 137 /* Okay, this is where we set the timeout. */ 138 if (timeout != SM_TIME_FOREVER) 139 { 140 if (setjmp(OpenTimeOut) != 0) 141 { 142 errno = EAGAIN; 143 return NULL; 144 } 145 evt = sm_seteventm(timeout, openalrm, 0); 146 } 147 148 if ((*fp->f_open)(fp, info, flags, rpool) < 0) 149 { 150 fp->f_flags = 0; /* release */ 151 fp->sm_magic = NULL; /* release */ 152 return NULL; 153 } 154 155 /* We're back. So undo our timeout and handler */ 156 if (evt != NULL) 157 sm_clrevent(evt); 158 159#if SM_RPOOL 160 if (rpool != NULL) 161 sm_rpool_attach_x(rpool, sm_io_fclose, fp); 162#endif /* SM_RPOOL */ 163 164 return fp; 165} 166/* 167** SM_IO_DUP -- duplicate a file pointer 168** 169** Parameters: 170** fp -- file pointer to duplicate 171** 172** Returns: 173** Success - the duplicated file pointer 174** Failure - NULL (was an invalid file pointer or too many open) 175** 176** Increments the duplicate counter (dup_cnt) for the open file pointer. 177** The counter counts the number of duplicates. When the duplicate 178** counter is 0 (zero) then the file pointer is the only one left 179** (no duplicates, it is the only one). 180*/ 181 182SM_FILE_T * 183sm_io_dup(fp) 184 SM_FILE_T *fp; 185{ 186 187 SM_REQUIRE_ISA(fp, SmFileMagic); 188 if (fp->sm_magic != SmFileMagic) 189 { 190 errno = EBADF; 191 return NULL; 192 } 193 if (fp->f_dup_cnt >= INT_MAX - 1) 194 { 195 /* Can't let f_dup_cnt wrap! */ 196 errno = EMFILE; 197 return NULL; 198 } 199 fp->f_dup_cnt++; 200 return fp; 201} 202/* 203** SM_IO_REOPEN -- open a new file using the old file pointer 204** 205** Parameters: 206** type -- file type to be opened 207** timeout -- time to complete the reopen 208** info -- infomation about what is to be "re-opened" (type dep.) 209** flags -- user flags to map to internal flags 210** rpool -- rpool file to be associated with 211** fp -- the file pointer to reuse 212** 213** Returns: 214** Raises an exception on heap exhaustion. 215** Aborts if type is invalid. 216** Failure: returns NULL 217** Success: returns "reopened" file pointer 218*/ 219 220SM_FILE_T * 221sm_io_reopen(type, timeout, info, flags, rpool, fp) 222 const SM_FILE_T *type; 223 int SM_NONVOLATILE timeout; 224 const void *info; 225 int flags; 226 const void *rpool; 227 SM_FILE_T *fp; 228{ 229 int ioflags, ret; 230 SM_FILE_T *fp2; 231 SM_EVENT *evt = NULL; 232 233 if ((ioflags = sm_flags(flags)) == 0) 234 { 235 (void) sm_io_close(fp, timeout); 236 return NULL; 237 } 238 239 if (!Sm_IO_DidInit) 240 sm_init(); 241 242 if (timeout == SM_TIME_DEFAULT) 243 timeout = SM_TIME_FOREVER; 244 if (timeout == SM_TIME_IMMEDIATE) 245 { 246 /* 247 ** Filling the buffer will take time and we are wanted to 248 ** return immediately. So... 249 */ 250 251 errno = EAGAIN; 252 return NULL; 253 } 254 /* Okay, this is where we set the timeout. */ 255 if (timeout != SM_TIME_FOREVER) 256 { 257 if (setjmp(ReopenTimeOut) != 0) 258 { 259 errno = EAGAIN; 260 return NULL; 261 } 262 263 evt = sm_seteventm(timeout, reopenalrm, 0); 264 } 265 266 /* 267 ** There are actually programs that depend on being able to "reopen" 268 ** descriptors that weren't originally open. Keep this from breaking. 269 ** Remember whether the stream was open to begin with, and which file 270 ** descriptor (if any) was associated with it. If it was attached to 271 ** a descriptor, defer closing it; reopen("/dev/stdin", "r", stdin) 272 ** should work. This is unnecessary if it was not a Unix file. 273 */ 274 275 if (fp != NULL) 276 { 277 if (fp->sm_magic != SmFileMagic) 278 fp->f_flags = SMFEOF; /* hold on to it */ 279 else 280 { 281 /* flush the stream; ANSI doesn't require this. */ 282 (void) sm_io_flush(fp, SM_TIME_FOREVER); 283 (void) sm_io_close(fp, SM_TIME_FOREVER); 284 } 285 } 286 287 fp2 = sm_fp(type, ioflags, fp); 288 ret = (*fp2->f_open)(fp2, info, flags, rpool); 289 290 /* We're back. So undo our timeout and handler */ 291 if (evt != NULL) 292 sm_clrevent(evt); 293 294 if (ret < 0) 295 { 296 fp2->f_flags = 0; /* release */ 297 fp2->sm_magic = NULL; /* release */ 298 return NULL; 299 } 300 301 /* 302 ** We're not preserving this logic (below) for sm_io because it is now 303 ** abstracted at least one "layer" away. By closing and reopening 304 ** the 1st fd used should be the just released one (when Unix 305 ** behavior followed). Old comment:: 306 ** If reopening something that was open before on a real file, try 307 ** to maintain the descriptor. Various C library routines (perror) 308 ** assume stderr is always fd STDERR_FILENO, even if being reopen'd. 309 */ 310 311#if SM_RPOOL 312 if (rpool != NULL) 313 sm_rpool_attach_x(rpool, sm_io_close, fp2); 314#endif /* SM_RPOOL */ 315 316 return fp2; 317} 318/* 319** SM_IO_AUTOFLUSH -- link another file to this for auto-flushing 320** 321** When a read occurs on fp, fp2 will be flushed iff there is no 322** data waiting on fp. 323** 324** Parameters: 325** fp -- the file opened for reading. 326** fp2 -- the file opened for writing. 327** 328** Returns: 329** The old flush file pointer. 330*/ 331 332SM_FILE_T * 333sm_io_autoflush(fp, fp2) 334 SM_FILE_T *fp; 335 SM_FILE_T *fp2; 336{ 337 SM_FILE_T *savefp; 338 339 SM_REQUIRE_ISA(fp, SmFileMagic); 340 if (fp2 != NULL) 341 SM_REQUIRE_ISA(fp2, SmFileMagic); 342 343 savefp = fp->f_flushfp; 344 fp->f_flushfp = fp2; 345 return savefp; 346} 347/* 348** SM_IO_AUTOMODE -- link another file to this for auto-moding 349** 350** When the mode (blocking or non-blocking) changes for fp1 then 351** update fp2's mode at the same time. This is to be used when 352** a system dup() has generated a second file descriptor for 353** another sm_io_open() by file descriptor. The modes have been 354** linked in the system and this formalizes it for sm_io internally. 355** 356** Parameters: 357** fp1 -- the first file 358** fp2 -- the second file 359** 360** Returns: 361** nothing 362*/ 363 364void 365sm_io_automode(fp1, fp2) 366 SM_FILE_T *fp1; 367 SM_FILE_T *fp2; 368{ 369 SM_REQUIRE_ISA(fp1, SmFileMagic); 370 SM_REQUIRE_ISA(fp2, SmFileMagic); 371 372 fp1->f_modefp = fp2; 373 fp2->f_modefp = fp1; 374} 375