2 * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
4 * Copyright (c) 1990, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENSE file which can be found at the top level of
12 * the sendmail distribution.
16 SM_RCSID("@(#)$Id: fopen.c,v 1.60 2002/01/07 21:41:35 ca Exp $")
21 #include <sm/signal.h>
22 #include <sm/assert.h>
27 extern int sm_io_fclose __P((SM_FILE_T *));
29 static jmp_buf OpenTimeOut, ReopenTimeOut;
32 ** OPENALRM -- handler when timeout activated for sm_io_open()
34 ** Returns flow of control to where setjmp(OpenTimeOut) was set.
43 ** returns flow of control to setjmp(OpenTimeOut).
45 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
46 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
55 longjmp(OpenTimeOut, 1);
58 ** REOPENALRM -- handler when timeout activated for sm_io_reopen()
60 ** Returns flow of control to where setjmp(ReopenTimeOut) was set.
69 ** returns flow of control to setjmp(ReopenTimeOut).
71 ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
72 ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
81 longjmp(ReopenTimeOut, 1);
85 ** SM_IO_OPEN -- open a file of a specific type
88 ** type -- type of file to open
89 ** timeout -- time to complete the open
90 ** info -- info describing what is to be opened (type dependant)
91 ** flags -- user selected flags
92 ** rpool -- pointer to rpool to be used for this open
95 ** Raises exception on heap exhaustion.
96 ** Aborts if type is invalid.
97 ** Returns NULL and sets errno
98 ** - when the type specific open fails
99 ** - when open vector errors
100 ** - when flags not set or invalid
101 ** Success returns a file pointer to the opened file type.
105 sm_io_open(type, timeout, info, flags, rpool)
106 const SM_FILE_T *type;
107 int SM_NONVOLATILE timeout; /* this is not the file type timeout */
112 register SM_FILE_T *fp;
114 SM_EVENT *evt = NULL;
116 ioflags = sm_flags(flags);
120 /* must give some indication/intent */
125 if (timeout == SM_TIME_DEFAULT)
126 timeout = SM_TIME_FOREVER;
127 if (timeout == SM_TIME_IMMEDIATE)
133 fp = sm_fp(type, ioflags, NULL);
135 /* Okay, this is where we set the timeout. */
136 if (timeout != SM_TIME_FOREVER)
138 if (setjmp(OpenTimeOut) != 0)
143 evt = sm_seteventm(timeout, openalrm, 0);
146 if ((*fp->f_open)(fp, info, flags, rpool) < 0)
148 fp->f_flags = 0; /* release */
149 fp->sm_magic = NULL; /* release */
153 /* We're back. So undo our timeout and handler */
159 sm_rpool_attach_x(rpool, sm_io_fclose, fp);
160 #endif /* SM_RPOOL */
165 ** SM_IO_DUP -- duplicate a file pointer
168 ** fp -- file pointer to duplicate
171 ** Success - the duplicated file pointer
172 ** Failure - NULL (was an invalid file pointer or too many open)
174 ** Increments the duplicate counter (dup_cnt) for the open file pointer.
175 ** The counter counts the number of duplicates. When the duplicate
176 ** counter is 0 (zero) then the file pointer is the only one left
177 ** (no duplicates, it is the only one).
185 SM_REQUIRE_ISA(fp, SmFileMagic);
186 if (fp->sm_magic != SmFileMagic)
191 if (fp->f_dup_cnt >= INT_MAX - 1)
193 /* Can't let f_dup_cnt wrap! */
201 ** SM_IO_REOPEN -- open a new file using the old file pointer
204 ** type -- file type to be opened
205 ** timeout -- time to complete the reopen
206 ** info -- infomation about what is to be "re-opened" (type dep.)
207 ** flags -- user flags to map to internal flags
208 ** rpool -- rpool file to be associated with
209 ** fp -- the file pointer to reuse
212 ** Raises an exception on heap exhaustion.
213 ** Aborts if type is invalid.
214 ** Failure: returns NULL
215 ** Success: returns "reopened" file pointer
219 sm_io_reopen(type, timeout, info, flags, rpool, fp)
220 const SM_FILE_T *type;
221 int SM_NONVOLATILE timeout;
229 SM_EVENT *evt = NULL;
231 if ((ioflags = sm_flags(flags)) == 0)
233 (void) sm_io_close(fp, timeout);
240 if (timeout == SM_TIME_DEFAULT)
241 timeout = SM_TIME_FOREVER;
242 if (timeout == SM_TIME_IMMEDIATE)
245 ** Filling the buffer will take time and we are wanted to
246 ** return immediately. So...
252 /* Okay, this is where we set the timeout. */
253 if (timeout != SM_TIME_FOREVER)
255 if (setjmp(ReopenTimeOut) != 0)
261 evt = sm_seteventm(timeout, reopenalrm, 0);
265 ** There are actually programs that depend on being able to "reopen"
266 ** descriptors that weren't originally open. Keep this from breaking.
267 ** Remember whether the stream was open to begin with, and which file
268 ** descriptor (if any) was associated with it. If it was attached to
269 ** a descriptor, defer closing it; reopen("/dev/stdin", "r", stdin)
270 ** should work. This is unnecessary if it was not a Unix file.
275 if (fp->sm_magic != SmFileMagic)
276 fp->f_flags = SMFEOF; /* hold on to it */
279 /* flush the stream; ANSI doesn't require this. */
280 (void) sm_io_flush(fp, SM_TIME_FOREVER);
281 (void) sm_io_close(fp, SM_TIME_FOREVER);
285 fp2 = sm_fp(type, ioflags, fp);
286 ret = (*fp2->f_open)(fp2, info, flags, rpool);
288 /* We're back. So undo our timeout and handler */
294 fp2->f_flags = 0; /* release */
295 fp2->sm_magic = NULL; /* release */
300 ** We're not preserving this logic (below) for sm_io because it is now
301 ** abstracted at least one "layer" away. By closing and reopening
302 ** the 1st fd used should be the just released one (when Unix
303 ** behavior followed). Old comment::
304 ** If reopening something that was open before on a real file, try
305 ** to maintain the descriptor. Various C library routines (perror)
306 ** assume stderr is always fd STDERR_FILENO, even if being reopen'd.
311 sm_rpool_attach_x(rpool, sm_io_close, fp2);
312 #endif /* SM_RPOOL */
317 ** SM_IO_AUTOFLUSH -- link another file to this for auto-flushing
319 ** When a read occurs on fp, fp2 will be flushed iff there is no
320 ** data waiting on fp.
323 ** fp -- the file opened for reading.
324 ** fp2 -- the file opened for writing.
327 ** The old flush file pointer.
331 sm_io_autoflush(fp, fp2)
337 SM_REQUIRE_ISA(fp, SmFileMagic);
339 SM_REQUIRE_ISA(fp2, SmFileMagic);
341 savefp = fp->f_flushfp;
346 ** SM_IO_AUTOMODE -- link another file to this for auto-moding
348 ** When the mode (blocking or non-blocking) changes for fp1 then
349 ** update fp2's mode at the same time. This is to be used when
350 ** a system dup() has generated a second file descriptor for
351 ** another sm_io_open() by file descriptor. The modes have been
352 ** linked in the system and this formalizes it for sm_io internally.
355 ** fp1 -- the first file
356 ** fp2 -- the second file
363 sm_io_automode(fp1, fp2)
367 SM_REQUIRE_ISA(fp1, SmFileMagic);
368 SM_REQUIRE_ISA(fp2, SmFileMagic);