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