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