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> |
---|
16 | SM_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 | |
---|
27 | extern int sm_io_fclose __P((SM_FILE_T *)); |
---|
28 | |
---|
29 | static 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 */ |
---|
51 | static void |
---|
52 | openalrm(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 */ |
---|
77 | static void |
---|
78 | reopenalrm(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 | |
---|
104 | SM_FILE_T * |
---|
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 */ |
---|
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 | |
---|
180 | SM_FILE_T * |
---|
181 | sm_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 | |
---|
218 | SM_FILE_T * |
---|
219 | sm_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 | |
---|
330 | SM_FILE_T * |
---|
331 | sm_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 | |
---|
362 | void |
---|
363 | sm_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 | } |
---|