120253Sjoerg/* 220302Sjoerg * Copyright (c) 2000-2002, 2004-2006 Proofpoint, Inc. and its suppliers. 320302Sjoerg * All rights reserved. 420253Sjoerg * Copyright (c) 1990, 1993 520253Sjoerg * The Regents of the University of California. All rights reserved. 620253Sjoerg * 720253Sjoerg * This code is derived from software contributed to Berkeley by 820253Sjoerg * Chris Torek. 920302Sjoerg * 1020253Sjoerg * By using this file, you agree to the terms and conditions set 1120253Sjoerg * forth in the LICENSE file which can be found at the top level of 1220253Sjoerg * the sendmail distribution. 1320253Sjoerg * 1420302Sjoerg * $Id: local.h,v 1.59 2013-11-22 20:51:43 ca Exp $ 1520253Sjoerg */ 1620253Sjoerg 1720302Sjoerg/* 1820253Sjoerg** Information local to this implementation of stdio, 1920253Sjoerg** in particular, macros and private variables. 2020253Sjoerg*/ 2120253Sjoerg 2220253Sjoerg#include <sm/time.h> 2320253Sjoerg#if !SM_CONF_MEMCHR 2420253Sjoerg# include <memory.h> 2520253Sjoerg#endif /* !SM_CONF_MEMCHR */ 2620253Sjoerg#include <sm/heap.h> 2730259Scharnier 2830259Scharnierint sm_flush __P((SM_FILE_T *, int *)); 2950479SpeterSM_FILE_T *smfp __P((void)); 3030259Scharnierint sm_refill __P((SM_FILE_T *, int)); 3130259Scharniervoid sm_init __P((void)); 3220253Sjoergvoid sm_cleanup __P((void)); 3330259Scharniervoid sm_makebuf __P((SM_FILE_T *)); 3420253Sjoergint sm_whatbuf __P((SM_FILE_T *, size_t *, int *)); 3530259Scharnierint sm_fwalk __P((int (*)(SM_FILE_T *, int *), int *)); 3620253Sjoergint sm_wsetup __P((SM_FILE_T *)); 3720253Sjoergint sm_flags __P((int)); 3820253SjoergSM_FILE_T *sm_fp __P((const SM_FILE_T *, const int, SM_FILE_T *)); 3920253Sjoergint sm_vprintf __P((int, char const *, va_list)); 4020253Sjoerg 4120253Sjoerg/* std io functions */ 4220253Sjoergssize_t sm_stdread __P((SM_FILE_T *, char *, size_t)); 4320253Sjoergssize_t sm_stdwrite __P((SM_FILE_T *, char const *, size_t)); 4420253Sjoergoff_t sm_stdseek __P((SM_FILE_T *, off_t, int)); 4520253Sjoergint sm_stdclose __P((SM_FILE_T *)); 4620253Sjoergint sm_stdopen __P((SM_FILE_T *, const void *, int, const void *)); 4752502Sdavidnint sm_stdfdopen __P((SM_FILE_T *, const void *, int, const void *)); 4820253Sjoergint sm_stdsetinfo __P((SM_FILE_T *, int , void *)); 4920253Sjoergint sm_stdgetinfo __P((SM_FILE_T *, int , void *)); 5020253Sjoerg 5120253Sjoerg/* stdio io functions */ 5220747Sdavidnssize_t sm_stdioread __P((SM_FILE_T *, char *, size_t)); 5352502Sdavidnssize_t sm_stdiowrite __P((SM_FILE_T *, char const *, size_t)); 5420253Sjoergoff_t sm_stdioseek __P((SM_FILE_T *, off_t, int)); 5520253Sjoergint sm_stdioclose __P((SM_FILE_T *)); 5620253Sjoergint sm_stdioopen __P((SM_FILE_T *, const void *, int, const void *)); 5720253Sjoergint sm_stdiosetinfo __P((SM_FILE_T *, int , void *)); 5820253Sjoergint sm_stdiogetinfo __P((SM_FILE_T *, int , void *)); 5920253Sjoerg 6020253Sjoerg/* string io functions */ 6120253Sjoergssize_t sm_strread __P((SM_FILE_T *, char *, size_t)); 6220253Sjoergssize_t sm_strwrite __P((SM_FILE_T *, char const *, size_t)); 6352512Sdavidnoff_t sm_strseek __P((SM_FILE_T *, off_t, int)); 6452512Sdavidnint sm_strclose __P((SM_FILE_T *)); 6552512Sdavidnint sm_stropen __P((SM_FILE_T *, const void *, int, const void *)); 6620267Sjoergint sm_strsetinfo __P((SM_FILE_T *, int , void *)); 6720267Sjoergint sm_strgetinfo __P((SM_FILE_T *, int , void *)); 6820267Sjoerg 6920267Sjoerg/* syslog io functions */ 7052512Sdavidnssize_t sm_syslogread __P((SM_FILE_T *, char *, size_t)); 7120267Sjoergssize_t sm_syslogwrite __P((SM_FILE_T *, char const *, size_t)); 7220267Sjoergoff_t sm_syslogseek __P((SM_FILE_T *, off_t, int)); 7320267Sjoergint sm_syslogclose __P((SM_FILE_T *)); 7420267Sjoergint sm_syslogopen __P((SM_FILE_T *, const void *, int, const void *)); 7520267Sjoergint sm_syslogsetinfo __P((SM_FILE_T *, int , void *)); 7620267Sjoergint sm_sysloggetinfo __P((SM_FILE_T *, int , void *)); 7720267Sjoerg 7820253Sjoergextern bool Sm_IO_DidInit; 7920267Sjoerg 8020253Sjoerg/* Return true iff the given SM_FILE_T cannot be written now. */ 8144229Sdavidn#define cantwrite(fp) \ 8244229Sdavidn ((((fp)->f_flags & SMWR) == 0 || (fp)->f_bf.smb_base == NULL) && \ 8320253Sjoerg sm_wsetup(fp)) 8444229Sdavidn 8520267Sjoerg/* 8620253Sjoerg** Test whether the given stdio file has an active ungetc buffer; 8720253Sjoerg** release such a buffer, without restoring ordinary unread data. 8820253Sjoerg*/ 8930259Scharnier 9020253Sjoerg#define HASUB(fp) ((fp)->f_ub.smb_base != NULL) 9120253Sjoerg#define FREEUB(fp) \ 9220253Sjoerg{ \ 9320253Sjoerg if ((fp)->f_ub.smb_base != (fp)->f_ubuf) \ 9420253Sjoerg sm_free((char *)(fp)->f_ub.smb_base); \ 9520253Sjoerg (fp)->f_ub.smb_base = NULL; \ 9644229Sdavidn} 9720253Sjoerg 9820253Sjoergextern const char SmFileMagic[]; 9920253Sjoerg 10044229Sdavidn#define SM_ALIGN(p) (((unsigned long)(p) + SM_ALIGN_BITS) & ~SM_ALIGN_BITS) 10120253Sjoerg 10220253Sjoerg#define sm_io_flockfile(fp) ((void) 0) 10320253Sjoerg#define sm_io_funlockfile(fp) ((void) 0) 10420747Sdavidn 10520747Sdavidnint sm_flags __P((int)); 10620253Sjoerg 10720253Sjoerg#ifndef FDSET_CAST 10820747Sdavidn# define FDSET_CAST /* empty cast for fd_set arg to select */ 10920267Sjoerg#endif 11020253Sjoerg 11130259Scharnier/* 11220253Sjoerg** SM_CONVERT_TIME -- convert the API timeout flag for select() usage. 11320253Sjoerg** 11420253Sjoerg** This takes a 'fp' (a file type pointer) and obtains the "raw" 11520253Sjoerg** file descriptor (fd) if possible. The 'fd' is needed to possibly 11620253Sjoerg** switch the mode of the file (blocking/non-blocking) to match 11720253Sjoerg** the type of timeout. If timeout is SM_TIME_FOREVER then the 11820253Sjoerg** timeout using select won't be needed and the file is best placed 11920253Sjoerg** in blocking mode. If there is to be a finite timeout then the file 12020253Sjoerg** is best placed in non-blocking mode. Then, if not enough can be 12120253Sjoerg** written, select() can be used to test when something can be written 12252502Sdavidn** yet still timeout if the wait is too long. 12352502Sdavidn** If the mode is already in the correct state we don't change it. 12452502Sdavidn** Iff (yes "iff") the 'fd' is "-1" in value then the mode change 12552502Sdavidn** will not happen. This situation arises when a late-binding-to-disk 12656000Sdavidn** file type is in use. An example of this is the sendmail buffered 12752502Sdavidn** file type (in sendmail/bf.c). 12852502Sdavidn** 12920253Sjoerg** Parameters 13020267Sjoerg** fp -- the file pointer the timeout is for 13120253Sjoerg** fd -- to become the file descriptor value from 'fp' 13220267Sjoerg** val -- the timeout value to be converted 13320253Sjoerg** time -- a struct timeval holding the converted value 13420253Sjoerg** 13520253Sjoerg** Returns 13620253Sjoerg** nothing, this is flow-through code 13720253Sjoerg** 13820679Sdavidn** Side Effects: 13920253Sjoerg** May or may not change the mode of a currently open file. 14020253Sjoerg** The file mode may be changed to O_NONBLOCK or ~O_NONBLOCK 14130259Scharnier** (meaning block). This is done to best match the type of 14220253Sjoerg** timeout and for (possible) use with select(). 14330259Scharnier*/ 14420253Sjoerg 14520747Sdavidn# define SM_CONVERT_TIME(fp, fd, val, time) { \ 14620747Sdavidn if (((fd) = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1) \ 14720253Sjoerg { \ 14820679Sdavidn /* can't get an fd, likely internal 'fake' fp */ \ 14920253Sjoerg errno = 0; \ 15020253Sjoerg } \ 15120253Sjoerg if ((val) == SM_TIME_DEFAULT) \ 15220253Sjoerg (val) = (fp)->f_timeout; \ 15320253Sjoerg if ((val) == SM_TIME_IMMEDIATE || (val) == SM_TIME_FOREVER) \ 15420253Sjoerg { \ 15520253Sjoerg (time)->tv_sec = 0; \ 15620253Sjoerg (time)->tv_usec = 0; \ 15720253Sjoerg } \ 15820253Sjoerg else \ 15920253Sjoerg { \ 16020253Sjoerg (time)->tv_sec = (val) / 1000; \ 16120253Sjoerg (time)->tv_usec = ((val) - ((time)->tv_sec * 1000)) * 1000; \ 16220253Sjoerg } \ 16320253Sjoerg if ((val) == SM_TIME_FOREVER) \ 16420253Sjoerg { \ 16520253Sjoerg if ((fp)->f_timeoutstate == SM_TIME_NONBLOCK && (fd) != -1) \ 16620253Sjoerg { \ 16720253Sjoerg int ret; \ 16820253Sjoerg ret = fcntl((fd), F_GETFL, 0); \ 16920253Sjoerg if (ret == -1 || fcntl((fd), F_SETFL, \ 17020253Sjoerg ret & ~O_NONBLOCK) == -1) \ 17120253Sjoerg { \ 17220253Sjoerg /* errno should be set */ \ 17320253Sjoerg return SM_IO_EOF; \ 17420253Sjoerg } \ 17520253Sjoerg (fp)->f_timeoutstate = SM_TIME_BLOCK; \ 17620253Sjoerg if ((fp)->f_modefp != NULL) \ 17720253Sjoerg (fp)->f_modefp->f_timeoutstate = SM_TIME_BLOCK; \ 17820253Sjoerg } \ 17920253Sjoerg } \ 18020253Sjoerg else { \ 18120253Sjoerg if ((fp)->f_timeoutstate == SM_TIME_BLOCK && (fd) != -1) \ 18220253Sjoerg { \ 18320253Sjoerg int ret; \ 18420253Sjoerg ret = fcntl((fd), F_GETFL, 0); \ 18520253Sjoerg if (ret == -1 || fcntl((fd), F_SETFL, \ 18620253Sjoerg ret | O_NONBLOCK) == -1) \ 18720253Sjoerg { \ 18820253Sjoerg /* errno should be set */ \ 18920253Sjoerg return SM_IO_EOF; \ 19020253Sjoerg } \ 19130259Scharnier (fp)->f_timeoutstate = SM_TIME_NONBLOCK; \ 19220267Sjoerg if ((fp)->f_modefp != NULL) \ 19320253Sjoerg (fp)->f_modefp->f_timeoutstate = SM_TIME_NONBLOCK; \ 19420253Sjoerg } \ 19520253Sjoerg } \ 19620253Sjoerg} 19720253Sjoerg 19830259Scharnier/* 19920253Sjoerg** SM_IO_WR_TIMEOUT -- setup the timeout for the write 20020253Sjoerg** 20120253Sjoerg** This #define uses a select() to wait for the 'fd' to become writable. 20220267Sjoerg** The select() can be active for up to 'to' time. The select may not 20320267Sjoerg** use all of the the 'to' time. Hence, the amount of "wall-clock" time is 20420267Sjoerg** measured to decide how much to subtract from 'to' to update it. On some 20520267Sjoerg** BSD-based/like systems the timeout for a select is updated for the 20620267Sjoerg** amount of time used. On many/most systems this does not happen. Therefore 20720267Sjoerg** the updating of 'to' must be done ourselves; a copy of 'to' is passed 20820747Sdavidn** since a BSD-like system will have updated it and we don't want to 20920747Sdavidn** double the time used! 21020267Sjoerg** Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the 21120747Sdavidn** sendmail buffered file type in sendmail/bf.c; see fvwrite.c). 21220747Sdavidn** 21320747Sdavidn** Parameters 21420747Sdavidn** fd -- a file descriptor for doing select() with 21520747Sdavidn** timeout -- the original user set value. 21620747Sdavidn** 21720747Sdavidn** Returns 21820267Sjoerg** nothing, this is flow through code 21920267Sjoerg** 22020747Sdavidn** Side Effects: 22120267Sjoerg** adjusts 'timeout' for time used 22244229Sdavidn*/ 22320267Sjoerg 22430259Scharnier#define SM_IO_WR_TIMEOUT(fp, fd, to) { \ 22520267Sjoerg struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff; \ 22620267Sjoerg struct timeval sm_io_to; \ 22720267Sjoerg int sm_io_to_sel; \ 22820267Sjoerg fd_set sm_io_to_mask, sm_io_x_mask; \ 22920267Sjoerg errno = 0; \ 23020267Sjoerg if ((to) == SM_TIME_DEFAULT) \ 23120747Sdavidn (to) = (fp)->f_timeout; \ 23220267Sjoerg if ((to) == SM_TIME_IMMEDIATE) \ 23320267Sjoerg { \ 23420747Sdavidn errno = EAGAIN; \ 23520267Sjoerg return SM_IO_EOF; \ 23620267Sjoerg } \ 23720267Sjoerg else if ((to) == SM_TIME_FOREVER) \ 23820267Sjoerg { \ 23920267Sjoerg errno = EINVAL; \ 24020267Sjoerg return SM_IO_EOF; \ 24120267Sjoerg } \ 24252502Sdavidn else \ 24352502Sdavidn { \ 24452502Sdavidn sm_io_to.tv_sec = (to) / 1000; \ 24552502Sdavidn sm_io_to.tv_usec = ((to) - (sm_io_to.tv_sec * 1000)) * 1000; \ 24652502Sdavidn } \ 24720267Sjoerg if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE) \ 24852502Sdavidn { \ 24952502Sdavidn errno = EINVAL; \ 25052502Sdavidn return SM_IO_EOF; \ 25152502Sdavidn } \ 25256000Sdavidn FD_ZERO(&sm_io_to_mask); \ 25352502Sdavidn FD_SET((fd), &sm_io_to_mask); \ 25420253Sjoerg FD_ZERO(&sm_io_x_mask); \ 25520253Sjoerg FD_SET((fd), &sm_io_x_mask); \ 25644229Sdavidn if (gettimeofday(&sm_io_to_before, NULL) < 0) \ 25730259Scharnier return SM_IO_EOF; \ 25820253Sjoerg do \ 25920253Sjoerg { \ 26020253Sjoerg sm_io_to_sel = select((fd) + 1, NULL, &sm_io_to_mask, \ 26120747Sdavidn &sm_io_x_mask, &sm_io_to); \ 26220747Sdavidn } while (sm_io_to_sel < 0 && errno == EINTR); \ 26320747Sdavidn if (sm_io_to_sel < 0) \ 26420267Sjoerg { \ 26520253Sjoerg /* something went wrong, errno set */ \ 26620253Sjoerg return SM_IO_EOF; \ 26720253Sjoerg } \ 26820253Sjoerg else if (sm_io_to_sel == 0) \ 26920253Sjoerg { \ 27020253Sjoerg /* timeout */ \ 27120253Sjoerg errno = EAGAIN; \ 27220253Sjoerg return SM_IO_EOF; \ 27320253Sjoerg } \ 27420253Sjoerg /* else loop again */ \ 27520253Sjoerg if (gettimeofday(&sm_io_to_after, NULL) < 0) \ 27620253Sjoerg return SM_IO_EOF; \ 27720253Sjoerg timersub(&sm_io_to_after, &sm_io_to_before, &sm_io_to_diff); \ 27820253Sjoerg (to) -= (sm_io_to_diff.tv_sec * 1000); \ 27920253Sjoerg (to) -= (sm_io_to_diff.tv_usec / 1000); \ 28020253Sjoerg if ((to) < 0) \ 28144229Sdavidn (to) = 0; \ 28230259Scharnier} 28320253Sjoerg 28420253Sjoerg/* 28520253Sjoerg** If there is no 'fd' just error (we can't timeout). If the timeout 28620253Sjoerg** is SM_TIME_FOREVER then there is no need to do a timeout with 28720253Sjoerg** select since this will be a real error. If the error is not 28820253Sjoerg** EAGAIN/EWOULDBLOCK (from a nonblocking) then it's a real error. 28920253Sjoerg** Specify the condition here as macro so it can be used in several places. 29020253Sjoerg*/ 29120253Sjoerg 29220253Sjoerg#define IS_IO_ERROR(fd, ret, to) \ 29320253Sjoerg ((fd) < 0 || \ 29420253Sjoerg ((ret) < 0 && errno != EAGAIN && errno != EWOULDBLOCK) || \ 29520253Sjoerg (to) == SM_TIME_FOREVER) 29620253Sjoerg 29720253Sjoerg