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