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