source: trunk/third/sendmail/libsm/local.h @ 22421

Revision 22421, 10.4 KB checked in by zacheiss, 19 years ago (diff)
Apply patches from 3-22-06 CERT advisory.
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 *      $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
28int     sm_flush __P((SM_FILE_T *, int *));
29SM_FILE_T       *smfp __P((void));
30int     sm_refill __P((SM_FILE_T *, int));
31void    sm_init __P((void));
32void    sm_cleanup __P((void));
33void    sm_makebuf __P((SM_FILE_T *));
34int     sm_whatbuf __P((SM_FILE_T *, size_t *, int *));
35int     sm_fwalk __P((int (*)(SM_FILE_T *, int *), int *));
36int     sm_wsetup __P((SM_FILE_T *));
37int     sm_flags __P((int));
38SM_FILE_T       *sm_fp __P((const SM_FILE_T *, const int, SM_FILE_T *));
39int     sm_vprintf __P((int, char const *, va_list));
40int     sm_vfscanf __P((SM_FILE_T *, int, char const *, va_list));
41
42/* std io functions */
43ssize_t sm_stdread __P((SM_FILE_T *, char *, size_t));
44ssize_t sm_stdwrite __P((SM_FILE_T *, char const *, size_t));
45off_t   sm_stdseek __P((SM_FILE_T *, off_t, int));
46int     sm_stdclose __P((SM_FILE_T *));
47int     sm_stdopen __P((SM_FILE_T *, const void *, int, const void *));
48int     sm_stdfdopen __P((SM_FILE_T *, const void *, int, const void *));
49int     sm_stdsetinfo __P((SM_FILE_T *, int , void *));
50int     sm_stdgetinfo __P((SM_FILE_T *, int , void *));
51
52/* stdio io functions */
53ssize_t sm_stdioread __P((SM_FILE_T *, char *, size_t));
54ssize_t sm_stdiowrite __P((SM_FILE_T *, char const *, size_t));
55off_t   sm_stdioseek __P((SM_FILE_T *, off_t, int));
56int     sm_stdioclose __P((SM_FILE_T *));
57int     sm_stdioopen __P((SM_FILE_T *, const void *, int, const void *));
58int     sm_stdiosetinfo __P((SM_FILE_T *, int , void *));
59int     sm_stdiogetinfo __P((SM_FILE_T *, int , void *));
60
61/* string io functions */
62ssize_t sm_strread __P((SM_FILE_T *, char *, size_t));
63ssize_t sm_strwrite __P((SM_FILE_T *, char const *, size_t));
64off_t   sm_strseek __P((SM_FILE_T *, off_t, int));
65int     sm_strclose __P((SM_FILE_T *));
66int     sm_stropen __P((SM_FILE_T *, const void *, int, const void *));
67int     sm_strsetinfo __P((SM_FILE_T *, int , void *));
68int     sm_strgetinfo __P((SM_FILE_T *, int , void *));
69
70/* syslog io functions */
71ssize_t sm_syslogread __P((SM_FILE_T *, char *, size_t));
72ssize_t sm_syslogwrite __P((SM_FILE_T *, char const *, size_t));
73off_t   sm_syslogseek __P((SM_FILE_T *, off_t, int));
74int     sm_syslogclose __P((SM_FILE_T *));
75int     sm_syslogopen __P((SM_FILE_T *, const void *, int, const void *));
76int     sm_syslogsetinfo __P((SM_FILE_T *, int , void *));
77int     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
115extern 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
135extern 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
Note: See TracBrowser for help on using the repository browser.