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