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