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 #include <sm/gen.h> 16 SM_RCSID("@(#)$Id: fclose.c,v 1.44 2005/06/14 23:07:20 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 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 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