xref: /freebsd/contrib/sendmail/libsm/local.h (revision 4e4196cb7454f47341efebe4e0a17f1b8cd534c7)
1 /*
2  * Copyright (c) 2000-2002, 2004-2006 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.57 2006/02/28 18:48:25 ca Exp $
15  */
16 
17 /*
18 **  Information local to this implementation of stdio,
19 **  in particular, macros and private variables.
20 */
21 
22 #include <sm/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 extern bool Sm_IO_DidInit;
79 
80 /* Return true iff the given SM_FILE_T cannot be written now. */
81 #define cantwrite(fp) \
82 	((((fp)->f_flags & SMWR) == 0 || (fp)->f_bf.smb_base == NULL) && \
83 	 sm_wsetup(fp))
84 
85 /*
86 **  Test whether the given stdio file has an active ungetc buffer;
87 **   release such a buffer, without restoring ordinary unread data.
88 */
89 
90 #define HASUB(fp) ((fp)->f_ub.smb_base != NULL)
91 #define FREEUB(fp)					\
92 {							\
93 	if ((fp)->f_ub.smb_base != (fp)->f_ubuf)	\
94 		sm_free((char *)(fp)->f_ub.smb_base);	\
95 	(fp)->f_ub.smb_base = NULL;			\
96 }
97 
98 extern const char SmFileMagic[];
99 
100 #define SM_ALIGN(p)	(((unsigned long)(p) + SM_ALIGN_BITS) & ~SM_ALIGN_BITS)
101 
102 #define sm_io_flockfile(fp)	((void) 0)
103 #define sm_io_funlockfile(fp)	((void) 0)
104 
105 #ifndef FDSET_CAST
106 # define FDSET_CAST		/* empty cast for fd_set arg to select */
107 #endif
108 
109 /*
110 **  SM_CONVERT_TIME -- convert the API timeout flag for select() usage.
111 **
112 **	This takes a 'fp' (a file type pointer) and obtains the "raw"
113 **	file descriptor (fd) if possible. The 'fd' is needed to possibly
114 **	switch the mode of the file (blocking/non-blocking) to match
115 **	the type of timeout. If timeout is SM_TIME_FOREVER then the
116 **	timeout using select won't be needed and the file is best placed
117 **	in blocking mode. If there is to be a finite timeout then the file
118 **	is best placed in non-blocking mode. Then, if not enough can be
119 **	written, select() can be used to test when something can be written
120 **	yet still timeout if the wait is too long.
121 **	If the mode is already in the correct state we don't change it.
122 **	Iff (yes "iff") the 'fd' is "-1" in value then the mode change
123 **	will not happen. This situation arises when a late-binding-to-disk
124 **	file type is in use. An example of this is the sendmail buffered
125 **	file type (in sendmail/bf.c).
126 **
127 **	Parameters
128 **		fp -- the file pointer the timeout is for
129 **		fd -- to become the file descriptor value from 'fp'
130 **		val -- the timeout value to be converted
131 **		time -- a struct timeval holding the converted value
132 **
133 **	Returns
134 **		nothing, this is flow-through code
135 **
136 **	Side Effects:
137 **		May or may not change the mode of a currently open file.
138 **		The file mode may be changed to O_NONBLOCK or ~O_NONBLOCK
139 **		(meaning block). This is done to best match the type of
140 **		timeout and for (possible) use with select().
141 */
142 
143 # define SM_CONVERT_TIME(fp, fd, val, time) { \
144 	if (((fd) = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1) \
145 	{ \
146 		/* can't get an fd, likely internal 'fake' fp */ \
147 		errno = 0; \
148 	} \
149 	if ((val) == SM_TIME_DEFAULT) \
150 		(val) = (fp)->f_timeout; \
151 	if ((val) == SM_TIME_IMMEDIATE || (val) == SM_TIME_FOREVER) \
152 	{ \
153 		(time)->tv_sec = 0; \
154 		(time)->tv_usec = 0; \
155 	} \
156 	else \
157 	{ \
158 		(time)->tv_sec = (val) / 1000; \
159 		(time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 1000; \
160 	} \
161 	if ((val) == SM_TIME_FOREVER) \
162 	{ \
163 		if ((fp)->f_timeoutstate == SM_TIME_NONBLOCK && (fd) != -1) \
164 		{ \
165 			int ret; \
166 			ret = fcntl((fd), F_GETFL, 0); \
167 			if (ret == -1 || fcntl((fd), F_SETFL, \
168 					       ret & ~O_NONBLOCK) == -1) \
169 			{ \
170 				/* errno should be set */ \
171 				return SM_IO_EOF; \
172 			} \
173 			(fp)->f_timeoutstate = SM_TIME_BLOCK; \
174 			if ((fp)->f_modefp != NULL) \
175 				(fp)->f_modefp->f_timeoutstate = SM_TIME_BLOCK; \
176 		} \
177 	} \
178 	else { \
179 		if ((fp)->f_timeoutstate == SM_TIME_BLOCK && (fd) != -1) \
180 		{ \
181 			int ret; \
182 			ret = fcntl((fd), F_GETFL, 0); \
183 			if (ret == -1 || fcntl((fd), F_SETFL, \
184 					       ret | O_NONBLOCK) == -1) \
185 			{ \
186 				/* errno should be set */ \
187 				return SM_IO_EOF; \
188 			} \
189 			(fp)->f_timeoutstate = SM_TIME_NONBLOCK; \
190 			if ((fp)->f_modefp != NULL) \
191 				(fp)->f_modefp->f_timeoutstate = SM_TIME_NONBLOCK; \
192 		} \
193 	} \
194 }
195 
196 /*
197 **  SM_IO_WR_TIMEOUT -- setup the timeout for the write
198 **
199 **  This #define uses a select() to wait for the 'fd' to become writable.
200 **  The select() can be active for up to 'to' time. The select may not
201 **  use all of the the 'to' time. Hence, the amount of "wall-clock" time is
202 **  measured to decide how much to subtract from 'to' to update it. On some
203 **  BSD-based/like systems the timeout for a select is updated for the
204 **  amount of time used. On many/most systems this does not happen. Therefore
205 **  the updating of 'to' must be done ourselves; a copy of 'to' is passed
206 **  since a BSD-like system will have updated it and we don't want to
207 **  double the time used!
208 **  Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
209 **  sendmail buffered file type in sendmail/bf.c; see fvwrite.c).
210 **
211 **	Parameters
212 **		fd -- a file descriptor for doing select() with
213 **		timeout -- the original user set value.
214 **
215 **	Returns
216 **		nothing, this is flow through code
217 **
218 **	Side Effects:
219 **		adjusts 'timeout' for time used
220 */
221 
222 #define SM_IO_WR_TIMEOUT(fp, fd, to) { \
223 	struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \
224 	struct timeval sm_io_to; \
225 	int sm_io_to_sel; \
226 	fd_set sm_io_to_mask, sm_io_x_mask; \
227 	errno = 0; \
228 	if ((to) == SM_TIME_DEFAULT) \
229 		(to) = (fp)->f_timeout; \
230 	if ((to) == SM_TIME_IMMEDIATE) \
231 	{ \
232 		errno = EAGAIN; \
233 		return SM_IO_EOF; \
234 	} \
235 	else if ((to) == SM_TIME_FOREVER) \
236 	{ \
237 		errno = EINVAL; \
238 		return SM_IO_EOF; \
239 	} \
240 	else \
241 	{ \
242 		sm_io_to.tv_sec = (to) / 1000; \
243 		sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 1000; \
244 	} \
245 	if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE) \
246 	{ \
247 		errno = EINVAL; \
248 		return SM_IO_EOF; \
249 	} \
250 	FD_ZERO(&sm_io_to_mask); \
251 	FD_SET((fd), &sm_io_to_mask); \
252 	FD_ZERO(&sm_io_x_mask); \
253 	FD_SET((fd), &sm_io_x_mask); \
254 	if (gettimeofday(&sm_io_to_before, NULL) < 0) \
255 		return SM_IO_EOF; \
256 	do \
257 	{	\
258 		sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, \
259 					&sm_io_x_mask, &sm_io_to); \
260 	} while (sm_io_to_sel < 0 && errno == EINTR); \
261 	if (sm_io_to_sel < 0) \
262 	{ \
263 		/* something went wrong, errno set */ \
264 		return SM_IO_EOF; \
265 	} \
266 	else if (sm_io_to_sel == 0) \
267 	{ \
268 		/* timeout */ \
269 		errno = EAGAIN; \
270 		return SM_IO_EOF; \
271 	} \
272 	/* else loop again */ \
273 	if (gettimeofday(&sm_io_to_after, NULL) < 0) \
274 		return SM_IO_EOF; \
275 	timersub(&sm_io_to_after, &sm_io_to_before, &sm_io_to_diff); \
276 	(to) -= (sm_io_to_diff.tv_sec * 1000); \
277 	(to) -= (sm_io_to_diff.tv_usec / 1000); \
278 	if ((to) < 0) \
279 		(to) = 0; \
280 }
281 
282 /*
283 **  If there is no 'fd' just error (we can't timeout). If the timeout
284 **  is SM_TIME_FOREVER then there is no need to do a timeout with
285 **  select since this will be a real error.  If the error is not
286 **  EAGAIN/EWOULDBLOCK (from a nonblocking) then it's a real error.
287 **  Specify the condition here as macro so it can be used in several places.
288 */
289 
290 #define IS_IO_ERROR(fd, ret, to) \
291 	((fd) < 0 ||	\
292 	 ((ret) < 0 && errno != EAGAIN && errno != EWOULDBLOCK) ||	\
293 	 (to) == SM_TIME_FOREVER)
294 
295