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.43 2004/08/03 20:17:38 ca Exp $") 19 #include <errno.h> 20 #include <stdlib.h> 21 #include <sys/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 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 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