fclose.c revision 266692
1/*
2 * Copyright (c) 2000-2002, 2004 Proofpoint, Inc. and its suppliers.
3 *      All rights reserved.
4 * Copyright (c) 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Chris Torek.
9 *
10 * By using this file, you agree to the terms and conditions set
11 * forth in the LICENSE file which can be found at the top level of
12 * the sendmail distribution.
13 */
14
15#include <sm/gen.h>
16SM_RCSID("@(#)$Id: fclose.c,v 1.45 2013-11-22 20:51:42 ca Exp $")
17#include <errno.h>
18#include <stdlib.h>
19#include <sm/time.h>
20#include <setjmp.h>
21#include <sm/io.h>
22#include <sm/assert.h>
23#include <sm/heap.h>
24#include <sm/signal.h>
25#include <sm/conf.h>
26#include <sm/clock.h>
27#include "local.h"
28
29static void	closealrm __P((int));
30static jmp_buf CloseTimeOut;
31
32/*
33**  CLOSEALRM -- handler when timeout activated for sm_io_close()
34**
35**	Returns flow of control to where setjmp(CloseTimeOut) was set.
36**
37**	Parameters:
38**		sig -- unused
39**
40**	Returns:
41**		does not return
42**
43**	Side Effects:
44**		returns flow of control to setjmp(CloseTimeOut).
45**
46**	NOTE:	THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
47**		ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
48**		DOING.
49*/
50
51/* ARGSUSED0 */
52static void
53closealrm(sig)
54	int sig;
55{
56	longjmp(CloseTimeOut, 1);
57}
58
59/*
60**  SM_IO_CLOSE -- close a file handle/pointer
61**
62**	Parameters:
63**		fp -- file pointer to be closed
64**		timeout -- maximum time allowed to perform the close (millisecs)
65**
66**	Returns:
67**		0 on success
68**		-1 on failure and sets errno
69**
70**	Side Effects:
71**		file pointer 'fp' will no longer be valid.
72*/
73
74int
75sm_io_close(fp, timeout)
76	register SM_FILE_T *fp;
77	int SM_NONVOLATILE timeout;
78{
79	register int SM_NONVOLATILE r;
80	SM_EVENT *evt = NULL;
81
82	if (fp == NULL)
83	{
84		errno = EBADF;
85		return SM_IO_EOF;
86	}
87
88	SM_REQUIRE_ISA(fp, SmFileMagic);
89
90	/* XXX this won't be reached if above macro is active */
91	if (fp->sm_magic == NULL)
92	{
93		/* not open! */
94		errno = EBADF;
95		return SM_IO_EOF;
96	}
97	if (fp->f_close == NULL)
98	{
99		/* no close function! */
100		errno = ENODEV;
101		return SM_IO_EOF;
102	}
103	if (fp->f_dup_cnt > 0)
104	{
105		/* decrement file pointer open count */
106		fp->f_dup_cnt--;
107		return 0;
108	}
109
110	/*  Okay, this is where we set the timeout.  */
111	if (timeout == SM_TIME_DEFAULT)
112		timeout = fp->f_timeout;
113	if (timeout == SM_TIME_IMMEDIATE)
114	{
115		errno = EAGAIN;
116		return -1;
117	}
118
119	/* No more duplicates of file pointer. Flush buffer and close */
120	r = fp->f_flags & SMWR ? sm_flush(fp, (int *) &timeout) : 0;
121
122	/* sm_flush() has updated to.it_value for the time it's used */
123	if (timeout != SM_TIME_FOREVER)
124	{
125		if (setjmp(CloseTimeOut) != 0)
126		{
127			errno = EAGAIN;
128			return SM_IO_EOF;
129		}
130		evt = sm_seteventm(timeout, closealrm, 0);
131	}
132	if ((*fp->f_close)(fp) < 0)
133		r = SM_IO_EOF;
134
135	/*  We're back. So undo our timeout and handler */
136	if (evt != NULL)
137		sm_clrevent(evt);
138	if (fp->f_flags & SMMBF)
139	{
140		sm_free((char *)fp->f_bf.smb_base);
141		fp->f_bf.smb_base = NULL;
142	}
143	if (HASUB(fp))
144		FREEUB(fp);
145	fp->f_flags = 0;	/* clear flags */
146	fp->sm_magic = NULL;	/* Release this SM_FILE_T for reuse. */
147	fp->f_r = fp->f_w = 0;	/* Mess up if reaccessed. */
148	return r;
149}
150