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