1 /* 2 * Copyright (c) 2000-2001 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 #include <sm/gen.h> 16 SM_RCSID("@(#)$Id: refill.c,v 1.50 2002/09/09 21:50:10 gshapiro Exp $") 17 #include <stdlib.h> 18 #include <unistd.h> 19 #include <errno.h> 20 #include <setjmp.h> 21 #include <signal.h> 22 #include <sys/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 30 static 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 (sel_ret) = select((fd) + 1, &sm_io_to_mask, NULL, \ 80 &sm_io_x_mask, (to)); \ 81 if ((sel_ret) < 0) \ 82 { \ 83 /* something went wrong, errno set */ \ 84 fp->f_r = 0; \ 85 fp->f_flags |= SMERR; \ 86 return SM_IO_EOF; \ 87 } \ 88 else if ((sel_ret) == 0) \ 89 { \ 90 /* timeout */ \ 91 errno = EAGAIN; \ 92 return SM_IO_EOF; \ 93 } \ 94 /* calulate wall-clock time used */ \ 95 if (gettimeofday(&sm_io_to_after, NULL) < 0) \ 96 return SM_IO_EOF; \ 97 timersub(&sm_io_to_before, &sm_io_to_after, &sm_io_to_diff); \ 98 timersub((to), &sm_io_to_diff, (to)); \ 99 } 100 101 /* 102 ** SM_LFLUSH -- flush a file if it is line buffered and writable 103 ** 104 ** Parameters: 105 ** fp -- file pointer to flush 106 ** timeout -- original timeout value (in milliseconds) 107 ** 108 ** Returns: 109 ** Failure: returns SM_IO_EOF and sets errno 110 ** Success: returns 0 111 */ 112 113 static int 114 sm_lflush(fp, timeout) 115 SM_FILE_T *fp; 116 int *timeout; 117 { 118 119 if ((fp->f_flags & (SMLBF|SMWR)) == (SMLBF|SMWR)) 120 return sm_flush(fp, timeout); 121 return 0; 122 } 123 124 /* 125 ** SM_REFILL -- refill a buffer 126 ** 127 ** Parameters: 128 ** fp -- file pointer for buffer refill 129 ** timeout -- time to complete filling the buffer in milliseconds 130 ** 131 ** Returns: 132 ** Success: returns 0 133 ** Failure: returns SM_IO_EOF 134 */ 135 136 int 137 sm_refill(fp, timeout) 138 register SM_FILE_T *fp; 139 int timeout; 140 { 141 int ret, r; 142 struct timeval to; 143 int fd; 144 145 if (timeout == SM_TIME_DEFAULT) 146 timeout = fp->f_timeout; 147 if (timeout == SM_TIME_IMMEDIATE) 148 { 149 /* 150 ** Filling the buffer will take time and we are wanted to 151 ** return immediately. And we're not EOF or ERR really. 152 ** So... the failure is we couldn't do it in time. 153 */ 154 155 errno = EAGAIN; 156 fp->f_r = 0; /* just to be sure */ 157 return 0; 158 } 159 160 /* make sure stdio is set up */ 161 if (!Sm_IO_DidInit) 162 sm_init(); 163 164 fp->f_r = 0; /* largely a convenience for callers */ 165 166 if (fp->f_flags & SMFEOF) 167 return SM_IO_EOF; 168 169 SM_CONVERT_TIME(fp, fd, timeout, &to); 170 171 /* if not already reading, have to be reading and writing */ 172 if ((fp->f_flags & SMRD) == 0) 173 { 174 if ((fp->f_flags & SMRW) == 0) 175 { 176 errno = EBADF; 177 fp->f_flags |= SMERR; 178 return SM_IO_EOF; 179 } 180 181 /* switch to reading */ 182 if (fp->f_flags & SMWR) 183 { 184 if (sm_flush(fp, &timeout)) 185 return SM_IO_EOF; 186 fp->f_flags &= ~SMWR; 187 fp->f_w = 0; 188 fp->f_lbfsize = 0; 189 } 190 fp->f_flags |= SMRD; 191 } 192 else 193 { 194 /* 195 ** We were reading. If there is an ungetc buffer, 196 ** we must have been reading from that. Drop it, 197 ** restoring the previous buffer (if any). If there 198 ** is anything in that buffer, return. 199 */ 200 201 if (HASUB(fp)) 202 { 203 FREEUB(fp); 204 if ((fp->f_r = fp->f_ur) != 0) 205 { 206 fp->f_p = fp->f_up; 207 208 /* revert blocking state */ 209 return 0; 210 } 211 } 212 } 213 214 if (fp->f_bf.smb_base == NULL) 215 sm_makebuf(fp); 216 217 /* 218 ** Before reading from a line buffered or unbuffered file, 219 ** flush all line buffered output files, per the ANSI C standard. 220 */ 221 222 if (fp->f_flags & (SMLBF|SMNBF)) 223 (void) sm_fwalk(sm_lflush, &timeout); 224 225 /* 226 ** If this file is linked to another, and we are going to hang 227 ** on the read, flush the linked file before continuing. 228 */ 229 230 if (fp->f_flushfp != NULL && 231 (*fp->f_getinfo)(fp, SM_IO_IS_READABLE, NULL) <= 0) 232 sm_flush(fp->f_flushfp, &timeout); 233 234 fp->f_p = fp->f_bf.smb_base; 235 236 /* 237 ** The do-while loop stops trying to read when something is read 238 ** or it appears that the timeout has expired before finding 239 ** something available to be read (via select()). 240 */ 241 242 ret = 0; 243 do 244 { 245 errno = 0; /* needed to ensure EOF correctly found */ 246 r = (*fp->f_read)(fp, (char *)fp->f_p, fp->f_bf.smb_size); 247 if (r <= 0) 248 { 249 if (r == 0 && errno == 0) 250 break; /* EOF found */ 251 if (IS_IO_ERROR(fd, r, timeout)) 252 goto err; /* errno set */ 253 254 /* read would block */ 255 SM_IO_RD_TIMEOUT(fp, fd, &to, timeout, ret); 256 } 257 } while (r <= 0 && ret > 0); 258 259 err: 260 if (r <= 0) 261 { 262 if (r == 0) 263 fp->f_flags |= SMFEOF; 264 else 265 fp->f_flags |= SMERR; 266 fp->f_r = 0; 267 return SM_IO_EOF; 268 } 269 fp->f_r = r; 270 return 0; 271 } 272 273 /* 274 ** SM_RGET -- refills buffer and returns first character 275 ** 276 ** Handle sm_getc() when the buffer ran out: 277 ** Refill, then return the first character in the newly-filled buffer. 278 ** 279 ** Parameters: 280 ** fp -- file pointer to work on 281 ** timeout -- time to complete refill 282 ** 283 ** Returns: 284 ** Success: first character in refilled buffer as an int 285 ** Failure: SM_IO_EOF 286 */ 287 288 int 289 sm_rget(fp, timeout) 290 register SM_FILE_T *fp; 291 int timeout; 292 { 293 if (sm_refill(fp, timeout) == 0) 294 { 295 fp->f_r--; 296 return *fp->f_p++; 297 } 298 return SM_IO_EOF; 299 } 300