xref: /freebsd/contrib/sendmail/libsm/setvbuf.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
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