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