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> 18 SM_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 32 static 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 118 static int 119 sm_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 141 int 142 sm_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 264 err: 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 293 int 294 sm_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