140266059SGregory Neil Shapiro /* 25dd76dd0SGregory Neil Shapiro * Copyright (c) 2000-2001 Proofpoint, Inc. and its suppliers. 340266059SGregory Neil Shapiro * All rights reserved. 440266059SGregory Neil Shapiro * Copyright (c) 1990, 1993 540266059SGregory Neil Shapiro * The Regents of the University of California. All rights reserved. 640266059SGregory Neil Shapiro * 740266059SGregory Neil Shapiro * This code is derived from software contributed to Berkeley by 840266059SGregory Neil Shapiro * Chris Torek. 940266059SGregory Neil Shapiro * 1040266059SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 1140266059SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 1240266059SGregory Neil Shapiro * the sendmail distribution. 1340266059SGregory Neil Shapiro */ 1440266059SGregory Neil Shapiro 1540266059SGregory Neil Shapiro #include <sm/gen.h> 164313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: setvbuf.c,v 1.33 2013-11-22 20:51:43 ca Exp $") 1740266059SGregory Neil Shapiro #include <stdlib.h> 1840266059SGregory Neil Shapiro #include <errno.h> 1940266059SGregory Neil Shapiro #include <fcntl.h> 20*d39bd2c1SGregory Neil Shapiro #include <sm/limits.h> 2140266059SGregory Neil Shapiro #include <sm/io.h> 2240266059SGregory Neil Shapiro #include <sm/heap.h> 2340266059SGregory Neil Shapiro #include <sm/assert.h> 2440266059SGregory Neil Shapiro #include <sm/conf.h> 2540266059SGregory Neil Shapiro #include "local.h" 2640266059SGregory Neil Shapiro 2740266059SGregory Neil Shapiro /* 2840266059SGregory Neil Shapiro ** SM_IO_SETVBUF -- set the buffering type for a file 2940266059SGregory Neil Shapiro ** 3040266059SGregory Neil Shapiro ** Set one of the different kinds of buffering, optionally including 3140266059SGregory Neil Shapiro ** a buffer. 3240266059SGregory Neil Shapiro ** If 'size' is == 0 then an "optimal" size will be selected. 3340266059SGregory Neil Shapiro ** If 'buf' is == NULL then space will be allocated at 'size'. 3440266059SGregory Neil Shapiro ** 3540266059SGregory Neil Shapiro ** Parameters: 3640266059SGregory Neil Shapiro ** fp -- the file that buffering is to be changed for 3740266059SGregory Neil Shapiro ** timeout -- time allowed for completing the function 3840266059SGregory Neil Shapiro ** buf -- buffer to use 3940266059SGregory Neil Shapiro ** mode -- buffering method to use 4040266059SGregory Neil Shapiro ** size -- size of 'buf' 4140266059SGregory Neil Shapiro ** 4240266059SGregory Neil Shapiro ** Returns: 4340266059SGregory Neil Shapiro ** Failure: SM_IO_EOF 4440266059SGregory Neil Shapiro ** Success: 0 (zero) 4540266059SGregory Neil Shapiro */ 4640266059SGregory Neil Shapiro 4740266059SGregory Neil Shapiro int 4840266059SGregory Neil Shapiro sm_io_setvbuf(fp, timeout, buf, mode, size) 4940266059SGregory Neil Shapiro SM_FILE_T *fp; 5040266059SGregory Neil Shapiro int timeout; 5140266059SGregory Neil Shapiro char *buf; 5240266059SGregory Neil Shapiro int mode; 5340266059SGregory Neil Shapiro size_t size; 5440266059SGregory Neil Shapiro { 5540266059SGregory Neil Shapiro int ret, flags; 5640266059SGregory Neil Shapiro size_t iosize; 5740266059SGregory Neil Shapiro int ttyflag; 5840266059SGregory Neil Shapiro int fd; 5940266059SGregory Neil Shapiro struct timeval to; 6040266059SGregory Neil Shapiro 6140266059SGregory Neil Shapiro SM_REQUIRE_ISA(fp, SmFileMagic); 6240266059SGregory Neil Shapiro 6340266059SGregory Neil Shapiro /* 6440266059SGregory Neil Shapiro ** Verify arguments. The `int' limit on `size' is due to this 6540266059SGregory Neil Shapiro ** particular implementation. Note, buf and size are ignored 6640266059SGregory Neil Shapiro ** when setting SM_IO_NBF. 6740266059SGregory Neil Shapiro */ 6840266059SGregory Neil Shapiro 6940266059SGregory Neil Shapiro if (mode != SM_IO_NBF) 7040266059SGregory Neil Shapiro if ((mode != SM_IO_FBF && mode != SM_IO_LBF && 71*d39bd2c1SGregory Neil Shapiro mode != SM_IO_NOW) || size > INT_MAX) 7240266059SGregory Neil Shapiro return SM_IO_EOF; 7340266059SGregory Neil Shapiro 7440266059SGregory Neil Shapiro /* 7540266059SGregory Neil Shapiro ** Write current buffer, if any. Discard unread input (including 7640266059SGregory Neil Shapiro ** ungetc data), cancel line buffering, and free old buffer if 7740266059SGregory Neil Shapiro ** malloc()ed. We also clear any eof condition, as if this were 7840266059SGregory Neil Shapiro ** a seek. 7940266059SGregory Neil Shapiro */ 8040266059SGregory Neil Shapiro 8140266059SGregory Neil Shapiro ret = 0; 8240266059SGregory Neil Shapiro SM_CONVERT_TIME(fp, fd, timeout, &to); 8340266059SGregory Neil Shapiro (void) sm_flush(fp, &timeout); 8440266059SGregory Neil Shapiro if (HASUB(fp)) 8540266059SGregory Neil Shapiro FREEUB(fp); 8640266059SGregory Neil Shapiro fp->f_r = fp->f_lbfsize = 0; 8740266059SGregory Neil Shapiro flags = fp->f_flags; 8840266059SGregory Neil Shapiro if (flags & SMMBF) 8940266059SGregory Neil Shapiro { 9040266059SGregory Neil Shapiro sm_free((void *) fp->f_bf.smb_base); 9140266059SGregory Neil Shapiro fp->f_bf.smb_base = NULL; 9240266059SGregory Neil Shapiro } 9340266059SGregory Neil Shapiro flags &= ~(SMLBF | SMNBF | SMMBF | SMOPT | SMNPT | SMFEOF | SMNOW | 9440266059SGregory Neil Shapiro SMFBF); 9540266059SGregory Neil Shapiro 9640266059SGregory Neil Shapiro /* If setting unbuffered mode, skip all the hard work. */ 9740266059SGregory Neil Shapiro if (mode == SM_IO_NBF) 9840266059SGregory Neil Shapiro goto nbf; 9940266059SGregory Neil Shapiro 10040266059SGregory Neil Shapiro /* 10140266059SGregory Neil Shapiro ** Find optimal I/O size for seek optimization. This also returns 10240266059SGregory Neil Shapiro ** a `tty flag' to suggest that we check isatty(fd), but we do not 10340266059SGregory Neil Shapiro ** care since our caller told us how to buffer. 10440266059SGregory Neil Shapiro */ 10540266059SGregory Neil Shapiro 10640266059SGregory Neil Shapiro flags |= sm_whatbuf(fp, &iosize, &ttyflag); 10740266059SGregory Neil Shapiro if (size == 0) 10840266059SGregory Neil Shapiro { 10940266059SGregory Neil Shapiro buf = NULL; /* force local allocation */ 11040266059SGregory Neil Shapiro size = iosize; 11140266059SGregory Neil Shapiro } 11240266059SGregory Neil Shapiro 11340266059SGregory Neil Shapiro /* Allocate buffer if needed. */ 11440266059SGregory Neil Shapiro if (buf == NULL) 11540266059SGregory Neil Shapiro { 11640266059SGregory Neil Shapiro if ((buf = sm_malloc(size)) == NULL) 11740266059SGregory Neil Shapiro { 11840266059SGregory Neil Shapiro /* 11940266059SGregory Neil Shapiro ** Unable to honor user's request. We will return 12040266059SGregory Neil Shapiro ** failure, but try again with file system size. 12140266059SGregory Neil Shapiro */ 12240266059SGregory Neil Shapiro 12340266059SGregory Neil Shapiro ret = SM_IO_EOF; 12440266059SGregory Neil Shapiro if (size != iosize) 12540266059SGregory Neil Shapiro { 12640266059SGregory Neil Shapiro size = iosize; 12740266059SGregory Neil Shapiro buf = sm_malloc(size); 12840266059SGregory Neil Shapiro } 12940266059SGregory Neil Shapiro } 13040266059SGregory Neil Shapiro if (buf == NULL) 13140266059SGregory Neil Shapiro { 13240266059SGregory Neil Shapiro /* No luck; switch to unbuffered I/O. */ 13340266059SGregory Neil Shapiro nbf: 13440266059SGregory Neil Shapiro fp->f_flags = flags | SMNBF; 13540266059SGregory Neil Shapiro fp->f_w = 0; 13640266059SGregory Neil Shapiro fp->f_bf.smb_base = fp->f_p = fp->f_nbuf; 13740266059SGregory Neil Shapiro fp->f_bf.smb_size = 1; 13840266059SGregory Neil Shapiro return ret; 13940266059SGregory Neil Shapiro } 14040266059SGregory Neil Shapiro flags |= SMMBF; 14140266059SGregory Neil Shapiro } 14240266059SGregory Neil Shapiro 14340266059SGregory Neil Shapiro /* 14440266059SGregory Neil Shapiro ** Kill any seek optimization if the buffer is not the 14540266059SGregory Neil Shapiro ** right size. 14640266059SGregory Neil Shapiro ** 14740266059SGregory Neil Shapiro ** SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)? 14840266059SGregory Neil Shapiro */ 14940266059SGregory Neil Shapiro 15040266059SGregory Neil Shapiro if (size != iosize) 15140266059SGregory Neil Shapiro flags |= SMNPT; 15240266059SGregory Neil Shapiro 15340266059SGregory Neil Shapiro /* 15440266059SGregory Neil Shapiro ** Fix up the SM_FILE_T fields, and set sm_cleanup for output flush on 15540266059SGregory Neil Shapiro ** exit (since we are buffered in some way). 15640266059SGregory Neil Shapiro */ 15740266059SGregory Neil Shapiro 15840266059SGregory Neil Shapiro if (mode == SM_IO_LBF) 15940266059SGregory Neil Shapiro flags |= SMLBF; 16040266059SGregory Neil Shapiro else if (mode == SM_IO_NOW) 16140266059SGregory Neil Shapiro flags |= SMNOW; 16240266059SGregory Neil Shapiro else if (mode == SM_IO_FBF) 16340266059SGregory Neil Shapiro flags |= SMFBF; 16440266059SGregory Neil Shapiro fp->f_flags = flags; 16540266059SGregory Neil Shapiro fp->f_bf.smb_base = fp->f_p = (unsigned char *)buf; 16640266059SGregory Neil Shapiro fp->f_bf.smb_size = size; 16740266059SGregory Neil Shapiro /* fp->f_lbfsize is still 0 */ 16840266059SGregory Neil Shapiro if (flags & SMWR) 16940266059SGregory Neil Shapiro { 17040266059SGregory Neil Shapiro /* 17140266059SGregory Neil Shapiro ** Begin or continue writing: see sm_wsetup(). Note 17240266059SGregory Neil Shapiro ** that SMNBF is impossible (it was handled earlier). 17340266059SGregory Neil Shapiro */ 17440266059SGregory Neil Shapiro 17540266059SGregory Neil Shapiro if (flags & SMLBF) 17640266059SGregory Neil Shapiro { 17740266059SGregory Neil Shapiro fp->f_w = 0; 17840266059SGregory Neil Shapiro fp->f_lbfsize = -fp->f_bf.smb_size; 17940266059SGregory Neil Shapiro } 18040266059SGregory Neil Shapiro else 18140266059SGregory Neil Shapiro fp->f_w = size; 18240266059SGregory Neil Shapiro } 18340266059SGregory Neil Shapiro else 18440266059SGregory Neil Shapiro { 18540266059SGregory Neil Shapiro /* begin/continue reading, or stay in intermediate state */ 18640266059SGregory Neil Shapiro fp->f_w = 0; 18740266059SGregory Neil Shapiro } 18840266059SGregory Neil Shapiro 18940266059SGregory Neil Shapiro atexit(sm_cleanup); 19040266059SGregory Neil Shapiro return ret; 19140266059SGregory Neil Shapiro } 192