1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1990, 1993 5*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by 8*7c478bd9Sstevel@tonic-gate * Chris Torek. 9*7c478bd9Sstevel@tonic-gate * 10*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 11*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 12*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 13*7c478bd9Sstevel@tonic-gate */ 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate #include <sm/gen.h> 16*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: setvbuf.c,v 1.30 2001/02/28 20:25:18 rodney Exp $") 17*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 18*7c478bd9Sstevel@tonic-gate #include <errno.h> 19*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 20*7c478bd9Sstevel@tonic-gate #include <sm/io.h> 21*7c478bd9Sstevel@tonic-gate #include <sm/heap.h> 22*7c478bd9Sstevel@tonic-gate #include <sm/assert.h> 23*7c478bd9Sstevel@tonic-gate #include <sm/conf.h> 24*7c478bd9Sstevel@tonic-gate #include "local.h" 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate ** SM_IO_SETVBUF -- set the buffering type for a file 28*7c478bd9Sstevel@tonic-gate ** 29*7c478bd9Sstevel@tonic-gate ** Set one of the different kinds of buffering, optionally including 30*7c478bd9Sstevel@tonic-gate ** a buffer. 31*7c478bd9Sstevel@tonic-gate ** If 'size' is == 0 then an "optimal" size will be selected. 32*7c478bd9Sstevel@tonic-gate ** If 'buf' is == NULL then space will be allocated at 'size'. 33*7c478bd9Sstevel@tonic-gate ** 34*7c478bd9Sstevel@tonic-gate ** Parameters: 35*7c478bd9Sstevel@tonic-gate ** fp -- the file that buffering is to be changed for 36*7c478bd9Sstevel@tonic-gate ** timeout -- time allowed for completing the function 37*7c478bd9Sstevel@tonic-gate ** buf -- buffer to use 38*7c478bd9Sstevel@tonic-gate ** mode -- buffering method to use 39*7c478bd9Sstevel@tonic-gate ** size -- size of 'buf' 40*7c478bd9Sstevel@tonic-gate ** 41*7c478bd9Sstevel@tonic-gate ** Returns: 42*7c478bd9Sstevel@tonic-gate ** Failure: SM_IO_EOF 43*7c478bd9Sstevel@tonic-gate ** Success: 0 (zero) 44*7c478bd9Sstevel@tonic-gate */ 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate int 47*7c478bd9Sstevel@tonic-gate sm_io_setvbuf(fp, timeout, buf, mode, size) 48*7c478bd9Sstevel@tonic-gate SM_FILE_T *fp; 49*7c478bd9Sstevel@tonic-gate int timeout; 50*7c478bd9Sstevel@tonic-gate char *buf; 51*7c478bd9Sstevel@tonic-gate int mode; 52*7c478bd9Sstevel@tonic-gate size_t size; 53*7c478bd9Sstevel@tonic-gate { 54*7c478bd9Sstevel@tonic-gate int ret, flags; 55*7c478bd9Sstevel@tonic-gate size_t iosize; 56*7c478bd9Sstevel@tonic-gate int ttyflag; 57*7c478bd9Sstevel@tonic-gate int fd; 58*7c478bd9Sstevel@tonic-gate struct timeval to; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate SM_REQUIRE_ISA(fp, SmFileMagic); 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate /* 63*7c478bd9Sstevel@tonic-gate ** Verify arguments. The `int' limit on `size' is due to this 64*7c478bd9Sstevel@tonic-gate ** particular implementation. Note, buf and size are ignored 65*7c478bd9Sstevel@tonic-gate ** when setting SM_IO_NBF. 66*7c478bd9Sstevel@tonic-gate */ 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate if (mode != SM_IO_NBF) 69*7c478bd9Sstevel@tonic-gate if ((mode != SM_IO_FBF && mode != SM_IO_LBF && 70*7c478bd9Sstevel@tonic-gate mode != SM_IO_NOW) || (int) size < 0) 71*7c478bd9Sstevel@tonic-gate return SM_IO_EOF; 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate ** Write current buffer, if any. Discard unread input (including 75*7c478bd9Sstevel@tonic-gate ** ungetc data), cancel line buffering, and free old buffer if 76*7c478bd9Sstevel@tonic-gate ** malloc()ed. We also clear any eof condition, as if this were 77*7c478bd9Sstevel@tonic-gate ** a seek. 78*7c478bd9Sstevel@tonic-gate */ 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate ret = 0; 81*7c478bd9Sstevel@tonic-gate SM_CONVERT_TIME(fp, fd, timeout, &to); 82*7c478bd9Sstevel@tonic-gate (void) sm_flush(fp, &timeout); 83*7c478bd9Sstevel@tonic-gate if (HASUB(fp)) 84*7c478bd9Sstevel@tonic-gate FREEUB(fp); 85*7c478bd9Sstevel@tonic-gate fp->f_r = fp->f_lbfsize = 0; 86*7c478bd9Sstevel@tonic-gate flags = fp->f_flags; 87*7c478bd9Sstevel@tonic-gate if (flags & SMMBF) 88*7c478bd9Sstevel@tonic-gate { 89*7c478bd9Sstevel@tonic-gate sm_free((void *) fp->f_bf.smb_base); 90*7c478bd9Sstevel@tonic-gate fp->f_bf.smb_base = NULL; 91*7c478bd9Sstevel@tonic-gate } 92*7c478bd9Sstevel@tonic-gate flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW | 93*7c478bd9Sstevel@tonic-gate SMFBF); 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* If setting unbuffered mode, skip all the hard work. */ 96*7c478bd9Sstevel@tonic-gate if (mode == SM_IO_NBF) 97*7c478bd9Sstevel@tonic-gate goto nbf; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* 100*7c478bd9Sstevel@tonic-gate ** Find optimal I/O size for seek optimization. This also returns 101*7c478bd9Sstevel@tonic-gate ** a `tty flag' to suggest that we check isatty(fd), but we do not 102*7c478bd9Sstevel@tonic-gate ** care since our caller told us how to buffer. 103*7c478bd9Sstevel@tonic-gate */ 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate flags |= sm_whatbuf(fp, &iosize, &ttyflag); 106*7c478bd9Sstevel@tonic-gate if (size == 0) 107*7c478bd9Sstevel@tonic-gate { 108*7c478bd9Sstevel@tonic-gate buf = NULL; /* force local allocation */ 109*7c478bd9Sstevel@tonic-gate size = iosize; 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* Allocate buffer if needed. */ 113*7c478bd9Sstevel@tonic-gate if (buf == NULL) 114*7c478bd9Sstevel@tonic-gate { 115*7c478bd9Sstevel@tonic-gate if ((buf = sm_malloc(size)) == NULL) 116*7c478bd9Sstevel@tonic-gate { 117*7c478bd9Sstevel@tonic-gate /* 118*7c478bd9Sstevel@tonic-gate ** Unable to honor user's request. We will return 119*7c478bd9Sstevel@tonic-gate ** failure, but try again with file system size. 120*7c478bd9Sstevel@tonic-gate */ 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate ret = SM_IO_EOF; 123*7c478bd9Sstevel@tonic-gate if (size != iosize) 124*7c478bd9Sstevel@tonic-gate { 125*7c478bd9Sstevel@tonic-gate size = iosize; 126*7c478bd9Sstevel@tonic-gate buf = sm_malloc(size); 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate if (buf == NULL) 130*7c478bd9Sstevel@tonic-gate { 131*7c478bd9Sstevel@tonic-gate /* No luck; switch to unbuffered I/O. */ 132*7c478bd9Sstevel@tonic-gate nbf: 133*7c478bd9Sstevel@tonic-gate fp->f_flags = flags | SMNBF; 134*7c478bd9Sstevel@tonic-gate fp->f_w = 0; 135*7c478bd9Sstevel@tonic-gate fp->f_bf.smb_base = fp->f_p = fp->f_nbuf; 136*7c478bd9Sstevel@tonic-gate fp->f_bf.smb_size = 1; 137*7c478bd9Sstevel@tonic-gate return ret; 138*7c478bd9Sstevel@tonic-gate } 139*7c478bd9Sstevel@tonic-gate flags |= SMMBF; 140*7c478bd9Sstevel@tonic-gate } 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate /* 143*7c478bd9Sstevel@tonic-gate ** Kill any seek optimization if the buffer is not the 144*7c478bd9Sstevel@tonic-gate ** right size. 145*7c478bd9Sstevel@tonic-gate ** 146*7c478bd9Sstevel@tonic-gate ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? 147*7c478bd9Sstevel@tonic-gate */ 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate if (size != iosize) 150*7c478bd9Sstevel@tonic-gate flags |= SMNPT; 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate /* 153*7c478bd9Sstevel@tonic-gate ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on 154*7c478bd9Sstevel@tonic-gate ** exit (since we are buffered in some way). 155*7c478bd9Sstevel@tonic-gate */ 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate if (mode == SM_IO_LBF) 158*7c478bd9Sstevel@tonic-gate flags |= SMLBF; 159*7c478bd9Sstevel@tonic-gate else if (mode == SM_IO_NOW) 160*7c478bd9Sstevel@tonic-gate flags |= SMNOW; 161*7c478bd9Sstevel@tonic-gate else if (mode == SM_IO_FBF) 162*7c478bd9Sstevel@tonic-gate flags |= SMFBF; 163*7c478bd9Sstevel@tonic-gate fp->f_flags = flags; 164*7c478bd9Sstevel@tonic-gate fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf; 165*7c478bd9Sstevel@tonic-gate fp->f_bf.smb_size = size; 166*7c478bd9Sstevel@tonic-gate /* fp->f_lbfsize is still 0 */ 167*7c478bd9Sstevel@tonic-gate if (flags & SMWR) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate /* 170*7c478bd9Sstevel@tonic-gate ** Begin or continue writing: see sm_wsetup(). Note 171*7c478bd9Sstevel@tonic-gate ** that SMNBF is impossible (it was handled earlier). 172*7c478bd9Sstevel@tonic-gate */ 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate if (flags & SMLBF) 175*7c478bd9Sstevel@tonic-gate { 176*7c478bd9Sstevel@tonic-gate fp->f_w = 0; 177*7c478bd9Sstevel@tonic-gate fp->f_lbfsize = -fp->f_bf.smb_size; 178*7c478bd9Sstevel@tonic-gate } 179*7c478bd9Sstevel@tonic-gate else 180*7c478bd9Sstevel@tonic-gate fp->f_w = size; 181*7c478bd9Sstevel@tonic-gate } 182*7c478bd9Sstevel@tonic-gate else 183*7c478bd9Sstevel@tonic-gate { 184*7c478bd9Sstevel@tonic-gate /* begin/continue reading, or stay in intermediate state */ 185*7c478bd9Sstevel@tonic-gate fp->f_w = 0; 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate atexit(sm_cleanup); 189*7c478bd9Sstevel@tonic-gate return ret; 190*7c478bd9Sstevel@tonic-gate } 191