xref: /titanic_41/usr/src/cmd/sendmail/libsm/refill.c (revision 445f2479fe3d7435daab18bf2cdc310b86cd6738)
17c478bd9Sstevel@tonic-gate /*
2*445f2479Sjbeck  * Copyright (c) 2000-2001, 2005-2006 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate  *      All rights reserved.
47c478bd9Sstevel@tonic-gate  * Copyright (c) 1990, 1993
57c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
87c478bd9Sstevel@tonic-gate  * Chris Torek.
97c478bd9Sstevel@tonic-gate  *
107c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
117c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
127c478bd9Sstevel@tonic-gate  * the sendmail distribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include <sm/gen.h>
18*445f2479Sjbeck SM_RCSID("@(#)$Id: refill.c,v 1.53 2006/02/28 18:48:25 ca Exp $")
197c478bd9Sstevel@tonic-gate #include <stdlib.h>
207c478bd9Sstevel@tonic-gate #include <unistd.h>
217c478bd9Sstevel@tonic-gate #include <errno.h>
227c478bd9Sstevel@tonic-gate #include <setjmp.h>
237c478bd9Sstevel@tonic-gate #include <signal.h>
2449218d4fSjbeck #include <sm/time.h>
257c478bd9Sstevel@tonic-gate #include <fcntl.h>
267c478bd9Sstevel@tonic-gate #include <string.h>
277c478bd9Sstevel@tonic-gate #include <sm/io.h>
287c478bd9Sstevel@tonic-gate #include <sm/conf.h>
297c478bd9Sstevel@tonic-gate #include <sm/assert.h>
307c478bd9Sstevel@tonic-gate #include "local.h"
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate static int sm_lflush __P((SM_FILE_T *, int *));
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /*
357c478bd9Sstevel@tonic-gate **  SM_IO_RD_TIMEOUT -- measured timeout for reads
367c478bd9Sstevel@tonic-gate **
377c478bd9Sstevel@tonic-gate **  This #define uses a select() to wait for the 'fd' to become readable.
387c478bd9Sstevel@tonic-gate **  The select() can be active for up to 'To' time. The select() may not
397c478bd9Sstevel@tonic-gate **  use all of the the 'To' time. Hence, the amount of "wall-clock" time is
407c478bd9Sstevel@tonic-gate **  measured to decide how much to subtract from 'To' to update it. On some
417c478bd9Sstevel@tonic-gate **  BSD-based/like systems the timeout for a select() is updated for the
427c478bd9Sstevel@tonic-gate **  amount of time used. On many/most systems this does not happen. Therefore
437c478bd9Sstevel@tonic-gate **  the updating of 'To' must be done ourselves; a copy of 'To' is passed
447c478bd9Sstevel@tonic-gate **  since a BSD-like system will have updated it and we don't want to
457c478bd9Sstevel@tonic-gate **  double the time used!
467c478bd9Sstevel@tonic-gate **  Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
477c478bd9Sstevel@tonic-gate **  sendmail buffered file type in sendmail/bf.c; see use below).
487c478bd9Sstevel@tonic-gate **
497c478bd9Sstevel@tonic-gate **	Parameters
507c478bd9Sstevel@tonic-gate **		fp -- the file pointer for the active file
517c478bd9Sstevel@tonic-gate **		fd -- raw file descriptor (from 'fp') to use for select()
527c478bd9Sstevel@tonic-gate **		to -- struct timeval of the timeout
537c478bd9Sstevel@tonic-gate **		timeout -- the original timeout value
547c478bd9Sstevel@tonic-gate **		sel_ret -- the return value from the select()
557c478bd9Sstevel@tonic-gate **
567c478bd9Sstevel@tonic-gate **	Returns:
577c478bd9Sstevel@tonic-gate **		nothing, flow through code
587c478bd9Sstevel@tonic-gate */
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define SM_IO_RD_TIMEOUT(fp, fd, to, timeout, sel_ret)			\
617c478bd9Sstevel@tonic-gate {									\
627c478bd9Sstevel@tonic-gate 	struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff;	\
637c478bd9Sstevel@tonic-gate 	fd_set sm_io_to_mask, sm_io_x_mask;				\
647c478bd9Sstevel@tonic-gate 	errno = 0;							\
657c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_IMMEDIATE)				\
667c478bd9Sstevel@tonic-gate 	{								\
677c478bd9Sstevel@tonic-gate 		errno = EAGAIN;						\
687c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
697c478bd9Sstevel@tonic-gate 	}								\
707c478bd9Sstevel@tonic-gate 	if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE)			\
717c478bd9Sstevel@tonic-gate 	{								\
727c478bd9Sstevel@tonic-gate 		errno = EINVAL;						\
737c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
747c478bd9Sstevel@tonic-gate 	}								\
757c478bd9Sstevel@tonic-gate 	FD_ZERO(&sm_io_to_mask);					\
767c478bd9Sstevel@tonic-gate 	FD_SET((fd), &sm_io_to_mask);					\
777c478bd9Sstevel@tonic-gate 	FD_ZERO(&sm_io_x_mask);						\
787c478bd9Sstevel@tonic-gate 	FD_SET((fd), &sm_io_x_mask);					\
797c478bd9Sstevel@tonic-gate 	if (gettimeofday(&sm_io_to_before, NULL) < 0)			\
807c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
81*445f2479Sjbeck 	do								\
82*445f2479Sjbeck 	{								\
837c478bd9Sstevel@tonic-gate 		(sel_ret) = select((fd) + 1, &sm_io_to_mask, NULL,	\
847c478bd9Sstevel@tonic-gate 			   	&sm_io_x_mask, (to));			\
85*445f2479Sjbeck 	} while ((sel_ret) < 0 && errno == EINTR);			\
867c478bd9Sstevel@tonic-gate 	if ((sel_ret) < 0)						\
877c478bd9Sstevel@tonic-gate 	{								\
887c478bd9Sstevel@tonic-gate 		/* something went wrong, errno set */			\
897c478bd9Sstevel@tonic-gate 		fp->f_r = 0;						\
907c478bd9Sstevel@tonic-gate 		fp->f_flags |= SMERR;					\
917c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
927c478bd9Sstevel@tonic-gate 	}								\
937c478bd9Sstevel@tonic-gate 	else if ((sel_ret) == 0)					\
947c478bd9Sstevel@tonic-gate 	{								\
957c478bd9Sstevel@tonic-gate 		/* timeout */						\
967c478bd9Sstevel@tonic-gate 		errno = EAGAIN;						\
977c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
987c478bd9Sstevel@tonic-gate 	}								\
997c478bd9Sstevel@tonic-gate 	/* calulate wall-clock time used */				\
1007c478bd9Sstevel@tonic-gate 	if (gettimeofday(&sm_io_to_after, NULL) < 0)			\
1017c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
102*445f2479Sjbeck 	timersub(&sm_io_to_after, &sm_io_to_before, &sm_io_to_diff);	\
1037c478bd9Sstevel@tonic-gate 	timersub((to), &sm_io_to_diff, (to));				\
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate **  SM_LFLUSH -- flush a file if it is line buffered and writable
1087c478bd9Sstevel@tonic-gate **
1097c478bd9Sstevel@tonic-gate **	Parameters:
1107c478bd9Sstevel@tonic-gate **		fp -- file pointer to flush
1117c478bd9Sstevel@tonic-gate **		timeout -- original timeout value (in milliseconds)
1127c478bd9Sstevel@tonic-gate **
1137c478bd9Sstevel@tonic-gate **	Returns:
1147c478bd9Sstevel@tonic-gate **		Failure: returns SM_IO_EOF and sets errno
1157c478bd9Sstevel@tonic-gate **		Success: returns 0
1167c478bd9Sstevel@tonic-gate */
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate static int
sm_lflush(fp,timeout)1197c478bd9Sstevel@tonic-gate sm_lflush(fp, timeout)
1207c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
1217c478bd9Sstevel@tonic-gate 	int *timeout;
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	if ((fp->f_flags & (SMLBF|SMWR)) == (SMLBF|SMWR))
1257c478bd9Sstevel@tonic-gate 		return sm_flush(fp, timeout);
1267c478bd9Sstevel@tonic-gate 	return 0;
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate **  SM_REFILL -- refill a buffer
1317c478bd9Sstevel@tonic-gate **
1327c478bd9Sstevel@tonic-gate **	Parameters:
1337c478bd9Sstevel@tonic-gate **		fp -- file pointer for buffer refill
1347c478bd9Sstevel@tonic-gate **		timeout -- time to complete filling the buffer in milliseconds
1357c478bd9Sstevel@tonic-gate **
1367c478bd9Sstevel@tonic-gate **	Returns:
1377c478bd9Sstevel@tonic-gate **		Success: returns 0
1387c478bd9Sstevel@tonic-gate **		Failure: returns SM_IO_EOF
1397c478bd9Sstevel@tonic-gate */
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate int
sm_refill(fp,timeout)1427c478bd9Sstevel@tonic-gate sm_refill(fp, timeout)
1437c478bd9Sstevel@tonic-gate 	register SM_FILE_T *fp;
1447c478bd9Sstevel@tonic-gate 	int timeout;
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	int ret, r;
1477c478bd9Sstevel@tonic-gate 	struct timeval to;
1487c478bd9Sstevel@tonic-gate 	int fd;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_DEFAULT)
1517c478bd9Sstevel@tonic-gate 		timeout = fp->f_timeout;
1527c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_IMMEDIATE)
1537c478bd9Sstevel@tonic-gate 	{
1547c478bd9Sstevel@tonic-gate 		/*
1557c478bd9Sstevel@tonic-gate 		**  Filling the buffer will take time and we are wanted to
1567c478bd9Sstevel@tonic-gate 		**  return immediately. And we're not EOF or ERR really.
1577c478bd9Sstevel@tonic-gate 		**  So... the failure is we couldn't do it in time.
1587c478bd9Sstevel@tonic-gate 		*/
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 		errno = EAGAIN;
1617c478bd9Sstevel@tonic-gate 		fp->f_r = 0; /* just to be sure */
1627c478bd9Sstevel@tonic-gate 		return 0;
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* make sure stdio is set up */
1667c478bd9Sstevel@tonic-gate 	if (!Sm_IO_DidInit)
1677c478bd9Sstevel@tonic-gate 		sm_init();
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	fp->f_r = 0;		/* largely a convenience for callers */
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (fp->f_flags & SMFEOF)
1727c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	SM_CONVERT_TIME(fp, fd, timeout, &to);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* if not already reading, have to be reading and writing */
1777c478bd9Sstevel@tonic-gate 	if ((fp->f_flags & SMRD) == 0)
1787c478bd9Sstevel@tonic-gate 	{
1797c478bd9Sstevel@tonic-gate 		if ((fp->f_flags & SMRW) == 0)
1807c478bd9Sstevel@tonic-gate 		{
1817c478bd9Sstevel@tonic-gate 			errno = EBADF;
1827c478bd9Sstevel@tonic-gate 			fp->f_flags |= SMERR;
1837c478bd9Sstevel@tonic-gate 			return SM_IO_EOF;
1847c478bd9Sstevel@tonic-gate 		}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 		/* switch to reading */
1877c478bd9Sstevel@tonic-gate 		if (fp->f_flags & SMWR)
1887c478bd9Sstevel@tonic-gate 		{
1897c478bd9Sstevel@tonic-gate 			if (sm_flush(fp, &timeout))
1907c478bd9Sstevel@tonic-gate 				return SM_IO_EOF;
1917c478bd9Sstevel@tonic-gate 			fp->f_flags &= ~SMWR;
1927c478bd9Sstevel@tonic-gate 			fp->f_w = 0;
1937c478bd9Sstevel@tonic-gate 			fp->f_lbfsize = 0;
1947c478bd9Sstevel@tonic-gate 		}
1957c478bd9Sstevel@tonic-gate 		fp->f_flags |= SMRD;
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 	else
1987c478bd9Sstevel@tonic-gate 	{
1997c478bd9Sstevel@tonic-gate 		/*
2007c478bd9Sstevel@tonic-gate 		**  We were reading.  If there is an ungetc buffer,
2017c478bd9Sstevel@tonic-gate 		**  we must have been reading from that.  Drop it,
2027c478bd9Sstevel@tonic-gate 		**  restoring the previous buffer (if any).  If there
2037c478bd9Sstevel@tonic-gate 		**  is anything in that buffer, return.
2047c478bd9Sstevel@tonic-gate 		*/
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 		if (HASUB(fp))
2077c478bd9Sstevel@tonic-gate 		{
2087c478bd9Sstevel@tonic-gate 			FREEUB(fp);
2097c478bd9Sstevel@tonic-gate 			if ((fp->f_r = fp->f_ur) != 0)
2107c478bd9Sstevel@tonic-gate 			{
2117c478bd9Sstevel@tonic-gate 				fp->f_p = fp->f_up;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 				/* revert blocking state */
2147c478bd9Sstevel@tonic-gate 				return 0;
2157c478bd9Sstevel@tonic-gate 			}
2167c478bd9Sstevel@tonic-gate 		}
2177c478bd9Sstevel@tonic-gate 	}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (fp->f_bf.smb_base == NULL)
2207c478bd9Sstevel@tonic-gate 		sm_makebuf(fp);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/*
2237c478bd9Sstevel@tonic-gate 	**  Before reading from a line buffered or unbuffered file,
2247c478bd9Sstevel@tonic-gate 	**  flush all line buffered output files, per the ANSI C standard.
2257c478bd9Sstevel@tonic-gate 	*/
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if (fp->f_flags & (SMLBF|SMNBF))
2287c478bd9Sstevel@tonic-gate 		(void) sm_fwalk(sm_lflush, &timeout);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/*
2317c478bd9Sstevel@tonic-gate 	**  If this file is linked to another, and we are going to hang
2327c478bd9Sstevel@tonic-gate 	**  on the read, flush the linked file before continuing.
2337c478bd9Sstevel@tonic-gate 	*/
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if (fp->f_flushfp != NULL &&
2367c478bd9Sstevel@tonic-gate 	    (*fp->f_getinfo)(fp, SM_IO_IS_READABLE, NULL) <= 0)
2377c478bd9Sstevel@tonic-gate 		sm_flush(fp->f_flushfp, &timeout);
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	fp->f_p = fp->f_bf.smb_base;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	/*
2427c478bd9Sstevel@tonic-gate 	**  The do-while loop stops trying to read when something is read
2437c478bd9Sstevel@tonic-gate 	**  or it appears that the timeout has expired before finding
2447c478bd9Sstevel@tonic-gate 	**  something available to be read (via select()).
2457c478bd9Sstevel@tonic-gate 	*/
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	ret = 0;
2487c478bd9Sstevel@tonic-gate 	do
2497c478bd9Sstevel@tonic-gate 	{
2507c478bd9Sstevel@tonic-gate 		errno = 0; /* needed to ensure EOF correctly found */
2517c478bd9Sstevel@tonic-gate 		r = (*fp->f_read)(fp, (char *)fp->f_p, fp->f_bf.smb_size);
2527c478bd9Sstevel@tonic-gate 		if (r <= 0)
2537c478bd9Sstevel@tonic-gate 		{
2547c478bd9Sstevel@tonic-gate 			if (r == 0 && errno == 0)
2557c478bd9Sstevel@tonic-gate 				break; /* EOF found */
2567c478bd9Sstevel@tonic-gate 			if (IS_IO_ERROR(fd, r, timeout))
2577c478bd9Sstevel@tonic-gate 				goto err; /* errno set */
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate 			/* read would block */
2607c478bd9Sstevel@tonic-gate 			SM_IO_RD_TIMEOUT(fp, fd, &to, timeout, ret);
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 	} while (r <= 0 && ret > 0);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate err:
2657c478bd9Sstevel@tonic-gate 	if (r <= 0)
2667c478bd9Sstevel@tonic-gate 	{
2677c478bd9Sstevel@tonic-gate 		if (r == 0)
2687c478bd9Sstevel@tonic-gate 			fp->f_flags |= SMFEOF;
2697c478bd9Sstevel@tonic-gate 		else
2707c478bd9Sstevel@tonic-gate 			fp->f_flags |= SMERR;
2717c478bd9Sstevel@tonic-gate 		fp->f_r = 0;
2727c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	fp->f_r = r;
2757c478bd9Sstevel@tonic-gate 	return 0;
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate /*
2797c478bd9Sstevel@tonic-gate **  SM_RGET -- refills buffer and returns first character
2807c478bd9Sstevel@tonic-gate **
2817c478bd9Sstevel@tonic-gate **  Handle sm_getc() when the buffer ran out:
2827c478bd9Sstevel@tonic-gate **  Refill, then return the first character in the newly-filled buffer.
2837c478bd9Sstevel@tonic-gate **
2847c478bd9Sstevel@tonic-gate **	Parameters:
2857c478bd9Sstevel@tonic-gate **		fp -- file pointer to work on
2867c478bd9Sstevel@tonic-gate **		timeout -- time to complete refill
2877c478bd9Sstevel@tonic-gate **
2887c478bd9Sstevel@tonic-gate **	Returns:
2897c478bd9Sstevel@tonic-gate **		Success: first character in refilled buffer as an int
2907c478bd9Sstevel@tonic-gate **		Failure: SM_IO_EOF
2917c478bd9Sstevel@tonic-gate */
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate int
sm_rget(fp,timeout)2947c478bd9Sstevel@tonic-gate sm_rget(fp, timeout)
2957c478bd9Sstevel@tonic-gate 	register SM_FILE_T *fp;
2967c478bd9Sstevel@tonic-gate 	int timeout;
2977c478bd9Sstevel@tonic-gate {
2987c478bd9Sstevel@tonic-gate 	if (sm_refill(fp, timeout) == 0)
2997c478bd9Sstevel@tonic-gate 	{
3007c478bd9Sstevel@tonic-gate 		fp->f_r--;
3017c478bd9Sstevel@tonic-gate 		return *fp->f_p++;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 	return SM_IO_EOF;
3047c478bd9Sstevel@tonic-gate }
305