190792Sgshapiro/*
2261194Sgshapiro * Copyright (c) 2000-2001, 2005, 2006 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *      All rights reserved.
490792Sgshapiro * Copyright (c) 1990, 1993
590792Sgshapiro *	The Regents of the University of California.  All rights reserved.
690792Sgshapiro *
790792Sgshapiro * This code is derived from software contributed to Berkeley by
890792Sgshapiro * Chris Torek.
990792Sgshapiro *
1090792Sgshapiro * By using this file, you agree to the terms and conditions set
1190792Sgshapiro * forth in the LICENSE file which can be found at the top level of
1290792Sgshapiro * the sendmail distribution.
1390792Sgshapiro */
1490792Sgshapiro
1590792Sgshapiro#include <sm/gen.h>
16266527SgshapiroSM_RCSID("@(#)$Id: fflush.c,v 1.46 2013-11-22 20:51:42 ca Exp $")
1790792Sgshapiro#include <unistd.h>
1890792Sgshapiro#include <errno.h>
19157001Sgshapiro#include <sm/time.h>
2090792Sgshapiro#include <signal.h>
2190792Sgshapiro#include <fcntl.h>
2290792Sgshapiro#include <string.h>
2390792Sgshapiro#include <sm/io.h>
2490792Sgshapiro#include <sm/assert.h>
2590792Sgshapiro#include <sm/setjmp.h>
2690792Sgshapiro#include "local.h"
2790792Sgshapiro#include <sm/conf.h>
2890792Sgshapiro
2990792Sgshapiro/*
3090792Sgshapiro**  SM_IO_FLUSH -- flush the buffer for a 'fp' to the "file"
3190792Sgshapiro**
3290792Sgshapiro**  Flush a single file. We don't allow this function to flush
3390792Sgshapiro**  all open files when fp==NULL any longer.
3490792Sgshapiro**
3590792Sgshapiro**	Parameters:
3690792Sgshapiro**		fp -- the file pointer buffer to flush
3790792Sgshapiro**		timeout -- time to complete the flush
3890792Sgshapiro**
3990792Sgshapiro**	Results:
4090792Sgshapiro**		Failure: SM_IO_EOF and sets errno
4190792Sgshapiro**		Success: 0 (zero)
4290792Sgshapiro*/
4390792Sgshapiro
4490792Sgshapiroint
4590792Sgshapirosm_io_flush(fp, timeout)
4690792Sgshapiro	register SM_FILE_T *fp;
4790792Sgshapiro	int SM_NONVOLATILE timeout;
4890792Sgshapiro{
4990792Sgshapiro	int fd;
5090792Sgshapiro	struct timeval to;
5190792Sgshapiro
5290792Sgshapiro	SM_REQUIRE_ISA(fp, SmFileMagic);
5390792Sgshapiro
5490792Sgshapiro	if ((fp->f_flags & (SMWR | SMRW)) == 0)
5590792Sgshapiro	{
5690792Sgshapiro		/*
5790792Sgshapiro		**  The file is not opened for writing, so it cannot be flushed
5890792Sgshapiro		**  (writable means SMWR [write] or SMRW [read/write].
5990792Sgshapiro		*/
6090792Sgshapiro
6190792Sgshapiro		errno = EBADF;
6290792Sgshapiro		return SM_IO_EOF;
6390792Sgshapiro	}
6490792Sgshapiro
6590792Sgshapiro	SM_CONVERT_TIME(fp, fd, timeout, &to);
6690792Sgshapiro
6790792Sgshapiro	/* Now do the flush */
6890792Sgshapiro	return sm_flush(fp, (int *) &timeout);
6990792Sgshapiro}
7090792Sgshapiro
7190792Sgshapiro/*
7290792Sgshapiro**  SM_FLUSH -- perform the actual flush
7390792Sgshapiro**
7490792Sgshapiro**  Assumes that 'fp' has been validated before this function called.
7590792Sgshapiro**
7690792Sgshapiro**	Parameters:
7790792Sgshapiro**		fp -- file pointer to be flushed
7890792Sgshapiro**		timeout -- max time allowed for flush (milliseconds)
7990792Sgshapiro**
8090792Sgshapiro**	Results:
8190792Sgshapiro**		Success: 0 (zero)
8290792Sgshapiro**		Failure: SM_IO_EOF and errno set
8390792Sgshapiro**
8490792Sgshapiro**	Side Effects:
8590792Sgshapiro**		timeout will get updated with the time remaining (if any)
8690792Sgshapiro*/
8790792Sgshapiro
8890792Sgshapiroint
8990792Sgshapirosm_flush(fp, timeout)
9090792Sgshapiro	register SM_FILE_T *fp;
9190792Sgshapiro	int *timeout;
9290792Sgshapiro{
9390792Sgshapiro	register unsigned char *p;
9490792Sgshapiro	register int n, t;
9590792Sgshapiro	int fd;
9690792Sgshapiro
9790792Sgshapiro	SM_REQUIRE_ISA(fp, SmFileMagic);
9890792Sgshapiro
9990792Sgshapiro	t = fp->f_flags;
10090792Sgshapiro	if ((t & SMWR) == 0)
10190792Sgshapiro		return 0;
10290792Sgshapiro
10390792Sgshapiro	if (t & SMSTR)
10490792Sgshapiro	{
10590792Sgshapiro		*fp->f_p = '\0';
10690792Sgshapiro		return 0;
10790792Sgshapiro	}
10890792Sgshapiro
10990792Sgshapiro	if ((p = fp->f_bf.smb_base) == NULL)
11090792Sgshapiro		return 0;
11190792Sgshapiro
11290792Sgshapiro	n = fp->f_p - p;		/* write this much */
11390792Sgshapiro
11490792Sgshapiro	if ((fd = sm_io_getinfo(fp, SM_IO_WHAT_FD, NULL)) == -1)
11590792Sgshapiro	{
11690792Sgshapiro		/* can't get an fd, likely internal 'fake' fp */
11790792Sgshapiro		errno = 0;
11890792Sgshapiro		fd = -1;
11990792Sgshapiro	}
12090792Sgshapiro
12190792Sgshapiro	/*
12290792Sgshapiro	**  Set these immediately to avoid problems with longjmp and to allow
12390792Sgshapiro	**  exchange buffering (via setvbuf) in user write function.
12490792Sgshapiro	*/
12590792Sgshapiro
12690792Sgshapiro	fp->f_p = p;
12790792Sgshapiro	fp->f_w = t & (SMLBF|SMNBF) ? 0 : fp->f_bf.smb_size; /* implies SMFBF */
12890792Sgshapiro
12990792Sgshapiro	for (; n > 0; n -= t, p += t)
13090792Sgshapiro	{
13190792Sgshapiro		errno = 0; /* needed to ensure EOF correctly found */
13290792Sgshapiro
13390792Sgshapiro		/* Call the file type's write function */
13490792Sgshapiro		t = (*fp->f_write)(fp, (char *)p, n);
13590792Sgshapiro		if (t <= 0)
13690792Sgshapiro		{
13790792Sgshapiro			if (t == 0 && errno == 0)
13890792Sgshapiro				break; /* EOF found */
13990792Sgshapiro
14090792Sgshapiro			if (IS_IO_ERROR(fd, t, *timeout))
14190792Sgshapiro			{
14290792Sgshapiro				fp->f_flags |= SMERR;
14390792Sgshapiro
14490792Sgshapiro				/* errno set by fp->f_write */
14590792Sgshapiro				return SM_IO_EOF;
14690792Sgshapiro			}
14790792Sgshapiro			SM_IO_WR_TIMEOUT(fp, fd, *timeout);
148157001Sgshapiro			t = 0;
14990792Sgshapiro		}
15090792Sgshapiro	}
15190792Sgshapiro	return 0;
15290792Sgshapiro}
153