/*	$CoreSDI: log.c,v 1.15 2001/08/29 22:19:34 claudio Exp $	*/

/*
 *   Copyright (c) 2000, 2001, Core SDI S.A., Argentina
 *   All rights reserved
 *  
 *   Redistribution and use in source and binary forms, with or without
 *   modification, are permitted provided that the following conditions
 *   are met:
 *  
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *   3. Neither name of the Core SDI S.A. nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *  
 *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 *   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef WIN32		/* Unix */
#include <sys/types.h>

#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>

#else			/* Win32 */

#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "exits.h"
#include "winsyslog.h"

#endif /* WIN32 */

#include "sysdep.h"
#include "log.h"

static int _facility = 0;
static LOGFLAGS _flags = LOGF_NOLOG;

#define CLEANUP_MAX	32
static int _cleanups = 0;
static void *_arg[CLEANUP_MAX];
static void (*_func[CLEANUP_MAX])(void *);


/*
 * _log_cleanup():
 *	Call all cleanup functions in stack order.
 */
static void
_log_cleanup()
{
	while (_cleanups--)
		_func[_cleanups](_arg[_cleanups]);
}


/*
 * log_init():
 *	Initialize log system.
 */
void
log_init(LOGFLAGS flags, int facility)
{
	_flags = flags;
	_facility = facility;
}


/*
 * log_vmsg():
 * log_msg():
 *	Log generic (not empty) message.
 */
void
log_vmsg(int level, const char *fmt, va_list ap)
{
	char msg[LINE_MAX], *src;
	extern char *__progname;

	if (_flags & LOGF_NOLOG)
		return;

	if (*fmt == '\0')
		return;

	switch (level) {
	case LOG_INFO:
		src = "";
		break;
	case LOG_WARNING:
		src = "Warning: ";
		break;
	case LOG_DEBUG:
		src = "Debug: ";
		break;
	case LOG_ERR:
	default:
		level = LOG_ERR;
		src = "Error: ";
	}

	/* Do not log empty messages */
	if (*fmt != '\0') {
		if (_flags & LOGF_STDERR) {
			snprintf(msg, sizeof(msg), "%s: %s%s\n", __progname,
			    src, fmt);
			vfprintf(stderr, msg, ap);
		} else {
			snprintf(msg, sizeof(msg), "%s%s\n", src, fmt);
			openlog(__progname, LOG_PID, _facility);
			vsyslog(_facility | level, msg, ap);
			closelog();
		}
	}
}

void
log_msg(int level, const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	log_vmsg(level, fmt, ap);
	va_end(ap);
}


/*
 * log_session():
 *	Log session message.
 */
void
log_session(const char *fmt, ...)
{
	if (_flags & LOGF_SESSION) {
		va_list ap;
		va_start(ap, fmt);
		log_vmsg(LOG_INFO, fmt, ap);
		va_end(ap);
	}
}


/*
 * log_vcmd():
 *	Log username and command.
 */
void
log_vcmd(const char *user, const char *status, const char *fmt, va_list ap)
{
	char	command[LINE_MAX];

	vsnprintf(command, sizeof(command), fmt, ap);
	log_session("User: %s. Command: %s. Status: %s.", user, command,
	    status);
}


/*
 * log_cmd():
 *	Log username and command.
 */
void
log_cmd(const char *user, const char *status, const char *fmt, ...)
{
	va_list	ap;
	
	va_start(ap, fmt);
	log_vcmd(user, status, fmt, ap);
	va_end(ap);
}


/*
 * log_debug():
 *	Log debugging messages.
 */
void
log_debug(const char *fmt, ...)
{
	if (_flags & LOGF_DEBUG) {
		va_list ap;
		va_start(ap, fmt);
		log_vmsg(LOG_DEBUG, fmt, ap);
		va_end(ap);
	}
}


/*
 * log_warn():
 *	Log warning messages.
 */
void
log_warn(const char *fmt, ...)
{
	if (_flags & LOGF_ERROR) {
		va_list ap;
		va_start(ap, fmt);
		log_vmsg(LOG_WARNING, fmt, ap);
		va_end(ap);
	}
}


/*
 * log_err():
 *	Log error messages.
 */
void
log_err(const char *fmt, ...)
{
	if (_flags & LOGF_ERROR) {
		va_list ap;
		va_start(ap, fmt);
		log_vmsg(LOG_ERR, fmt, ap);
		va_end(ap);
	}
}


/*
 * log_fatal():
 *	Log fatal messages, call cleanup functions, and exit(3).
 *	See cleanup_add().
 */
void
log_fatal(int ecode, const char *fmt, ...)
{
	if (_flags & LOGF_ERROR) {
		va_list ap;
		va_start(ap, fmt);
		log_vmsg(LOG_ERR, fmt, ap);
		va_end(ap);
	}
	_log_cleanup();
	exit(ecode);
}


/*
 * cleanup_add():
 *	Add a cleanup function. See log_fatal().
 */
int
cleanup_add(void(*fn)(void *), void *arg)
{
	if (_cleanups < CLEANUP_MAX && fn != NULL) {
		_func[_cleanups] = fn;
		_arg[_cleanups++] = arg;
		return (0);
	}
	return (-1);
}


/*
 * cleanup_rm_all():
 *	Remove all cleanup functions.
 */
void
cleanup_rm_all()
{
	_cleanups = 0;
}
	


