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