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.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
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
closealrm(sig)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
sm_io_close(fp,timeout)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