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