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