xref: /illumos-gate/usr/src/cmd/sendmail/libsm/fclose.c (revision 7c478bd9)
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>
18 SM_RCSID("@(#)$Id: fclose.c,v 1.43 2004/08/03 20:17:38 ca Exp $")
19 #include <errno.h>
20 #include <stdlib.h>
21 #include <sys/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 
31 static void	closealrm __P((int));
32 static 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 */
54 static void
55 closealrm(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 
76 int
77 sm_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