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