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