1 /* 2 * Copyright (c) 2000-2001 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.41 2001/09/11 04:04:48 gshapiro 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 if (fp->sm_magic == NULL) 90 { 91 /* not open! */ 92 errno = EBADF; 93 return SM_IO_EOF; 94 } 95 if (fp->f_close == NULL) 96 { 97 /* no close function! */ 98 errno = ENODEV; 99 return SM_IO_EOF; 100 } 101 if (fp->f_dup_cnt > 0) 102 { 103 /* decrement file pointer open count */ 104 fp->f_dup_cnt--; 105 return 0; 106 } 107 108 /* Okay, this is where we set the timeout. */ 109 if (timeout == SM_TIME_DEFAULT) 110 timeout = fp->f_timeout; 111 if (timeout == SM_TIME_IMMEDIATE) 112 { 113 errno = EAGAIN; 114 return -1; 115 } 116 117 /* No more duplicates of file pointer. Flush buffer and close */ 118 r = fp->f_flags & SMWR ? sm_flush(fp, (int *) &timeout) : 0; 119 120 /* sm_flush() has updated to.it_value for the time it's used */ 121 if (timeout != SM_TIME_FOREVER) 122 { 123 if (setjmp(CloseTimeOut) != 0) 124 { 125 errno = EAGAIN; 126 return SM_IO_EOF; 127 } 128 evt = sm_seteventm(timeout, closealrm, 0); 129 } 130 if ((*fp->f_close)(fp) < 0) 131 r = SM_IO_EOF; 132 133 /* We're back. So undo our timeout and handler */ 134 if (evt != NULL) 135 sm_clrevent(evt); 136 if (fp->f_flags & SMMBF) 137 { 138 sm_free((char *)fp->f_bf.smb_base); 139 fp->f_bf.smb_base = NULL; 140 } 141 if (HASUB(fp)) 142 FREEUB(fp); 143 if (HASLB(fp)) 144 FREELB(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