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 | * $Id: local.h,v 1.2 2006-03-23 21:02:44 zacheiss Exp $ |
---|
15 | */ |
---|
16 | |
---|
17 | /* |
---|
18 | ** Information local to this implementation of stdio, |
---|
19 | ** in particular, macros and private variables. |
---|
20 | */ |
---|
21 | |
---|
22 | #include <sys/time.h> |
---|
23 | #if !SM_CONF_MEMCHR |
---|
24 | # include <memory.h> |
---|
25 | #endif /* !SM_CONF_MEMCHR */ |
---|
26 | #include <sm/heap.h> |
---|
27 | |
---|
28 | int sm_flush __P((SM_FILE_T *, int *)); |
---|
29 | SM_FILE_T *smfp __P((void)); |
---|
30 | int sm_refill __P((SM_FILE_T *, int)); |
---|
31 | void sm_init __P((void)); |
---|
32 | void sm_cleanup __P((void)); |
---|
33 | void sm_makebuf __P((SM_FILE_T *)); |
---|
34 | int sm_whatbuf __P((SM_FILE_T *, size_t *, int *)); |
---|
35 | int sm_fwalk __P((int (*)(SM_FILE_T *, int *), int *)); |
---|
36 | int sm_wsetup __P((SM_FILE_T *)); |
---|
37 | int sm_flags __P((int)); |
---|
38 | SM_FILE_T *sm_fp __P((const SM_FILE_T *, const int, SM_FILE_T *)); |
---|
39 | int sm_vprintf __P((int, char const *, va_list)); |
---|
40 | int sm_vfscanf __P((SM_FILE_T *, int, char const *, va_list)); |
---|
41 | |
---|
42 | /* std io functions */ |
---|
43 | ssize_t sm_stdread __P((SM_FILE_T *, char *, size_t)); |
---|
44 | ssize_t sm_stdwrite __P((SM_FILE_T *, char const *, size_t)); |
---|
45 | off_t sm_stdseek __P((SM_FILE_T *, off_t, int)); |
---|
46 | int sm_stdclose __P((SM_FILE_T *)); |
---|
47 | int sm_stdopen __P((SM_FILE_T *, const void *, int, const void *)); |
---|
48 | int sm_stdfdopen __P((SM_FILE_T *, const void *, int, const void *)); |
---|
49 | int sm_stdsetinfo __P((SM_FILE_T *, int , void *)); |
---|
50 | int sm_stdgetinfo __P((SM_FILE_T *, int , void *)); |
---|
51 | |
---|
52 | /* stdio io functions */ |
---|
53 | ssize_t sm_stdioread __P((SM_FILE_T *, char *, size_t)); |
---|
54 | ssize_t sm_stdiowrite __P((SM_FILE_T *, char const *, size_t)); |
---|
55 | off_t sm_stdioseek __P((SM_FILE_T *, off_t, int)); |
---|
56 | int sm_stdioclose __P((SM_FILE_T *)); |
---|
57 | int sm_stdioopen __P((SM_FILE_T *, const void *, int, const void *)); |
---|
58 | int sm_stdiosetinfo __P((SM_FILE_T *, int , void *)); |
---|
59 | int sm_stdiogetinfo __P((SM_FILE_T *, int , void *)); |
---|
60 | |
---|
61 | /* string io functions */ |
---|
62 | ssize_t sm_strread __P((SM_FILE_T *, char *, size_t)); |
---|
63 | ssize_t sm_strwrite __P((SM_FILE_T *, char const *, size_t)); |
---|
64 | off_t sm_strseek __P((SM_FILE_T *, off_t, int)); |
---|
65 | int sm_strclose __P((SM_FILE_T *)); |
---|
66 | int sm_stropen __P((SM_FILE_T *, const void *, int, const void *)); |
---|
67 | int sm_strsetinfo __P((SM_FILE_T *, int , void *)); |
---|
68 | int sm_strgetinfo __P((SM_FILE_T *, int , void *)); |
---|
69 | |
---|
70 | /* syslog io functions */ |
---|
71 | ssize_t sm_syslogread __P((SM_FILE_T *, char *, size_t)); |
---|
72 | ssize_t sm_syslogwrite __P((SM_FILE_T *, char const *, size_t)); |
---|
73 | off_t sm_syslogseek __P((SM_FILE_T *, off_t, int)); |
---|
74 | int sm_syslogclose __P((SM_FILE_T *)); |
---|
75 | int sm_syslogopen __P((SM_FILE_T *, const void *, int, const void *)); |
---|
76 | int sm_syslogsetinfo __P((SM_FILE_T *, int , void *)); |
---|
77 | int sm_sysloggetinfo __P((SM_FILE_T *, int , void *)); |
---|
78 | |
---|
79 | /* should be defined in sys/time.h */ |
---|
80 | #ifndef timersub |
---|
81 | # define timersub(tvp, uvp, vvp) \ |
---|
82 | do \ |
---|
83 | { \ |
---|
84 | (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ |
---|
85 | (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ |
---|
86 | if ((vvp)->tv_usec < 0) \ |
---|
87 | { \ |
---|
88 | (vvp)->tv_sec--; \ |
---|
89 | (vvp)->tv_usec += 1000000; \ |
---|
90 | } \ |
---|
91 | } while (0) |
---|
92 | #endif /* !timersub */ |
---|
93 | |
---|
94 | #ifndef timeradd |
---|
95 | # define timeradd(tvp, uvp, vvp) \ |
---|
96 | do \ |
---|
97 | { \ |
---|
98 | (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ |
---|
99 | (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ |
---|
100 | if ((vvp)->tv_usec >= 1000000) \ |
---|
101 | { \ |
---|
102 | (vvp)->tv_sec++; \ |
---|
103 | (vvp)->tv_usec -= 1000000; \ |
---|
104 | } \ |
---|
105 | } while (0) |
---|
106 | #endif /* !timeradd */ |
---|
107 | |
---|
108 | #ifndef timercmp |
---|
109 | # define timercmp(tvp, uvp, cmp) \ |
---|
110 | (((tvp)->tv_sec == (uvp)->tv_sec) ? \ |
---|
111 | ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ |
---|
112 | ((tvp)->tv_sec cmp (uvp)->tv_sec)) |
---|
113 | #endif /* !timercmp */ |
---|
114 | |
---|
115 | extern bool Sm_IO_DidInit; |
---|
116 | |
---|
117 | /* Return true iff the given SM_FILE_T cannot be written now. */ |
---|
118 | #define cantwrite(fp) \ |
---|
119 | ((((fp)->f_flags & SMWR) == 0 || (fp)->f_bf.smb_base == NULL) && \ |
---|
120 | sm_wsetup(fp)) |
---|
121 | |
---|
122 | /* |
---|
123 | ** Test whether the given stdio file has an active ungetc buffer; |
---|
124 | ** release such a buffer, without restoring ordinary unread data. |
---|
125 | */ |
---|
126 | |
---|
127 | #define HASUB(fp) ((fp)->f_ub.smb_base != NULL) |
---|
128 | #define FREEUB(fp) \ |
---|
129 | { \ |
---|
130 | if ((fp)->f_ub.smb_base != (fp)->f_ubuf) \ |
---|
131 | sm_free((char *)(fp)->f_ub.smb_base); \ |
---|
132 | (fp)->f_ub.smb_base = NULL; \ |
---|
133 | } |
---|
134 | |
---|
135 | extern const char SmFileMagic[]; |
---|
136 | |
---|
137 | #define SM_ALIGN(p) (((unsigned long)(p) + SM_ALIGN_BITS) & ~SM_ALIGN_BITS) |
---|
138 | |
---|
139 | #define sm_io_flockfile(fp) ((void) 0) |
---|
140 | #define sm_io_funlockfile(fp) ((void) 0) |
---|
141 | |
---|
142 | #ifndef FDSET_CAST |
---|
143 | # define FDSET_CAST /* empty cast for fd_set arg to select */ |
---|
144 | #endif |
---|
145 | |
---|
146 | /* |
---|
147 | ** SM_CONVERT_TIME -- convert the API timeout flag for select() usage. |
---|
148 | ** |
---|
149 | ** This takes a 'fp' (a file type pointer) and obtains the "raw" |
---|
150 | ** file descriptor (fd) if possible. The 'fd' is needed to possibly |
---|
151 | ** switch the mode of the file (blocking/non-blocking) to match |
---|
152 | ** the type of timeout. If timeout is SM_TIME_FOREVER then the |
---|
153 | ** timeout using select won't be needed and the file is best placed |
---|
154 | ** in blocking mode. If there is to be a finite timeout then the file |
---|
155 | ** is best placed in non-blocking mode. Then, if not enough can be |
---|
156 | ** written, select() can be used to test when something can be written |
---|
157 | ** yet still timeout if the wait is too long. |
---|
158 | ** If the mode is already in the correct state we don't change it. |
---|
159 | ** Iff (yes "iff") the 'fd' is "-1" in value then the mode change |
---|
160 | ** will not happen. This situation arises when a late-binding-to-disk |
---|
161 | ** file type is in use. An example of this is the sendmail buffered |
---|
162 | ** file type (in sendmail/bf.c). |
---|
163 | ** |
---|
164 | ** Parameters |
---|
165 | ** fp -- the file pointer the timeout is for |
---|
166 | ** fd -- to become the file descriptor value from 'fp' |
---|
167 | ** val -- the timeout value to be converted |
---|
168 | ** time -- a struct timeval holding the converted value |
---|
169 | ** |
---|
170 | ** Returns |
---|
171 | ** nothing, this is flow-through code |
---|
172 | ** |
---|
173 | ** Side Effects: |
---|
174 | ** May or may not change the mode of a currently open file. |
---|
175 | ** The file mode may be changed to O_NONBLOCK or ~O_NONBLOCK |
---|
176 | ** (meaning block). This is done to best match the type of |
---|
177 | ** timeout and for (possible) use with select(). |
---|
178 | */ |
---|
179 | |
---|
180 | # define SM_CONVERT_TIME(fp, fd, val, time) { \ |
---|
181 | if (((fd) = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1) \ |
---|
182 | { \ |
---|
183 | /* can't get an fd, likely internal 'fake' fp */ \ |
---|
184 | errno = 0; \ |
---|
185 | } \ |
---|
186 | if ((val) == SM_TIME_DEFAULT) \ |
---|
187 | (val) = (fp)->f_timeout; \ |
---|
188 | if ((val) == SM_TIME_IMMEDIATE || (val) == SM_TIME_FOREVER) \ |
---|
189 | { \ |
---|
190 | (time)->tv_sec = 0; \ |
---|
191 | (time)->tv_usec = 0; \ |
---|
192 | } \ |
---|
193 | else \ |
---|
194 | { \ |
---|
195 | (time)->tv_sec = (val) / 1000; \ |
---|
196 | (time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 1000; \ |
---|
197 | } \ |
---|
198 | if ((val) == SM_TIME_FOREVER) \ |
---|
199 | { \ |
---|
200 | if ((fp)->f_timeoutstate == SM_TIME_NONBLOCK && (fd) != -1) \ |
---|
201 | { \ |
---|
202 | int ret; \ |
---|
203 | ret = fcntl((fd), F_GETFL, 0); \ |
---|
204 | if (ret == -1 || fcntl((fd), F_SETFL, \ |
---|
205 | ret & ~O_NONBLOCK) == -1) \ |
---|
206 | { \ |
---|
207 | /* errno should be set */ \ |
---|
208 | return SM_IO_EOF; \ |
---|
209 | } \ |
---|
210 | (fp)->f_timeoutstate = SM_TIME_BLOCK; \ |
---|
211 | if ((fp)->f_modefp != NULL) \ |
---|
212 | (fp)->f_modefp->f_timeoutstate = SM_TIME_BLOCK; \ |
---|
213 | } \ |
---|
214 | } \ |
---|
215 | else { \ |
---|
216 | if ((fp)->f_timeoutstate == SM_TIME_BLOCK && (fd) != -1) \ |
---|
217 | { \ |
---|
218 | int ret; \ |
---|
219 | ret = fcntl((fd), F_GETFL, 0); \ |
---|
220 | if (ret == -1 || fcntl((fd), F_SETFL, \ |
---|
221 | ret | O_NONBLOCK) == -1) \ |
---|
222 | { \ |
---|
223 | /* errno should be set */ \ |
---|
224 | return SM_IO_EOF; \ |
---|
225 | } \ |
---|
226 | (fp)->f_timeoutstate = SM_TIME_NONBLOCK; \ |
---|
227 | if ((fp)->f_modefp != NULL) \ |
---|
228 | (fp)->f_modefp->f_timeoutstate = SM_TIME_NONBLOCK; \ |
---|
229 | } \ |
---|
230 | } \ |
---|
231 | } |
---|
232 | |
---|
233 | /* |
---|
234 | ** SM_IO_WR_TIMEOUT -- setup the timeout for the write |
---|
235 | ** |
---|
236 | ** This #define uses a select() to wait for the 'fd' to become writable. |
---|
237 | ** The select() can be active for up to 'to' time. The select may not |
---|
238 | ** use all of the the 'to' time. Hence, the amount of "wall-clock" time is |
---|
239 | ** measured to decide how much to subtract from 'to' to update it. On some |
---|
240 | ** BSD-based/like systems the timeout for a select is updated for the |
---|
241 | ** amount of time used. On many/most systems this does not happen. Therefore |
---|
242 | ** the updating of 'to' must be done ourselves; a copy of 'to' is passed |
---|
243 | ** since a BSD-like system will have updated it and we don't want to |
---|
244 | ** double the time used! |
---|
245 | ** Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the |
---|
246 | ** sendmail buffered file type in sendmail/bf.c; see fvwrite.c). |
---|
247 | ** |
---|
248 | ** Parameters |
---|
249 | ** fd -- a file descriptor for doing select() with |
---|
250 | ** timeout -- the original user set value. |
---|
251 | ** |
---|
252 | ** Returns |
---|
253 | ** nothing, this is flow through code |
---|
254 | ** |
---|
255 | ** Side Effects: |
---|
256 | ** adjusts 'timeout' for time used |
---|
257 | */ |
---|
258 | |
---|
259 | #define SM_IO_WR_TIMEOUT(fp, fd, to) { \ |
---|
260 | struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \ |
---|
261 | struct timeval sm_io_to; \ |
---|
262 | int sm_io_to_sel; \ |
---|
263 | fd_set sm_io_to_mask, sm_io_x_mask; \ |
---|
264 | errno = 0; \ |
---|
265 | if ((to) == SM_TIME_DEFAULT) \ |
---|
266 | (to) = (fp)->f_timeout; \ |
---|
267 | if ((to) == SM_TIME_IMMEDIATE) \ |
---|
268 | { \ |
---|
269 | errno = EAGAIN; \ |
---|
270 | return SM_IO_EOF; \ |
---|
271 | } \ |
---|
272 | else if ((to) == SM_TIME_FOREVER) \ |
---|
273 | { \ |
---|
274 | errno = EINVAL; \ |
---|
275 | return SM_IO_EOF; \ |
---|
276 | } \ |
---|
277 | else \ |
---|
278 | { \ |
---|
279 | sm_io_to.tv_sec = (to) / 1000; \ |
---|
280 | sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 1000; \ |
---|
281 | } \ |
---|
282 | if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE) \ |
---|
283 | { \ |
---|
284 | errno = EINVAL; \ |
---|
285 | return SM_IO_EOF; \ |
---|
286 | } \ |
---|
287 | FD_ZERO(&sm_io_to_mask); \ |
---|
288 | FD_SET((fd), &sm_io_to_mask); \ |
---|
289 | FD_ZERO(&sm_io_x_mask); \ |
---|
290 | FD_SET((fd), &sm_io_x_mask); \ |
---|
291 | if (gettimeofday(&sm_io_to_before, NULL) < 0) \ |
---|
292 | return SM_IO_EOF; \ |
---|
293 | do \ |
---|
294 | { \ |
---|
295 | sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, \ |
---|
296 | &sm_io_x_mask, &sm_io_to); \ |
---|
297 | } while (sm_io_to_sel < 0 && errno == EINTR); \ |
---|
298 | if (sm_io_to_sel < 0) \ |
---|
299 | { \ |
---|
300 | /* something went wrong, errno set */ \ |
---|
301 | return SM_IO_EOF; \ |
---|
302 | } \ |
---|
303 | else if (sm_io_to_sel == 0) \ |
---|
304 | { \ |
---|
305 | /* timeout */ \ |
---|
306 | errno = EAGAIN; \ |
---|
307 | return SM_IO_EOF; \ |
---|
308 | } \ |
---|
309 | /* else loop again */ \ |
---|
310 | if (gettimeofday(&sm_io_to_after, NULL) < 0) \ |
---|
311 | return SM_IO_EOF; \ |
---|
312 | timersub(&sm_io_to_after, &sm_io_to_before, &sm_io_to_diff); \ |
---|
313 | (to) -= (sm_io_to_diff.tv_sec * 1000); \ |
---|
314 | (to) -= (sm_io_to_diff.tv_usec / 1000); \ |
---|
315 | if ((to) < 0) \ |
---|
316 | (to) = 0; \ |
---|
317 | } |
---|
318 | |
---|
319 | /* |
---|
320 | ** If there is no 'fd' just error (we can't timeout). If the timeout |
---|
321 | ** is SM_TIME_FOREVER then there is no need to do a timeout with |
---|
322 | ** select since this will be a real error. If the error is not |
---|
323 | ** EAGAIN/EWOULDBLOCK (from a nonblocking) then it's a real error. |
---|
324 | ** Specify the condition here as macro so it can be used in several places. |
---|
325 | */ |
---|
326 | |
---|
327 | #define IS_IO_ERROR(fd, ret, to) \ |
---|
328 | ((fd) < 0 || \ |
---|
329 | ((ret) < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || \ |
---|
330 | (to) == SM_TIME_FOREVER) |
---|
331 | |
---|