xref: /illumos-gate/usr/src/cmd/sendmail/libsm/local.h (revision 058561cb)
17c478bd9Sstevel@tonic-gate /*
2445f2479Sjbeck  * Copyright (c) 2000-2002, 2004-2006 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *      All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1990, 1993
57c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
87c478bd9Sstevel@tonic-gate  * Chris Torek.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
117c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
127c478bd9Sstevel@tonic-gate  * the sendmail distribution.
137c478bd9Sstevel@tonic-gate  *
14*058561cbSjbeck  *	$Id: local.h,v 1.58 2006/12/19 19:44:23 ca Exp $
157c478bd9Sstevel@tonic-gate  */
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
187c478bd9Sstevel@tonic-gate 
197c478bd9Sstevel@tonic-gate /*
207c478bd9Sstevel@tonic-gate **  Information local to this implementation of stdio,
217c478bd9Sstevel@tonic-gate **  in particular, macros and private variables.
227c478bd9Sstevel@tonic-gate */
237c478bd9Sstevel@tonic-gate 
2449218d4fSjbeck #include <sm/time.h>
257c478bd9Sstevel@tonic-gate #if !SM_CONF_MEMCHR
267c478bd9Sstevel@tonic-gate # include <memory.h>
277c478bd9Sstevel@tonic-gate #endif /* !SM_CONF_MEMCHR */
287c478bd9Sstevel@tonic-gate #include <sm/heap.h>
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate int	sm_flush __P((SM_FILE_T *, int *));
317c478bd9Sstevel@tonic-gate SM_FILE_T	*smfp __P((void));
327c478bd9Sstevel@tonic-gate int	sm_refill __P((SM_FILE_T *, int));
337c478bd9Sstevel@tonic-gate void	sm_init __P((void));
347c478bd9Sstevel@tonic-gate void	sm_cleanup __P((void));
357c478bd9Sstevel@tonic-gate void	sm_makebuf __P((SM_FILE_T *));
367c478bd9Sstevel@tonic-gate int	sm_whatbuf __P((SM_FILE_T *, size_t *, int *));
377c478bd9Sstevel@tonic-gate int	sm_fwalk __P((int (*)(SM_FILE_T *, int *), int *));
387c478bd9Sstevel@tonic-gate int	sm_wsetup __P((SM_FILE_T *));
397c478bd9Sstevel@tonic-gate int	sm_flags __P((int));
407c478bd9Sstevel@tonic-gate SM_FILE_T	*sm_fp __P((const SM_FILE_T *, const int, SM_FILE_T *));
417c478bd9Sstevel@tonic-gate int	sm_vprintf __P((int, char const *, va_list));
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /* std io functions */
447c478bd9Sstevel@tonic-gate ssize_t	sm_stdread __P((SM_FILE_T *, char *, size_t));
457c478bd9Sstevel@tonic-gate ssize_t	sm_stdwrite __P((SM_FILE_T *, char const *, size_t));
467c478bd9Sstevel@tonic-gate off_t	sm_stdseek __P((SM_FILE_T *, off_t, int));
477c478bd9Sstevel@tonic-gate int	sm_stdclose __P((SM_FILE_T *));
487c478bd9Sstevel@tonic-gate int	sm_stdopen __P((SM_FILE_T *, const void *, int, const void *));
497c478bd9Sstevel@tonic-gate int	sm_stdfdopen __P((SM_FILE_T *, const void *, int, const void *));
507c478bd9Sstevel@tonic-gate int	sm_stdsetinfo __P((SM_FILE_T *, int , void *));
517c478bd9Sstevel@tonic-gate int	sm_stdgetinfo __P((SM_FILE_T *, int , void *));
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* stdio io functions */
547c478bd9Sstevel@tonic-gate ssize_t	sm_stdioread __P((SM_FILE_T *, char *, size_t));
557c478bd9Sstevel@tonic-gate ssize_t	sm_stdiowrite __P((SM_FILE_T *, char const *, size_t));
567c478bd9Sstevel@tonic-gate off_t	sm_stdioseek __P((SM_FILE_T *, off_t, int));
577c478bd9Sstevel@tonic-gate int	sm_stdioclose __P((SM_FILE_T *));
587c478bd9Sstevel@tonic-gate int	sm_stdioopen __P((SM_FILE_T *, const void *, int, const void *));
597c478bd9Sstevel@tonic-gate int	sm_stdiosetinfo __P((SM_FILE_T *, int , void *));
607c478bd9Sstevel@tonic-gate int	sm_stdiogetinfo __P((SM_FILE_T *, int , void *));
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /* string io functions */
637c478bd9Sstevel@tonic-gate ssize_t	sm_strread __P((SM_FILE_T *, char *, size_t));
647c478bd9Sstevel@tonic-gate ssize_t	sm_strwrite __P((SM_FILE_T *, char const *, size_t));
657c478bd9Sstevel@tonic-gate off_t	sm_strseek __P((SM_FILE_T *, off_t, int));
667c478bd9Sstevel@tonic-gate int	sm_strclose __P((SM_FILE_T *));
677c478bd9Sstevel@tonic-gate int	sm_stropen __P((SM_FILE_T *, const void *, int, const void *));
687c478bd9Sstevel@tonic-gate int	sm_strsetinfo __P((SM_FILE_T *, int , void *));
697c478bd9Sstevel@tonic-gate int	sm_strgetinfo __P((SM_FILE_T *, int , void *));
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /* syslog io functions */
727c478bd9Sstevel@tonic-gate ssize_t	sm_syslogread __P((SM_FILE_T *, char *, size_t));
737c478bd9Sstevel@tonic-gate ssize_t	sm_syslogwrite __P((SM_FILE_T *, char const *, size_t));
747c478bd9Sstevel@tonic-gate off_t	sm_syslogseek __P((SM_FILE_T *, off_t, int));
757c478bd9Sstevel@tonic-gate int	sm_syslogclose __P((SM_FILE_T *));
767c478bd9Sstevel@tonic-gate int	sm_syslogopen __P((SM_FILE_T *, const void *, int, const void *));
777c478bd9Sstevel@tonic-gate int	sm_syslogsetinfo __P((SM_FILE_T *, int , void *));
787c478bd9Sstevel@tonic-gate int	sm_sysloggetinfo __P((SM_FILE_T *, int , void *));
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate extern bool Sm_IO_DidInit;
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /* Return true iff the given SM_FILE_T cannot be written now. */
837c478bd9Sstevel@tonic-gate #define cantwrite(fp) \
847c478bd9Sstevel@tonic-gate 	((((fp)->f_flags & SMWR) == 0 || (fp)->f_bf.smb_base == NULL) && \
857c478bd9Sstevel@tonic-gate 	 sm_wsetup(fp))
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate **  Test whether the given stdio file has an active ungetc buffer;
897c478bd9Sstevel@tonic-gate **   release such a buffer, without restoring ordinary unread data.
907c478bd9Sstevel@tonic-gate */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate #define HASUB(fp) ((fp)->f_ub.smb_base != NULL)
937c478bd9Sstevel@tonic-gate #define FREEUB(fp)					\
947c478bd9Sstevel@tonic-gate {							\
957c478bd9Sstevel@tonic-gate 	if ((fp)->f_ub.smb_base != (fp)->f_ubuf)	\
967c478bd9Sstevel@tonic-gate 		sm_free((char *)(fp)->f_ub.smb_base);	\
977c478bd9Sstevel@tonic-gate 	(fp)->f_ub.smb_base = NULL;			\
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate extern const char SmFileMagic[];
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #define SM_ALIGN(p)	(((unsigned long)(p) + SM_ALIGN_BITS) & ~SM_ALIGN_BITS)
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate #define sm_io_flockfile(fp)	((void) 0)
1057c478bd9Sstevel@tonic-gate #define sm_io_funlockfile(fp)	((void) 0)
1067c478bd9Sstevel@tonic-gate 
107*058561cbSjbeck int sm_flags __P((int));
108*058561cbSjbeck 
1097c478bd9Sstevel@tonic-gate #ifndef FDSET_CAST
1107c478bd9Sstevel@tonic-gate # define FDSET_CAST		/* empty cast for fd_set arg to select */
1117c478bd9Sstevel@tonic-gate #endif
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate **  SM_CONVERT_TIME -- convert the API timeout flag for select() usage.
1157c478bd9Sstevel@tonic-gate **
1167c478bd9Sstevel@tonic-gate **	This takes a 'fp' (a file type pointer) and obtains the "raw"
1177c478bd9Sstevel@tonic-gate **	file descriptor (fd) if possible. The 'fd' is needed to possibly
1187c478bd9Sstevel@tonic-gate **	switch the mode of the file (blocking/non-blocking) to match
1197c478bd9Sstevel@tonic-gate **	the type of timeout. If timeout is SM_TIME_FOREVER then the
1207c478bd9Sstevel@tonic-gate **	timeout using select won't be needed and the file is best placed
1217c478bd9Sstevel@tonic-gate **	in blocking mode. If there is to be a finite timeout then the file
1227c478bd9Sstevel@tonic-gate **	is best placed in non-blocking mode. Then, if not enough can be
1237c478bd9Sstevel@tonic-gate **	written, select() can be used to test when something can be written
1247c478bd9Sstevel@tonic-gate **	yet still timeout if the wait is too long.
1257c478bd9Sstevel@tonic-gate **	If the mode is already in the correct state we don't change it.
1267c478bd9Sstevel@tonic-gate **	Iff (yes "iff") the 'fd' is "-1" in value then the mode change
1277c478bd9Sstevel@tonic-gate **	will not happen. This situation arises when a late-binding-to-disk
1287c478bd9Sstevel@tonic-gate **	file type is in use. An example of this is the sendmail buffered
1297c478bd9Sstevel@tonic-gate **	file type (in sendmail/bf.c).
1307c478bd9Sstevel@tonic-gate **
1317c478bd9Sstevel@tonic-gate **	Parameters
1327c478bd9Sstevel@tonic-gate **		fp -- the file pointer the timeout is for
1337c478bd9Sstevel@tonic-gate **		fd -- to become the file descriptor value from 'fp'
1347c478bd9Sstevel@tonic-gate **		val -- the timeout value to be converted
1357c478bd9Sstevel@tonic-gate **		time -- a struct timeval holding the converted value
1367c478bd9Sstevel@tonic-gate **
1377c478bd9Sstevel@tonic-gate **	Returns
1387c478bd9Sstevel@tonic-gate **		nothing, this is flow-through code
1397c478bd9Sstevel@tonic-gate **
1407c478bd9Sstevel@tonic-gate **	Side Effects:
1417c478bd9Sstevel@tonic-gate **		May or may not change the mode of a currently open file.
1427c478bd9Sstevel@tonic-gate **		The file mode may be changed to O_NONBLOCK or ~O_NONBLOCK
1437c478bd9Sstevel@tonic-gate **		(meaning block). This is done to best match the type of
1447c478bd9Sstevel@tonic-gate **		timeout and for (possible) use with select().
1457c478bd9Sstevel@tonic-gate */
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate # define SM_CONVERT_TIME(fp, fd, val, time) { \
1487c478bd9Sstevel@tonic-gate 	if (((fd) = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1) \
1497c478bd9Sstevel@tonic-gate 	{ \
1507c478bd9Sstevel@tonic-gate 		/* can't get an fd, likely internal 'fake' fp */ \
1517c478bd9Sstevel@tonic-gate 		errno = 0; \
1527c478bd9Sstevel@tonic-gate 	} \
1537c478bd9Sstevel@tonic-gate 	if ((val) == SM_TIME_DEFAULT) \
1547c478bd9Sstevel@tonic-gate 		(val) = (fp)->f_timeout; \
1557c478bd9Sstevel@tonic-gate 	if ((val) == SM_TIME_IMMEDIATE || (val) == SM_TIME_FOREVER) \
1567c478bd9Sstevel@tonic-gate 	{ \
1577c478bd9Sstevel@tonic-gate 		(time)->tv_sec = 0; \
1587c478bd9Sstevel@tonic-gate 		(time)->tv_usec = 0; \
1597c478bd9Sstevel@tonic-gate 	} \
1607c478bd9Sstevel@tonic-gate 	else \
1617c478bd9Sstevel@tonic-gate 	{ \
1627c478bd9Sstevel@tonic-gate 		(time)->tv_sec = (val) / 1000; \
163445f2479Sjbeck 		(time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 1000; \
1647c478bd9Sstevel@tonic-gate 	} \
1657c478bd9Sstevel@tonic-gate 	if ((val) == SM_TIME_FOREVER) \
1667c478bd9Sstevel@tonic-gate 	{ \
1677c478bd9Sstevel@tonic-gate 		if ((fp)->f_timeoutstate == SM_TIME_NONBLOCK && (fd) != -1) \
1687c478bd9Sstevel@tonic-gate 		{ \
1697c478bd9Sstevel@tonic-gate 			int ret; \
1707c478bd9Sstevel@tonic-gate 			ret = fcntl((fd), F_GETFL, 0); \
1717c478bd9Sstevel@tonic-gate 			if (ret == -1 || fcntl((fd), F_SETFL, \
1727c478bd9Sstevel@tonic-gate 					       ret & ~O_NONBLOCK) == -1) \
1737c478bd9Sstevel@tonic-gate 			{ \
1747c478bd9Sstevel@tonic-gate 				/* errno should be set */ \
1757c478bd9Sstevel@tonic-gate 				return SM_IO_EOF; \
1767c478bd9Sstevel@tonic-gate 			} \
1777c478bd9Sstevel@tonic-gate 			(fp)->f_timeoutstate = SM_TIME_BLOCK; \
1787c478bd9Sstevel@tonic-gate 			if ((fp)->f_modefp != NULL) \
1797c478bd9Sstevel@tonic-gate 				(fp)->f_modefp->f_timeoutstate = SM_TIME_BLOCK; \
1807c478bd9Sstevel@tonic-gate 		} \
1817c478bd9Sstevel@tonic-gate 	} \
1827c478bd9Sstevel@tonic-gate 	else { \
1837c478bd9Sstevel@tonic-gate 		if ((fp)->f_timeoutstate == SM_TIME_BLOCK && (fd) != -1) \
1847c478bd9Sstevel@tonic-gate 		{ \
1857c478bd9Sstevel@tonic-gate 			int ret; \
1867c478bd9Sstevel@tonic-gate 			ret = fcntl((fd), F_GETFL, 0); \
1877c478bd9Sstevel@tonic-gate 			if (ret == -1 || fcntl((fd), F_SETFL, \
1887c478bd9Sstevel@tonic-gate 					       ret | O_NONBLOCK) == -1) \
1897c478bd9Sstevel@tonic-gate 			{ \
1907c478bd9Sstevel@tonic-gate 				/* errno should be set */ \
1917c478bd9Sstevel@tonic-gate 				return SM_IO_EOF; \
1927c478bd9Sstevel@tonic-gate 			} \
1937c478bd9Sstevel@tonic-gate 			(fp)->f_timeoutstate = SM_TIME_NONBLOCK; \
1947c478bd9Sstevel@tonic-gate 			if ((fp)->f_modefp != NULL) \
1957c478bd9Sstevel@tonic-gate 				(fp)->f_modefp->f_timeoutstate = SM_TIME_NONBLOCK; \
1967c478bd9Sstevel@tonic-gate 		} \
1977c478bd9Sstevel@tonic-gate 	} \
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate **  SM_IO_WR_TIMEOUT -- setup the timeout for the write
2027c478bd9Sstevel@tonic-gate **
2037c478bd9Sstevel@tonic-gate **  This #define uses a select() to wait for the 'fd' to become writable.
2047c478bd9Sstevel@tonic-gate **  The select() can be active for up to 'to' time. The select may not
2057c478bd9Sstevel@tonic-gate **  use all of the the 'to' time. Hence, the amount of "wall-clock" time is
2067c478bd9Sstevel@tonic-gate **  measured to decide how much to subtract from 'to' to update it. On some
2077c478bd9Sstevel@tonic-gate **  BSD-based/like systems the timeout for a select is updated for the
2087c478bd9Sstevel@tonic-gate **  amount of time used. On many/most systems this does not happen. Therefore
2097c478bd9Sstevel@tonic-gate **  the updating of 'to' must be done ourselves; a copy of 'to' is passed
2107c478bd9Sstevel@tonic-gate **  since a BSD-like system will have updated it and we don't want to
2117c478bd9Sstevel@tonic-gate **  double the time used!
2127c478bd9Sstevel@tonic-gate **  Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
2137c478bd9Sstevel@tonic-gate **  sendmail buffered file type in sendmail/bf.c; see fvwrite.c).
2147c478bd9Sstevel@tonic-gate **
2157c478bd9Sstevel@tonic-gate **	Parameters
2167c478bd9Sstevel@tonic-gate **		fd -- a file descriptor for doing select() with
2177c478bd9Sstevel@tonic-gate **		timeout -- the original user set value.
2187c478bd9Sstevel@tonic-gate **
2197c478bd9Sstevel@tonic-gate **	Returns
2207c478bd9Sstevel@tonic-gate **		nothing, this is flow through code
2217c478bd9Sstevel@tonic-gate **
2227c478bd9Sstevel@tonic-gate **	Side Effects:
2237c478bd9Sstevel@tonic-gate **		adjusts 'timeout' for time used
2247c478bd9Sstevel@tonic-gate */
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate #define SM_IO_WR_TIMEOUT(fp, fd, to) { \
2277c478bd9Sstevel@tonic-gate 	struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \
2287c478bd9Sstevel@tonic-gate 	struct timeval sm_io_to; \
2297c478bd9Sstevel@tonic-gate 	int sm_io_to_sel; \
2307c478bd9Sstevel@tonic-gate 	fd_set sm_io_to_mask, sm_io_x_mask; \
2317c478bd9Sstevel@tonic-gate 	errno = 0; \
2327c478bd9Sstevel@tonic-gate 	if ((to) == SM_TIME_DEFAULT) \
2337c478bd9Sstevel@tonic-gate 		(to) = (fp)->f_timeout; \
2347c478bd9Sstevel@tonic-gate 	if ((to) == SM_TIME_IMMEDIATE) \
2357c478bd9Sstevel@tonic-gate 	{ \
2367c478bd9Sstevel@tonic-gate 		errno = EAGAIN; \
2377c478bd9Sstevel@tonic-gate 		return SM_IO_EOF; \
2387c478bd9Sstevel@tonic-gate 	} \
2397c478bd9Sstevel@tonic-gate 	else if ((to) == SM_TIME_FOREVER) \
2407c478bd9Sstevel@tonic-gate 	{ \
2417c478bd9Sstevel@tonic-gate 		errno = EINVAL; \
2427c478bd9Sstevel@tonic-gate 		return SM_IO_EOF; \
2437c478bd9Sstevel@tonic-gate 	} \
2447c478bd9Sstevel@tonic-gate 	else \
2457c478bd9Sstevel@tonic-gate 	{ \
2467c478bd9Sstevel@tonic-gate 		sm_io_to.tv_sec = (to) / 1000; \
247445f2479Sjbeck 		sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 1000; \
2487c478bd9Sstevel@tonic-gate 	} \
2497c478bd9Sstevel@tonic-gate 	if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE) \
2507c478bd9Sstevel@tonic-gate 	{ \
2517c478bd9Sstevel@tonic-gate 		errno = EINVAL; \
2527c478bd9Sstevel@tonic-gate 		return SM_IO_EOF; \
2537c478bd9Sstevel@tonic-gate 	} \
2547c478bd9Sstevel@tonic-gate 	FD_ZERO(&sm_io_to_mask); \
2557c478bd9Sstevel@tonic-gate 	FD_SET((fd), &sm_io_to_mask); \
2567c478bd9Sstevel@tonic-gate 	FD_ZERO(&sm_io_x_mask); \
2577c478bd9Sstevel@tonic-gate 	FD_SET((fd), &sm_io_x_mask); \
2587c478bd9Sstevel@tonic-gate 	if (gettimeofday(&sm_io_to_before, NULL) < 0) \
2597c478bd9Sstevel@tonic-gate 		return SM_IO_EOF; \
260445f2479Sjbeck 	do \
261445f2479Sjbeck 	{	\
262445f2479Sjbeck 		sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, \
263445f2479Sjbeck 					&sm_io_x_mask, &sm_io_to); \
264445f2479Sjbeck 	} while (sm_io_to_sel < 0 && errno == EINTR); \
2657c478bd9Sstevel@tonic-gate 	if (sm_io_to_sel < 0) \
2667c478bd9Sstevel@tonic-gate 	{ \
2677c478bd9Sstevel@tonic-gate 		/* something went wrong, errno set */ \
2687c478bd9Sstevel@tonic-gate 		return SM_IO_EOF; \
2697c478bd9Sstevel@tonic-gate 	} \
2707c478bd9Sstevel@tonic-gate 	else if (sm_io_to_sel == 0) \
2717c478bd9Sstevel@tonic-gate 	{ \
2727c478bd9Sstevel@tonic-gate 		/* timeout */ \
2737c478bd9Sstevel@tonic-gate 		errno = EAGAIN; \
2747c478bd9Sstevel@tonic-gate 		return SM_IO_EOF; \
2757c478bd9Sstevel@tonic-gate 	} \
2767c478bd9Sstevel@tonic-gate 	/* else loop again */ \
2777c478bd9Sstevel@tonic-gate 	if (gettimeofday(&sm_io_to_after, NULL) < 0) \
2787c478bd9Sstevel@tonic-gate 		return SM_IO_EOF; \
279445f2479Sjbeck 	timersub(&sm_io_to_after, &sm_io_to_before, &sm_io_to_diff); \
280445f2479Sjbeck 	(to) -= (sm_io_to_diff.tv_sec * 1000); \
281445f2479Sjbeck 	(to) -= (sm_io_to_diff.tv_usec / 1000); \
2827c478bd9Sstevel@tonic-gate 	if ((to) < 0) \
2837c478bd9Sstevel@tonic-gate 		(to) = 0; \
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate /*
2877c478bd9Sstevel@tonic-gate **  If there is no 'fd' just error (we can't timeout). If the timeout
2887c478bd9Sstevel@tonic-gate **  is SM_TIME_FOREVER then there is no need to do a timeout with
2897c478bd9Sstevel@tonic-gate **  select since this will be a real error.  If the error is not
2907c478bd9Sstevel@tonic-gate **  EAGAIN/EWOULDBLOCK (from a nonblocking) then it's a real error.
2917c478bd9Sstevel@tonic-gate **  Specify the condition here as macro so it can be used in several places.
2927c478bd9Sstevel@tonic-gate */
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate #define IS_IO_ERROR(fd, ret, to) \
2957c478bd9Sstevel@tonic-gate 	((fd) < 0 ||	\
2967c478bd9Sstevel@tonic-gate 	 ((ret) < 0 && errno != EAGAIN && errno != EWOULDBLOCK) ||	\
2977c478bd9Sstevel@tonic-gate 	 (to) == SM_TIME_FOREVER)
2987c478bd9Sstevel@tonic-gate 
299