/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/*
 * bootstrap -- fundamental service initiator and port server
 * Mike DeMoney, NeXT, Inc.
 * Copyright, 1990.  All rights reserved.
 *
 * error_log.c -- implementation of logging routines
 *
 * Routines may be safely invoked from multiple threads
 */

#import <pthread.h>
#import <mach/mach_error.h>
#import <stdio.h>
#import <syslog.h>
#import <sys/syslimits.h>
#import <libc.h>
#import	<errno.h>

#import "bootstrap_internal.h"
#import "error_log.h"

static pthread_mutex_t errlog_lock = PTHREAD_MUTEX_INITIALIZER;

void
init_errlog(boolean_t is_init)
{
	int nfds, fd;

	if (is_init) {
		close(0);
		freopen("/dev/console", "r", stdin);
		setbuf(stdin, NULL);
		close(1);
		freopen("/dev/console", "w", stdout);
		setbuf(stdout, NULL);
		close(2);
		freopen("/dev/console", "w", stderr);
		setbuf(stderr, NULL);
	}

	nfds = getdtablesize();
	for (fd = 3; fd < nfds; fd++)
		close(fd);
	openlog((char *)program_name, LOG_PID, LOG_DAEMON);
	setlogmask(LOG_UPTO(LOG_INFO));
}

void
close_errlog(void)
{
	closelog();
}

static void do_log(const int level, const char *format, va_list ap)
{
	pthread_mutex_lock(&errlog_lock);
	if (debugging) {
		fprintf(stderr, "%s[%d]%s: ",
			level == LOG_ALERT ? " FATAL" : "",
			getpid(), program_name);
		vfprintf(stderr, format, ap);
		fprintf(stderr, "\n");
	} else {
		vsyslog(level, format, ap);
	}
	pthread_mutex_unlock(&errlog_lock);
}

void debug(const char *format, ...)
{
    if (debugging) {
	va_list ap;
	
	va_start(ap, format);
	do_log(LOG_DEBUG, format, ap);
	va_end(ap);
    }
}

void info(const char *format, ...)
{
	va_list ap;
	
	va_start(ap, format);
	do_log(LOG_INFO, format, ap);
	va_end(ap);
}

__private_extern__ void log(const char *format, ...)
{
	va_list ap;
	
	va_start(ap, format);
	do_log(LOG_NOTICE, format, ap);
	va_end(ap);
}

void error(const char *format, ...)
{
	va_list ap;
	
	va_start(ap, format);
	do_log(LOG_CRIT, format, ap);
	va_end(ap);
}

void kern_error(kern_return_t result, const char *format, ...)
{
	va_list ap;
	char buf[1000];
	
	sprintf(buf, "%s: %s(%d)", format, mach_error_string(result), result);

	va_start(ap, format);
	do_log(LOG_CRIT, buf, ap);
	va_end(ap);
}

void unix_error(const char *format, ...)
{
	va_list ap;
	char buf[1000];
	
	sprintf(buf, "%s: %s(%d)", format, strerror(errno), errno);

	va_start(ap, format);
	do_log(LOG_CRIT, buf, ap);
	va_end(ap);
}

void parse_error(const char *token_string, const char *format, ...)
{
	va_list ap;
	char buf[1000];

	sprintf(buf, "%s unexpected: %s", token_string, format);

	va_start(ap, format);
	do_log(LOG_CRIT, buf, ap);
	va_end(ap);
}

void fatal(const char *format, ...)
{
	va_list ap;
	
	va_start(ap, format);
	do_log(LOG_ALERT, format, ap);
	va_end(ap);
	exit(1);
}

void kern_fatal(kern_return_t result, const char *format, ...)
{
	va_list ap;
	char buf[1000];
	
	sprintf(buf, "%s: %s(%d)", format, mach_error_string(result), result);

	va_start(ap, format);
	do_log(LOG_ALERT, buf, ap);
	va_end(ap);
	exit(1);
}

void unix_fatal(const char *format, ...)
{
	va_list ap;
	char buf[1000];
	
	sprintf(buf, "%s: %s(%d)", format, strerror(errno), errno);

	va_start(ap, format);
	do_log(LOG_ALERT, buf, ap);
	va_end(ap);
	exit(1);
}
