1 /*
2 * Copyright (c) 2000-2002, 2004 Proofpoint, 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.45 2013-11-22 20:51:42 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
closealrm(sig)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
sm_io_close(fp,timeout)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