pjdlog.c revision 218040
1139825Simp/*-
242805Skato * Copyright (c) 2009-2010 The FreeBSD Foundation
342805Skato * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
442805Skato * All rights reserved.
542805Skato *
642805Skato * This software was developed by Pawel Jakub Dawidek under sponsorship from
742805Skato * the FreeBSD Foundation.
842805Skato *
942805Skato * Redistribution and use in source and binary forms, with or without
1042805Skato * modification, are permitted provided that the following conditions
1142805Skato * are met:
1242805Skato * 1. Redistributions of source code must retain the above copyright
1342805Skato *    notice, this list of conditions and the following disclaimer.
1442805Skato * 2. Redistributions in binary form must reproduce the above copyright
1542805Skato *    notice, this list of conditions and the following disclaimer in the
1642805Skato *    documentation and/or other materials provided with the distribution.
1742805Skato *
1842805Skato * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1942805Skato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2042805Skato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2142805Skato * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2242805Skato * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2342805Skato * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2442805Skato * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2542805Skato * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2642805Skato * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2742805Skato * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2850477Speter * SUCH DAMAGE.
2942795Skato */
3042795Skato
31162711Sru#include <sys/cdefs.h>
3242795Skato__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 218040 2011-01-28 21:36:01Z pjd $");
3342795Skato
3442795Skato#include <assert.h>
3542795Skato#include <errno.h>
3642795Skato#include <stdarg.h>
3745783Skato#include <stdbool.h>
3842795Skato#include <stdio.h>
3945783Skato#include <stdlib.h>
4045783Skato#include <string.h>
4167370Skato#include <syslog.h>
4242795Skato
4342795Skato#include "pjdlog.h"
4442795Skato
4542795Skatostatic bool pjdlog_initialized = false;
4642795Skatostatic int pjdlog_mode, pjdlog_debug_level;
47146049Snyanstatic char pjdlog_prefix[128];
4845783Skato
4945783Skatovoid
5042795Skatopjdlog_init(int mode)
5142795Skato{
5242795Skato
5342795Skato	assert(!pjdlog_initialized);
5442795Skato	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
5545783Skato
5642795Skato	if (mode == PJDLOG_MODE_SYSLOG)
5745783Skato		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
5845783Skato	pjdlog_mode = mode;
5979702Snyan	pjdlog_debug_level = 0;
6045783Skato	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
6142795Skato
6245783Skato	pjdlog_initialized = true;
6345783Skato}
6445783Skato
6545783Skatovoid
6679702Snyanpjdlog_fini(void)
6745783Skato{
6845783Skato
6942795Skato	assert(pjdlog_initialized);
7045783Skato
7142795Skato	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
7245783Skato		closelog();
7350236Skato
7442795Skato	pjdlog_initialized = false;
7542795Skato}
7645783Skato
7745783Skato/*
7878385Snyan * Configure where the logs should go.
7978385Snyan * By default they are send to stdout/stderr, but after going into background
8044635Skato * (eg. by calling daemon(3)) application is responsible for changing mode to
8144635Skato * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
8250236Skato */
8344635Skatovoid
8442795Skatopjdlog_mode_set(int mode)
8542795Skato{
8642795Skato
8742795Skato	assert(pjdlog_initialized);
8845783Skato	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
8942795Skato
9078385Snyan	if (pjdlog_mode == mode)
9178385Snyan		return;
9278385Snyan
9351276Snyan	if (mode == PJDLOG_MODE_SYSLOG)
9451276Snyan		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
9551276Snyan	else /* if (mode == PJDLOG_MODE_STD) */
9651276Snyan		closelog();
9745783Skato
9845783Skato	pjdlog_mode = mode;
9978385Snyan}
10078385Snyan
10178385Snyan/*
10278385Snyan * Return current mode.
10378385Snyan */
10478385Snyanint
10578385Snyanpjdlog_mode_get(void)
10678385Snyan{
10778385Snyan
10878385Snyan	assert(pjdlog_initialized);
10978385Snyan
11078385Snyan	return (pjdlog_mode);
11178385Snyan}
11278385Snyan
11378385Snyan/*
11442795Skato * Set debug level. All the logs above the level specified here will be
11542795Skato * ignored.
11642795Skato */
11745783Skatovoid
11842795Skatopjdlog_debug_set(int level)
11950236Skato{
12045783Skato
12145783Skato	assert(pjdlog_initialized);
12278385Snyan	assert(level >= 0);
12342795Skato
12478385Snyan	pjdlog_debug_level = level;
12578385Snyan}
12678385Snyan
12778385Snyan/*
12878385Snyan * Return current debug level.
12978385Snyan */
13045783Skatoint
13178385Snyanpjdlog_debug_get(void)
13278385Snyan{
13378385Snyan
13478385Snyan	assert(pjdlog_initialized);
13578385Snyan
13678385Snyan	return (pjdlog_debug_level);
137127135Snjl}
13878385Snyan
13978385Snyan/*
140166901Spiso * Set prefix that will be used before each log.
14145783Skato * Setting prefix to NULL will remove it.
14279702Snyan */
14379702Snyanvoid
14479702Snyanpjdlog_prefix_set(const char *fmt, ...)
14579702Snyan{
14679702Snyan	va_list ap;
14779702Snyan
14879702Snyan	assert(pjdlog_initialized);
14979702Snyan
15079702Snyan	va_start(ap, fmt);
15179702Snyan	pjdlogv_prefix_set(fmt, ap);
15279702Snyan	va_end(ap);
153175001Snyan}
15479702Snyan
15545783Skato/*
15642795Skato * Set prefix that will be used before each log.
15742795Skato * Setting prefix to NULL will remove it.
15842795Skato */
15945783Skatovoid
16042795Skatopjdlogv_prefix_set(const char *fmt, va_list ap)
16150236Skato{
16242795Skato
163175001Snyan	assert(pjdlog_initialized);
16442795Skato	assert(fmt != NULL);
16542795Skato
16642795Skato	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
16744635Skato}
16842795Skato
16942795Skato/*
17042795Skato * Convert log level into string.
17144635Skato */
17242795Skatostatic const char *
17342795Skatopjdlog_level_string(int loglevel)
17442795Skato{
17542795Skato
17642795Skato	switch (loglevel) {
17742795Skato	case LOG_EMERG:
17842795Skato		return ("EMERG");
17944635Skato	case LOG_ALERT:
18044635Skato		return ("ALERT");
18144635Skato	case LOG_CRIT:
18244635Skato		return ("CRIT");
18342795Skato	case LOG_ERR:
18442795Skato		return ("ERROR");
18542795Skato	case LOG_WARNING:
18650236Skato		return ("WARNING");
18742795Skato	case LOG_NOTICE:
18842795Skato		return ("NOTICE");
18944635Skato	case LOG_INFO:
19042795Skato		return ("INFO");
19142795Skato	case LOG_DEBUG:
19242795Skato		return ("DEBUG");
19342795Skato	}
19442795Skato	assert(!"Invalid log level.");
19542795Skato	abort();	/* XXX: gcc */
19642795Skato}
19744635Skato
19844635Skato/*
19950236Skato * Common log routine.
20044635Skato */
20142795Skatovoid
20244635Skatopjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
20350236Skato{
20444635Skato	va_list ap;
20544635Skato
20650236Skato	assert(pjdlog_initialized);
20742795Skato
20842795Skato	va_start(ap, fmt);
20942795Skato	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
21050236Skato	va_end(ap);
21142795Skato}
21242795Skato
21342795Skato/*
21442795Skato * Common log routine, which can handle regular log level as well as debug
21542795Skato * level. We decide here where to send the logs (stdout/stderr or syslog).
21642795Skato */
21742795Skatovoid
21842795Skatopjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
21950236Skato    va_list ap)
22042795Skato{
22142795Skato
22250236Skato	assert(pjdlog_initialized);
22342795Skato	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
22442795Skato	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
22542795Skato	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
22642795Skato	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
22742795Skato	assert(loglevel != LOG_DEBUG || debuglevel > 0);
22842795Skato	assert(error >= -1);
22942795Skato
23042795Skato	/* Ignore debug above configured level. */
23142795Skato	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
23242795Skato		return;
23342795Skato
23442795Skato	switch (pjdlog_mode) {
23542795Skato	case PJDLOG_MODE_STD:
23642795Skato	    {
23742795Skato		FILE *out;
23842795Skato
23942795Skato		/*
24042795Skato		 * We send errors and warning to stderr and the rest to stdout.
24142795Skato		 */
24242795Skato		switch (loglevel) {
24342795Skato		case LOG_EMERG:
24442795Skato		case LOG_ALERT:
24542795Skato		case LOG_CRIT:
24642795Skato		case LOG_ERR:
24742795Skato		case LOG_WARNING:
24842795Skato			out = stderr;
249175001Snyan			break;
25042795Skato		case LOG_NOTICE:
25142795Skato		case LOG_INFO:
25242795Skato		case LOG_DEBUG:
25342795Skato			out = stdout;
25442795Skato			break;
255175001Snyan		default:
256175001Snyan			assert(!"Invalid loglevel.");
257175001Snyan			abort();	/* XXX: gcc */
25842795Skato		}
25942795Skato
26042795Skato		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
26142795Skato		/* Attach debuglevel if this is debug log. */
26242795Skato		if (loglevel == LOG_DEBUG)
26342795Skato			fprintf(out, "[%d]", debuglevel);
26442795Skato		fprintf(out, " %s", pjdlog_prefix);
265114216Skan		vfprintf(out, fmt, ap);
26642795Skato		if (error != -1)
26742795Skato			fprintf(out, ": %s.", strerror(error));
26842795Skato		fprintf(out, "\n");
26942795Skato		fflush(out);
27042795Skato		break;
27142795Skato	    }
27242795Skato	case PJDLOG_MODE_SYSLOG:
27342795Skato	    {
27442795Skato		char log[1024];
27542795Skato		int len;
27642795Skato
27742795Skato		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
27842795Skato		if ((size_t)len < sizeof(log))
27942795Skato			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
28042795Skato		if (error != -1 && (size_t)len < sizeof(log)) {
28142795Skato			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
28242795Skato			    strerror(error));
28342795Skato		}
28442795Skato		syslog(loglevel, "%s", log);
28542795Skato		break;
28642795Skato	    }
28742795Skato	default:
28842795Skato		assert(!"Invalid mode.");
28942795Skato	}
29042795Skato}
29142795Skato
29242795Skato/*
29342795Skato * Regular logs.
29442795Skato */
29542795Skatovoid
29642795Skatopjdlogv(int loglevel, const char *fmt, va_list ap)
29742795Skato{
29842795Skato
29944635Skato	assert(pjdlog_initialized);
30042795Skato
30142795Skato	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
30242795Skato	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
30342795Skato	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
30442795Skato	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
30542795Skato	    loglevel == LOG_INFO);
30642795Skato
30742795Skato	pjdlogv_common(loglevel, 0, -1, fmt, ap);
30842795Skato}
30942795Skato
31042795Skato/*
31142795Skato * Regular logs.
31242795Skato */
31342795Skatovoid
31442795Skatopjdlog(int loglevel, const char *fmt, ...)
31542795Skato{
31642795Skato	va_list ap;
31742795Skato
31842795Skato	assert(pjdlog_initialized);
31944635Skato
32042795Skato	va_start(ap, fmt);
32142795Skato	pjdlogv(loglevel, fmt, ap);
32242795Skato	va_end(ap);
32342795Skato}
32442795Skato
32542795Skato/*
32642795Skato * Debug logs.
32742795Skato */
32842795Skatovoid
32942795Skatopjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
33042795Skato{
33142795Skato
33242795Skato	assert(pjdlog_initialized);
33342795Skato
33442795Skato	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
33542795Skato}
33642795Skato
33742795Skato/*
33842795Skato * Debug logs.
33942795Skato */
34042795Skatovoid
34142795Skatopjdlog_debug(int debuglevel, const char *fmt, ...)
34242795Skato{
343146138Snyan	va_list ap;
34442795Skato
34542795Skato	assert(pjdlog_initialized);
34642795Skato
34742795Skato	va_start(ap, fmt);
34842795Skato	pjdlogv_debug(debuglevel, fmt, ap);
34942795Skato	va_end(ap);
35042795Skato}
35142795Skato
35242795Skato/*
35342795Skato * Error logs with errno logging.
35442795Skato */
35542795Skatovoid
35642795Skatopjdlogv_errno(int loglevel, const char *fmt, va_list ap)
35742795Skato{
35842795Skato
35942795Skato	assert(pjdlog_initialized);
36042795Skato
36142795Skato	pjdlogv_common(loglevel, 0, errno, fmt, ap);
36242795Skato}
36342795Skato
36442795Skato/*
36542795Skato * Error logs with errno logging.
36644635Skato */
36742795Skatovoid
36842795Skatopjdlog_errno(int loglevel, const char *fmt, ...)
36945783Skato{
37045783Skato	va_list ap;
37144635Skato
372117167Sjhb	assert(pjdlog_initialized);
37344635Skato
37444635Skato	va_start(ap, fmt);
37544635Skato	pjdlogv_errno(loglevel, fmt, ap);
37644635Skato	va_end(ap);
37744635Skato}
37844635Skato
37944635Skato/*
38044635Skato * Log error, errno and exit.
38144635Skato */
38242795Skatovoid
38342795Skatopjdlogv_exit(int exitcode, const char *fmt, va_list ap)
38442795Skato{
38542795Skato
38644635Skato	assert(pjdlog_initialized);
38744635Skato
38842795Skato	pjdlogv_errno(LOG_ERR, fmt, ap);
38944635Skato	exit(exitcode);
39044635Skato	/* NOTREACHED */
39142795Skato}
39244635Skato
39344635Skato/*
39442795Skato * Log error, errno and exit.
39542795Skato */
39642795Skatovoid
39742795Skatopjdlog_exit(int exitcode, const char *fmt, ...)
39844635Skato{
39942795Skato	va_list ap;
40044635Skato
40142795Skato	assert(pjdlog_initialized);
40242795Skato
40342795Skato	va_start(ap, fmt);
40442795Skato	pjdlogv_exit(exitcode, fmt, ap);
40542795Skato	/* NOTREACHED */
40642795Skato	va_end(ap);
40744635Skato}
40842795Skato
40942795Skato/*
41044635Skato * Log error and exit.
41142795Skato */
41242795Skatovoid
41342795Skatopjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
41442795Skato{
41542795Skato
41642795Skato	assert(pjdlog_initialized);
41742795Skato
41842795Skato	pjdlogv(LOG_ERR, fmt, ap);
41942795Skato	exit(exitcode);
42042795Skato	/* NOTREACHED */
42142795Skato}
42244635Skato
42342795Skato/*
42444635Skato * Log error and exit.
42544635Skato */
42644635Skatovoid
42744635Skatopjdlog_exitx(int exitcode, const char *fmt, ...)
42844635Skato{
42944635Skato	va_list ap;
43044635Skato
43142795Skato	assert(pjdlog_initialized);
43244635Skato
43344635Skato	va_start(ap, fmt);
43442795Skato	pjdlogv_exitx(exitcode, fmt, ap);
43544635Skato	/* NOTREACHED */
43644635Skato	va_end(ap);
43744635Skato}
43844635Skato
43944635Skato/*
44044635Skato * Log assertion and exit.
44144635Skato */
44244635Skatovoid
44344635Skatopjdlog_verify(const char *func, const char *file, int line,
44444635Skato    const char *failedexpr, const char *fmt, ...)
44544635Skato{
44644635Skato	va_list ap;
44744635Skato
44844635Skato	assert(pjdlog_initialized);
44944635Skato
45044635Skato	/*
45144635Skato	 * When there is no message we pass __func__ as 'fmt'.
45244635Skato	 * It would be cleaner to pass NULL or "", but gcc generates a warning
45344635Skato	 * for both of those.
45444635Skato	 */
45544635Skato	if (fmt != func) {
45644635Skato		va_start(ap, fmt);
45744635Skato		pjdlogv_critical(fmt, ap);
45844635Skato		va_end(ap);
45944635Skato	}
46044635Skato	if (failedexpr == NULL) {
46144635Skato		if (func == NULL) {
46244635Skato			pjdlog_critical("Aborted at file %s, line %d.", file,
46344635Skato			    line);
46444635Skato		} else {
46544635Skato			pjdlog_critical("Aborted at function %s, file %s, line %d.",
46644635Skato			    func, file, line);
46742795Skato		}
46844635Skato	} else {
46942795Skato		if (func == NULL) {
47042795Skato			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
47144635Skato			    failedexpr, file, line);
47242795Skato		} else {
47342795Skato			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
47442795Skato			    failedexpr, func, file, line);
47542795Skato		}
47642795Skato	}
47742795Skato	abort();
47842795Skato}
47942795Skato