xref: /freebsd/contrib/sendmail/libsm/fclose.c (revision 9336e0699bda8a301cd2bfa37106b6ec5e32012e)
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 #include <sm/gen.h>
16 SM_RCSID("@(#)$Id: fclose.c,v 1.44 2005/06/14 23:07:20 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 
29 static void	closealrm __P((int));
30 static 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 */
52 static void
53 closealrm(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 
74 int
75 sm_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