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