1N/A/*
1N/A * Copyright (c) 2000-2002, 2004 Sendmail, Inc. and its suppliers.
1N/A * All rights reserved.
1N/A * Copyright (c) 1990, 1993
1N/A * The Regents of the University of California. All rights reserved.
1N/A *
1N/A * This code is derived from software contributed to Berkeley by
1N/A * Chris Torek.
1N/A *
1N/A * By using this file, you agree to the terms and conditions set
1N/A * forth in the LICENSE file which can be found at the top level of
1N/A * the sendmail distribution.
1N/A */
1N/A
1N/A#pragma ident "%Z%%M% %I% %E% SMI"
1N/A
1N/A#include <sm/gen.h>
1N/ASM_RCSID("@(#)$Id: fclose.c,v 1.44 2005/06/14 23:07:20 ca Exp $")
1N/A#include <errno.h>
1N/A#include <stdlib.h>
1N/A#include <sm/time.h>
1N/A#include <setjmp.h>
1N/A#include <sm/io.h>
1N/A#include <sm/assert.h>
1N/A#include <sm/heap.h>
1N/A#include <sm/signal.h>
1N/A#include <sm/conf.h>
1N/A#include <sm/clock.h>
1N/A#include "local.h"
1N/A
1N/Astatic void closealrm __P((int));
1N/Astatic jmp_buf CloseTimeOut;
1N/A
1N/A/*
1N/A** CLOSEALRM -- handler when timeout activated for sm_io_close()
1N/A**
1N/A** Returns flow of control to where setjmp(CloseTimeOut) was set.
1N/A**
1N/A** Parameters:
1N/A** sig -- unused
1N/A**
1N/A** Returns:
1N/A** does not return
1N/A**
1N/A** Side Effects:
1N/A** returns flow of control to setjmp(CloseTimeOut).
1N/A**
1N/A** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
1N/A** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
1N/A** DOING.
1N/A*/
1N/A
1N/A/* ARGSUSED0 */
1N/Astatic void
1N/Aclosealrm(sig)
1N/A int sig;
1N/A{
1N/A longjmp(CloseTimeOut, 1);
1N/A}
1N/A
1N/A/*
1N/A** SM_IO_CLOSE -- close a file handle/pointer
1N/A**
1N/A** Parameters:
1N/A** fp -- file pointer to be closed
1N/A** timeout -- maximum time allowed to perform the close (millisecs)
1N/A**
1N/A** Returns:
1N/A** 0 on success
1N/A** -1 on failure and sets errno
1N/A**
1N/A** Side Effects:
1N/A** file pointer 'fp' will no longer be valid.
1N/A*/
1N/A
1N/Aint
1N/Asm_io_close(fp, timeout)
1N/A register SM_FILE_T *fp;
1N/A int SM_NONVOLATILE timeout;
1N/A{
1N/A register int SM_NONVOLATILE r;
1N/A SM_EVENT *evt = NULL;
1N/A
1N/A if (fp == NULL)
1N/A {
1N/A errno = EBADF;
1N/A return SM_IO_EOF;
1N/A }
1N/A
1N/A SM_REQUIRE_ISA(fp, SmFileMagic);
1N/A
1N/A /* XXX this won't be reached if above macro is active */
1N/A if (fp->sm_magic == NULL)
1N/A {
1N/A /* not open! */
1N/A errno = EBADF;
1N/A return SM_IO_EOF;
1N/A }
1N/A if (fp->f_close == NULL)
1N/A {
1N/A /* no close function! */
1N/A errno = ENODEV;
1N/A return SM_IO_EOF;
1N/A }
1N/A if (fp->f_dup_cnt > 0)
1N/A {
1N/A /* decrement file pointer open count */
1N/A fp->f_dup_cnt--;
1N/A return 0;
1N/A }
1N/A
1N/A /* Okay, this is where we set the timeout. */
1N/A if (timeout == SM_TIME_DEFAULT)
1N/A timeout = fp->f_timeout;
1N/A if (timeout == SM_TIME_IMMEDIATE)
1N/A {
1N/A errno = EAGAIN;
1N/A return -1;
1N/A }
1N/A
1N/A /* No more duplicates of file pointer. Flush buffer and close */
1N/A r = fp->f_flags & SMWR ? sm_flush(fp, (int *) &timeout) : 0;
1N/A
1N/A /* sm_flush() has updated to.it_value for the time it's used */
1N/A if (timeout != SM_TIME_FOREVER)
1N/A {
1N/A if (setjmp(CloseTimeOut) != 0)
1N/A {
1N/A errno = EAGAIN;
1N/A return SM_IO_EOF;
1N/A }
1N/A evt = sm_seteventm(timeout, closealrm, 0);
1N/A }
1N/A if ((*fp->f_close)(fp) < 0)
1N/A r = SM_IO_EOF;
1N/A
1N/A /* We're back. So undo our timeout and handler */
1N/A if (evt != NULL)
1N/A sm_clrevent(evt);
1N/A if (fp->f_flags & SMMBF)
1N/A {
1N/A sm_free((char *)fp->f_bf.smb_base);
1N/A fp->f_bf.smb_base = NULL;
1N/A }
1N/A if (HASUB(fp))
1N/A FREEUB(fp);
1N/A fp->f_flags = 0; /* clear flags */
1N/A fp->sm_magic = NULL; /* Release this SM_FILE_T for reuse. */
1N/A fp->f_r = fp->f_w = 0; /* Mess up if reaccessed. */
1N/A return r;
1N/A}