source: trunk/third/sendmail/libsm/fopen.c @ 19204

Revision 19204, 8.3 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19203, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * Copyright (c) 2000-2002 Sendmail, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1990, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
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.
13 */
14
15#include <sm/gen.h>
16SM_RCSID("@(#)$Id: fopen.c,v 1.1.1.1 2003-04-08 15:06:43 zacheiss Exp $")
17#include <errno.h>
18#include <setjmp.h>
19#include <sys/time.h>
20#include <sm/heap.h>
21#include <sm/signal.h>
22#include <sm/assert.h>
23#include <sm/io.h>
24#include <sm/clock.h>
25#include "local.h"
26
27extern int      sm_io_fclose __P((SM_FILE_T *));
28
29static jmp_buf OpenTimeOut, ReopenTimeOut;
30
31/*
32**  OPENALRM -- handler when timeout activated for sm_io_open()
33**
34**  Returns flow of control to where setjmp(OpenTimeOut) was set.
35**
36**      Parameters:
37**              sig -- unused
38**
39**      Returns:
40**              does not return
41**
42**      Side Effects:
43**              returns flow of control to setjmp(OpenTimeOut).
44**
45**      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
46**              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
47**              DOING.
48*/
49
50/* ARGSUSED0 */
51static void
52openalrm(sig)
53        int sig;
54{
55        longjmp(OpenTimeOut, 1);
56}
57/*
58**  REOPENALRM -- handler when timeout activated for sm_io_reopen()
59**
60**  Returns flow of control to where setjmp(ReopenTimeOut) was set.
61**
62**      Parameters:
63**              sig -- unused
64**
65**      Returns:
66**              does not return
67**
68**      Side Effects:
69**              returns flow of control to setjmp(ReopenTimeOut).
70**
71**      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
72**              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
73**              DOING.
74*/
75
76/* ARGSUSED0 */
77static void
78reopenalrm(sig)
79        int sig;
80{
81        longjmp(ReopenTimeOut, 1);
82}
83
84/*
85**  SM_IO_OPEN -- open a file of a specific type
86**
87**      Parameters:
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
93**
94**      Returns:
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.
102*/
103
104SM_FILE_T *
105sm_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 */
108        const void *info;
109        int flags;
110        const void *rpool;
111{
112        register SM_FILE_T *fp;
113        int ioflags;
114        SM_EVENT *evt = NULL;
115
116        ioflags = sm_flags(flags);
117
118        if (ioflags == 0)
119        {
120                /* must give some indication/intent */
121                errno = EINVAL;
122                return NULL;
123        }
124
125        if (timeout == SM_TIME_DEFAULT)
126                timeout = SM_TIME_FOREVER;
127        if (timeout == SM_TIME_IMMEDIATE)
128        {
129                errno = EAGAIN;
130                return NULL;
131        }
132
133        fp = sm_fp(type, ioflags, NULL);
134
135        /*  Okay, this is where we set the timeout.  */
136        if (timeout != SM_TIME_FOREVER)
137        {
138                if (setjmp(OpenTimeOut) != 0)
139                {
140                        errno = EAGAIN;
141                        return NULL;
142                }
143                evt = sm_seteventm(timeout, openalrm, 0);
144        }
145
146        if ((*fp->f_open)(fp, info, flags, rpool) < 0)
147        {
148                fp->f_flags = 0;        /* release */
149                fp->sm_magic = NULL;    /* release */
150                return NULL;
151        }
152
153        /*  We're back. So undo our timeout and handler */
154        if (evt != NULL)
155                sm_clrevent(evt);
156
157#if SM_RPOOL
158        if (rpool != NULL)
159                sm_rpool_attach_x(rpool, sm_io_fclose, fp);
160#endif /* SM_RPOOL */
161
162        return fp;
163}
164/*
165**  SM_IO_DUP -- duplicate a file pointer
166**
167**      Parameters:
168**              fp -- file pointer to duplicate
169**
170**      Returns:
171**              Success - the duplicated file pointer
172**              Failure - NULL (was an invalid file pointer or too many open)
173**
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).
178*/
179
180SM_FILE_T *
181sm_io_dup(fp)
182        SM_FILE_T *fp;
183{
184
185        SM_REQUIRE_ISA(fp, SmFileMagic);
186        if (fp->sm_magic != SmFileMagic)
187        {
188                errno = EBADF;
189                return NULL;
190        }
191        if (fp->f_dup_cnt >= INT_MAX - 1)
192        {
193                /* Can't let f_dup_cnt wrap! */
194                errno = EMFILE;
195                return NULL;
196        }
197        fp->f_dup_cnt++;
198        return fp;
199}
200/*
201**  SM_IO_REOPEN -- open a new file using the old file pointer
202**
203**      Parameters:
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
210**
211**      Returns:
212**              Raises an exception on heap exhaustion.
213**              Aborts if type is invalid.
214**              Failure: returns NULL
215**              Success: returns "reopened" file pointer
216*/
217
218SM_FILE_T *
219sm_io_reopen(type, timeout, info, flags, rpool, fp)
220        const SM_FILE_T *type;
221        int SM_NONVOLATILE timeout;
222        const void *info;
223        int flags;
224        const void *rpool;
225        SM_FILE_T *fp;
226{
227        int ioflags, ret;
228        SM_FILE_T *fp2;
229        SM_EVENT *evt = NULL;
230
231        if ((ioflags = sm_flags(flags)) == 0)
232        {
233                (void) sm_io_close(fp, timeout);
234                return NULL;
235        }
236
237        if (!Sm_IO_DidInit)
238                sm_init();
239
240        if (timeout == SM_TIME_DEFAULT)
241                timeout = SM_TIME_FOREVER;
242        if (timeout == SM_TIME_IMMEDIATE)
243        {
244                /*
245                **  Filling the buffer will take time and we are wanted to
246                **  return immediately. So...
247                */
248
249                errno = EAGAIN;
250                return NULL;
251        }
252        /*  Okay, this is where we set the timeout.  */
253        if (timeout != SM_TIME_FOREVER)
254        {
255                if (setjmp(ReopenTimeOut) != 0)
256                {
257                        errno = EAGAIN;
258                        return NULL;
259                }
260
261                evt = sm_seteventm(timeout, reopenalrm, 0);
262        }
263
264        /*
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.
271        */
272
273        if (fp != NULL)
274        {
275                if (fp->sm_magic != SmFileMagic)
276                        fp->f_flags = SMFEOF;   /* hold on to it */
277                else
278                {
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);
282                }
283        }
284
285        fp2 = sm_fp(type, ioflags, fp);
286        ret = (*fp2->f_open)(fp2, info, flags, rpool);
287
288        /*  We're back. So undo our timeout and handler */
289        if (evt != NULL)
290                sm_clrevent(evt);
291
292        if (ret < 0)
293        {
294                fp2->f_flags = 0;       /* release */
295                fp2->sm_magic = NULL;   /* release */
296                return NULL;
297        }
298
299        /*
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.
307        */
308
309#if SM_RPOOL
310        if (rpool != NULL)
311                sm_rpool_attach_x(rpool, sm_io_close, fp2);
312#endif /* SM_RPOOL */
313
314        return fp2;
315}
316/*
317**  SM_IO_AUTOFLUSH -- link another file to this for auto-flushing
318**
319**      When a read occurs on fp, fp2 will be flushed iff there is no
320**      data waiting on fp.
321**
322**      Parameters:
323**              fp -- the file opened for reading.
324**              fp2 -- the file opened for writing.
325**
326**      Returns:
327**              The old flush file pointer.
328*/
329
330SM_FILE_T *
331sm_io_autoflush(fp, fp2)
332        SM_FILE_T *fp;
333        SM_FILE_T *fp2;
334{
335        SM_FILE_T *savefp;
336
337        SM_REQUIRE_ISA(fp, SmFileMagic);
338        if (fp2 != NULL)
339                SM_REQUIRE_ISA(fp2, SmFileMagic);
340
341        savefp = fp->f_flushfp;
342        fp->f_flushfp = fp2;
343        return savefp;
344}
345/*
346**  SM_IO_AUTOMODE -- link another file to this for auto-moding
347**
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.
353**
354**      Parameters:
355**              fp1 -- the first file
356**              fp2 -- the second file
357**
358**      Returns:
359**              nothing
360*/
361
362void
363sm_io_automode(fp1, fp2)
364        SM_FILE_T *fp1;
365        SM_FILE_T *fp2;
366{
367        SM_REQUIRE_ISA(fp1, SmFileMagic);
368        SM_REQUIRE_ISA(fp2, SmFileMagic);
369
370        fp1->f_modefp = fp2;
371        fp2->f_modefp = fp1;
372}
Note: See TracBrowser for help on using the repository browser.