Merge from vendor branch FILE:
[dragonfly.git] / contrib / sendmail / libsm / fclose.c
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 }