xref: /titanic_50/usr/src/cmd/sendmail/libsm/refill.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3*7c478bd9Sstevel@tonic-gate  *      All rights reserved.
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1990, 1993
5*7c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
6*7c478bd9Sstevel@tonic-gate  *
7*7c478bd9Sstevel@tonic-gate  * This code is derived from software contributed to Berkeley by
8*7c478bd9Sstevel@tonic-gate  * Chris Torek.
9*7c478bd9Sstevel@tonic-gate  *
10*7c478bd9Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
11*7c478bd9Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
12*7c478bd9Sstevel@tonic-gate  * the sendmail distribution.
13*7c478bd9Sstevel@tonic-gate  */
14*7c478bd9Sstevel@tonic-gate 
15*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <sm/gen.h>
18*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: refill.c,v 1.49.2.1 2002/09/09 21:38:08 gshapiro Exp $")
19*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
20*7c478bd9Sstevel@tonic-gate #include <unistd.h>
21*7c478bd9Sstevel@tonic-gate #include <errno.h>
22*7c478bd9Sstevel@tonic-gate #include <setjmp.h>
23*7c478bd9Sstevel@tonic-gate #include <signal.h>
24*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
25*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
26*7c478bd9Sstevel@tonic-gate #include <string.h>
27*7c478bd9Sstevel@tonic-gate #include <sm/io.h>
28*7c478bd9Sstevel@tonic-gate #include <sm/conf.h>
29*7c478bd9Sstevel@tonic-gate #include <sm/assert.h>
30*7c478bd9Sstevel@tonic-gate #include "local.h"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate static int sm_lflush __P((SM_FILE_T *, int *));
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate /*
35*7c478bd9Sstevel@tonic-gate **  SM_IO_RD_TIMEOUT -- measured timeout for reads
36*7c478bd9Sstevel@tonic-gate **
37*7c478bd9Sstevel@tonic-gate **  This #define uses a select() to wait for the 'fd' to become readable.
38*7c478bd9Sstevel@tonic-gate **  The select() can be active for up to 'To' time. The select() may not
39*7c478bd9Sstevel@tonic-gate **  use all of the the 'To' time. Hence, the amount of "wall-clock" time is
40*7c478bd9Sstevel@tonic-gate **  measured to decide how much to subtract from 'To' to update it. On some
41*7c478bd9Sstevel@tonic-gate **  BSD-based/like systems the timeout for a select() is updated for the
42*7c478bd9Sstevel@tonic-gate **  amount of time used. On many/most systems this does not happen. Therefore
43*7c478bd9Sstevel@tonic-gate **  the updating of 'To' must be done ourselves; a copy of 'To' is passed
44*7c478bd9Sstevel@tonic-gate **  since a BSD-like system will have updated it and we don't want to
45*7c478bd9Sstevel@tonic-gate **  double the time used!
46*7c478bd9Sstevel@tonic-gate **  Note: if a valid 'fd' doesn't exist yet, don't use this (e.g. the
47*7c478bd9Sstevel@tonic-gate **  sendmail buffered file type in sendmail/bf.c; see use below).
48*7c478bd9Sstevel@tonic-gate **
49*7c478bd9Sstevel@tonic-gate **	Parameters
50*7c478bd9Sstevel@tonic-gate **		fp -- the file pointer for the active file
51*7c478bd9Sstevel@tonic-gate **		fd -- raw file descriptor (from 'fp') to use for select()
52*7c478bd9Sstevel@tonic-gate **		to -- struct timeval of the timeout
53*7c478bd9Sstevel@tonic-gate **		timeout -- the original timeout value
54*7c478bd9Sstevel@tonic-gate **		sel_ret -- the return value from the select()
55*7c478bd9Sstevel@tonic-gate **
56*7c478bd9Sstevel@tonic-gate **	Returns:
57*7c478bd9Sstevel@tonic-gate **		nothing, flow through code
58*7c478bd9Sstevel@tonic-gate */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate #define SM_IO_RD_TIMEOUT(fp, fd, to, timeout, sel_ret)			\
61*7c478bd9Sstevel@tonic-gate {									\
62*7c478bd9Sstevel@tonic-gate 	struct timeval sm_io_to_before, sm_io_to_after, sm_io_to_diff;	\
63*7c478bd9Sstevel@tonic-gate 	fd_set sm_io_to_mask, sm_io_x_mask;				\
64*7c478bd9Sstevel@tonic-gate 	errno = 0;							\
65*7c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_IMMEDIATE)				\
66*7c478bd9Sstevel@tonic-gate 	{								\
67*7c478bd9Sstevel@tonic-gate 		errno = EAGAIN;						\
68*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
69*7c478bd9Sstevel@tonic-gate 	}								\
70*7c478bd9Sstevel@tonic-gate 	if (FD_SETSIZE > 0 && (fd) >= FD_SETSIZE)			\
71*7c478bd9Sstevel@tonic-gate 	{								\
72*7c478bd9Sstevel@tonic-gate 		errno = EINVAL;						\
73*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
74*7c478bd9Sstevel@tonic-gate 	}								\
75*7c478bd9Sstevel@tonic-gate 	FD_ZERO(&sm_io_to_mask);					\
76*7c478bd9Sstevel@tonic-gate 	FD_SET((fd), &sm_io_to_mask);					\
77*7c478bd9Sstevel@tonic-gate 	FD_ZERO(&sm_io_x_mask);						\
78*7c478bd9Sstevel@tonic-gate 	FD_SET((fd), &sm_io_x_mask);					\
79*7c478bd9Sstevel@tonic-gate 	if (gettimeofday(&sm_io_to_before, NULL) < 0)			\
80*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
81*7c478bd9Sstevel@tonic-gate 	(sel_ret) = select((fd) + 1, &sm_io_to_mask, NULL,		\
82*7c478bd9Sstevel@tonic-gate 			   &sm_io_x_mask, (to));			\
83*7c478bd9Sstevel@tonic-gate 	if ((sel_ret) < 0)						\
84*7c478bd9Sstevel@tonic-gate 	{								\
85*7c478bd9Sstevel@tonic-gate 		/* something went wrong, errno set */			\
86*7c478bd9Sstevel@tonic-gate 		fp->f_r = 0;						\
87*7c478bd9Sstevel@tonic-gate 		fp->f_flags |= SMERR;					\
88*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
89*7c478bd9Sstevel@tonic-gate 	}								\
90*7c478bd9Sstevel@tonic-gate 	else if ((sel_ret) == 0)					\
91*7c478bd9Sstevel@tonic-gate 	{								\
92*7c478bd9Sstevel@tonic-gate 		/* timeout */						\
93*7c478bd9Sstevel@tonic-gate 		errno = EAGAIN;						\
94*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
95*7c478bd9Sstevel@tonic-gate 	}								\
96*7c478bd9Sstevel@tonic-gate 	/* calulate wall-clock time used */				\
97*7c478bd9Sstevel@tonic-gate 	if (gettimeofday(&sm_io_to_after, NULL) < 0)			\
98*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;					\
99*7c478bd9Sstevel@tonic-gate 	timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff);	\
100*7c478bd9Sstevel@tonic-gate 	timersub((to), &sm_io_to_diff, (to));				\
101*7c478bd9Sstevel@tonic-gate }
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate /*
104*7c478bd9Sstevel@tonic-gate **  SM_LFLUSH -- flush a file if it is line buffered and writable
105*7c478bd9Sstevel@tonic-gate **
106*7c478bd9Sstevel@tonic-gate **	Parameters:
107*7c478bd9Sstevel@tonic-gate **		fp -- file pointer to flush
108*7c478bd9Sstevel@tonic-gate **		timeout -- original timeout value (in milliseconds)
109*7c478bd9Sstevel@tonic-gate **
110*7c478bd9Sstevel@tonic-gate **	Returns:
111*7c478bd9Sstevel@tonic-gate **		Failure: returns SM_IO_EOF and sets errno
112*7c478bd9Sstevel@tonic-gate **		Success: returns 0
113*7c478bd9Sstevel@tonic-gate */
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate static int
116*7c478bd9Sstevel@tonic-gate sm_lflush(fp, timeout)
117*7c478bd9Sstevel@tonic-gate 	SM_FILE_T *fp;
118*7c478bd9Sstevel@tonic-gate 	int *timeout;
119*7c478bd9Sstevel@tonic-gate {
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate 	if ((fp->f_flags & (SMLBF|SMWR)) == (SMLBF|SMWR))
122*7c478bd9Sstevel@tonic-gate 		return sm_flush(fp, timeout);
123*7c478bd9Sstevel@tonic-gate 	return 0;
124*7c478bd9Sstevel@tonic-gate }
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate /*
127*7c478bd9Sstevel@tonic-gate **  SM_REFILL -- refill a buffer
128*7c478bd9Sstevel@tonic-gate **
129*7c478bd9Sstevel@tonic-gate **	Parameters:
130*7c478bd9Sstevel@tonic-gate **		fp -- file pointer for buffer refill
131*7c478bd9Sstevel@tonic-gate **		timeout -- time to complete filling the buffer in milliseconds
132*7c478bd9Sstevel@tonic-gate **
133*7c478bd9Sstevel@tonic-gate **	Returns:
134*7c478bd9Sstevel@tonic-gate **		Success: returns 0
135*7c478bd9Sstevel@tonic-gate **		Failure: returns SM_IO_EOF
136*7c478bd9Sstevel@tonic-gate */
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate int
139*7c478bd9Sstevel@tonic-gate sm_refill(fp, timeout)
140*7c478bd9Sstevel@tonic-gate 	register SM_FILE_T *fp;
141*7c478bd9Sstevel@tonic-gate 	int timeout;
142*7c478bd9Sstevel@tonic-gate {
143*7c478bd9Sstevel@tonic-gate 	int ret, r;
144*7c478bd9Sstevel@tonic-gate 	struct timeval to;
145*7c478bd9Sstevel@tonic-gate 	int fd;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_DEFAULT)
148*7c478bd9Sstevel@tonic-gate 		timeout = fp->f_timeout;
149*7c478bd9Sstevel@tonic-gate 	if (timeout == SM_TIME_IMMEDIATE)
150*7c478bd9Sstevel@tonic-gate 	{
151*7c478bd9Sstevel@tonic-gate 		/*
152*7c478bd9Sstevel@tonic-gate 		**  Filling the buffer will take time and we are wanted to
153*7c478bd9Sstevel@tonic-gate 		**  return immediately. And we're not EOF or ERR really.
154*7c478bd9Sstevel@tonic-gate 		**  So... the failure is we couldn't do it in time.
155*7c478bd9Sstevel@tonic-gate 		*/
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 		errno = EAGAIN;
158*7c478bd9Sstevel@tonic-gate 		fp->f_r = 0; /* just to be sure */
159*7c478bd9Sstevel@tonic-gate 		return 0;
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	/* make sure stdio is set up */
163*7c478bd9Sstevel@tonic-gate 	if (!Sm_IO_DidInit)
164*7c478bd9Sstevel@tonic-gate 		sm_init();
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 	fp->f_r = 0;		/* largely a convenience for callers */
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 	if (fp->f_flags & SMFEOF)
169*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	SM_CONVERT_TIME(fp, fd, timeout, &to);
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate 	/* if not already reading, have to be reading and writing */
174*7c478bd9Sstevel@tonic-gate 	if ((fp->f_flags & SMRD) == 0)
175*7c478bd9Sstevel@tonic-gate 	{
176*7c478bd9Sstevel@tonic-gate 		if ((fp->f_flags & SMRW) == 0)
177*7c478bd9Sstevel@tonic-gate 		{
178*7c478bd9Sstevel@tonic-gate 			errno = EBADF;
179*7c478bd9Sstevel@tonic-gate 			fp->f_flags |= SMERR;
180*7c478bd9Sstevel@tonic-gate 			return SM_IO_EOF;
181*7c478bd9Sstevel@tonic-gate 		}
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 		/* switch to reading */
184*7c478bd9Sstevel@tonic-gate 		if (fp->f_flags & SMWR)
185*7c478bd9Sstevel@tonic-gate 		{
186*7c478bd9Sstevel@tonic-gate 			if (sm_flush(fp, &timeout))
187*7c478bd9Sstevel@tonic-gate 				return SM_IO_EOF;
188*7c478bd9Sstevel@tonic-gate 			fp->f_flags &= ~SMWR;
189*7c478bd9Sstevel@tonic-gate 			fp->f_w = 0;
190*7c478bd9Sstevel@tonic-gate 			fp->f_lbfsize = 0;
191*7c478bd9Sstevel@tonic-gate 		}
192*7c478bd9Sstevel@tonic-gate 		fp->f_flags |= SMRD;
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate 	else
195*7c478bd9Sstevel@tonic-gate 	{
196*7c478bd9Sstevel@tonic-gate 		/*
197*7c478bd9Sstevel@tonic-gate 		**  We were reading.  If there is an ungetc buffer,
198*7c478bd9Sstevel@tonic-gate 		**  we must have been reading from that.  Drop it,
199*7c478bd9Sstevel@tonic-gate 		**  restoring the previous buffer (if any).  If there
200*7c478bd9Sstevel@tonic-gate 		**  is anything in that buffer, return.
201*7c478bd9Sstevel@tonic-gate 		*/
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 		if (HASUB(fp))
204*7c478bd9Sstevel@tonic-gate 		{
205*7c478bd9Sstevel@tonic-gate 			FREEUB(fp);
206*7c478bd9Sstevel@tonic-gate 			if ((fp->f_r = fp->f_ur) != 0)
207*7c478bd9Sstevel@tonic-gate 			{
208*7c478bd9Sstevel@tonic-gate 				fp->f_p = fp->f_up;
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 				/* revert blocking state */
211*7c478bd9Sstevel@tonic-gate 				return 0;
212*7c478bd9Sstevel@tonic-gate 			}
213*7c478bd9Sstevel@tonic-gate 		}
214*7c478bd9Sstevel@tonic-gate 	}
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	if (fp->f_bf.smb_base == NULL)
217*7c478bd9Sstevel@tonic-gate 		sm_makebuf(fp);
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	/*
220*7c478bd9Sstevel@tonic-gate 	**  Before reading from a line buffered or unbuffered file,
221*7c478bd9Sstevel@tonic-gate 	**  flush all line buffered output files, per the ANSI C standard.
222*7c478bd9Sstevel@tonic-gate 	*/
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	if (fp->f_flags & (SMLBF|SMNBF))
225*7c478bd9Sstevel@tonic-gate 		(void) sm_fwalk(sm_lflush, &timeout);
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 	/*
228*7c478bd9Sstevel@tonic-gate 	**  If this file is linked to another, and we are going to hang
229*7c478bd9Sstevel@tonic-gate 	**  on the read, flush the linked file before continuing.
230*7c478bd9Sstevel@tonic-gate 	*/
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if (fp->f_flushfp != NULL &&
233*7c478bd9Sstevel@tonic-gate 	    (*fp->f_getinfo)(fp, SM_IO_IS_READABLE, NULL) <= 0)
234*7c478bd9Sstevel@tonic-gate 		sm_flush(fp->f_flushfp, &timeout);
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	fp->f_p = fp->f_bf.smb_base;
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	/*
239*7c478bd9Sstevel@tonic-gate 	**  The do-while loop stops trying to read when something is read
240*7c478bd9Sstevel@tonic-gate 	**  or it appears that the timeout has expired before finding
241*7c478bd9Sstevel@tonic-gate 	**  something available to be read (via select()).
242*7c478bd9Sstevel@tonic-gate 	*/
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	ret = 0;
245*7c478bd9Sstevel@tonic-gate 	do
246*7c478bd9Sstevel@tonic-gate 	{
247*7c478bd9Sstevel@tonic-gate 		errno = 0; /* needed to ensure EOF correctly found */
248*7c478bd9Sstevel@tonic-gate 		r = (*fp->f_read)(fp, (char *)fp->f_p, fp->f_bf.smb_size);
249*7c478bd9Sstevel@tonic-gate 		if (r <= 0)
250*7c478bd9Sstevel@tonic-gate 		{
251*7c478bd9Sstevel@tonic-gate 			if (r == 0 && errno == 0)
252*7c478bd9Sstevel@tonic-gate 				break; /* EOF found */
253*7c478bd9Sstevel@tonic-gate 			if (IS_IO_ERROR(fd, r, timeout))
254*7c478bd9Sstevel@tonic-gate 				goto err; /* errno set */
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 			/* read would block */
257*7c478bd9Sstevel@tonic-gate 			SM_IO_RD_TIMEOUT(fp, fd, &to, timeout, ret);
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 	} while (r <= 0 && ret > 0);
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate err:
262*7c478bd9Sstevel@tonic-gate 	if (r <= 0)
263*7c478bd9Sstevel@tonic-gate 	{
264*7c478bd9Sstevel@tonic-gate 		if (r == 0)
265*7c478bd9Sstevel@tonic-gate 			fp->f_flags |= SMFEOF;
266*7c478bd9Sstevel@tonic-gate 		else
267*7c478bd9Sstevel@tonic-gate 			fp->f_flags |= SMERR;
268*7c478bd9Sstevel@tonic-gate 		fp->f_r = 0;
269*7c478bd9Sstevel@tonic-gate 		return SM_IO_EOF;
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 	fp->f_r = r;
272*7c478bd9Sstevel@tonic-gate 	return 0;
273*7c478bd9Sstevel@tonic-gate }
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate /*
276*7c478bd9Sstevel@tonic-gate **  SM_RGET -- refills buffer and returns first character
277*7c478bd9Sstevel@tonic-gate **
278*7c478bd9Sstevel@tonic-gate **  Handle sm_getc() when the buffer ran out:
279*7c478bd9Sstevel@tonic-gate **  Refill, then return the first character in the newly-filled buffer.
280*7c478bd9Sstevel@tonic-gate **
281*7c478bd9Sstevel@tonic-gate **	Parameters:
282*7c478bd9Sstevel@tonic-gate **		fp -- file pointer to work on
283*7c478bd9Sstevel@tonic-gate **		timeout -- time to complete refill
284*7c478bd9Sstevel@tonic-gate **
285*7c478bd9Sstevel@tonic-gate **	Returns:
286*7c478bd9Sstevel@tonic-gate **		Success: first character in refilled buffer as an int
287*7c478bd9Sstevel@tonic-gate **		Failure: SM_IO_EOF
288*7c478bd9Sstevel@tonic-gate */
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate int
291*7c478bd9Sstevel@tonic-gate sm_rget(fp, timeout)
292*7c478bd9Sstevel@tonic-gate 	register SM_FILE_T *fp;
293*7c478bd9Sstevel@tonic-gate 	int timeout;
294*7c478bd9Sstevel@tonic-gate {
295*7c478bd9Sstevel@tonic-gate 	if (sm_refill(fp, timeout) == 0)
296*7c478bd9Sstevel@tonic-gate 	{
297*7c478bd9Sstevel@tonic-gate 		fp->f_r--;
298*7c478bd9Sstevel@tonic-gate 		return *fp->f_p++;
299*7c478bd9Sstevel@tonic-gate 	}
300*7c478bd9Sstevel@tonic-gate 	return SM_IO_EOF;
301*7c478bd9Sstevel@tonic-gate }
302