xref: /freebsd/contrib/sendmail/libsm/fclose.c (revision 42c159fe388a3765f69860c84183700af37aca8a)
1 /*
2  * Copyright (c) 2000-2001 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.41 2001/09/11 04:04:48 gshapiro 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 	if (fp->sm_magic == NULL)
90 	{
91 		/* not open! */
92 		errno = EBADF;
93 		return SM_IO_EOF;
94 	}
95 	if (fp->f_close == NULL)
96 	{
97 		/* no close function! */
98 		errno = ENODEV;
99 		return SM_IO_EOF;
100 	}
101 	if (fp->f_dup_cnt > 0)
102 	{
103 		/* decrement file pointer open count */
104 		fp->f_dup_cnt--;
105 		return 0;
106 	}
107 
108 	/*  Okay, this is where we set the timeout.  */
109 	if (timeout == SM_TIME_DEFAULT)
110 		timeout = fp->f_timeout;
111 	if (timeout == SM_TIME_IMMEDIATE)
112 	{
113 		errno = EAGAIN;
114 		return -1;
115 	}
116 
117 	/* No more duplicates of file pointer. Flush buffer and close */
118 	r = fp->f_flags & SMWR ? sm_flush(fp, (int *) &timeout) : 0;
119 
120 	/* sm_flush() has updated to.it_value for the time it's used */
121 	if (timeout != SM_TIME_FOREVER)
122 	{
123 		if (setjmp(CloseTimeOut) != 0)
124 		{
125 			errno = EAGAIN;
126 			return SM_IO_EOF;
127 		}
128 		evt = sm_seteventm(timeout, closealrm, 0);
129 	}
130 	if ((*fp->f_close)(fp) < 0)
131 		r = SM_IO_EOF;
132 
133 	/*  We're back. So undo our timeout and handler */
134 	if (evt != NULL)
135 		sm_clrevent(evt);
136 	if (fp->f_flags & SMMBF)
137 	{
138 		sm_free((char *)fp->f_bf.smb_base);
139 		fp->f_bf.smb_base = NULL;
140 	}
141 	if (HASUB(fp))
142 		FREEUB(fp);
143 	if (HASLB(fp))
144 		FREELB(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