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