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 } 149