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