pjdlog.c revision 212052
160812Sps/*-
260786Sps * Copyright (c) 2009-2010 The FreeBSD Foundation
3221715Sdelphij * All rights reserved.
460786Sps *
560786Sps * This software was developed by Pawel Jakub Dawidek under sponsorship from
660786Sps * the FreeBSD Foundation.
760786Sps *
860786Sps * Redistribution and use in source and binary forms, with or without
960786Sps * modification, are permitted provided that the following conditions
1060786Sps * are met:
1160786Sps * 1. Redistributions of source code must retain the above copyright
1260786Sps *    notice, this list of conditions and the following disclaimer.
1360786Sps * 2. Redistributions in binary form must reproduce the above copyright
1460786Sps *    notice, this list of conditions and the following disclaimer in the
1560786Sps *    documentation and/or other materials provided with the distribution.
1660786Sps *
1760786Sps * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18195941Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1960786Sps * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20172471Sdelphij * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2160786Sps * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2260786Sps * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2360786Sps * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2460786Sps * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2560786Sps * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2660786Sps * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2760786Sps * SUCH DAMAGE.
2860786Sps */
2960786Sps
3060786Sps#include <sys/cdefs.h>
3160786Sps__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 212052 2010-08-31 12:05:13Z pjd $");
32170259Sdelphij
33128348Stjr#include <assert.h>
3463131Sps#include <errno.h>
35170259Sdelphij#include <stdarg.h>
3660786Sps#include <stdio.h>
3760786Sps#include <stdlib.h>
38191930Sdelphij#include <string.h>
39191930Sdelphij#include <syslog.h>
4060786Sps
4160786Sps#include "pjdlog.h"
4260786Sps
4360786Spsstatic int pjdlog_mode = PJDLOG_MODE_STD;
4460786Spsstatic int pjdlog_debug_level = 0;
4560786Spsstatic char pjdlog_prefix[128];
4660786Sps
4760786Sps/*
48195941Sdelphij * Configure where the logs should go.
49195941Sdelphij * By default they are send to stdout/stderr, but after going into background
5060786Sps * (eg. by calling daemon(3)) application is responsible for changing mode to
5160786Sps * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
5260786Sps */
5360786Spsvoid
5460786Spspjdlog_mode_set(int mode)
5560786Sps{
5660786Sps
5760786Sps	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
58191930Sdelphij
5960786Sps	pjdlog_mode = mode;
6060786Sps
6160786Sps	if (mode == PJDLOG_MODE_SYSLOG)
6260786Sps		openlog(NULL, LOG_PID, LOG_DAEMON);
6360786Sps}
64195941Sdelphij
6560786Sps/*
66195941Sdelphij * Return current mode.
67195941Sdelphij */
68195941Sdelphijint
69195941Sdelphijpjdlog_mode_get(void)
70195941Sdelphij{
71195941Sdelphij
72195941Sdelphij	return (pjdlog_mode);
73195941Sdelphij}
7460786Sps
75173685Sdelphij/*
76221715Sdelphij * Set debug level. All the logs above the level specified here will be
77221715Sdelphij * ignored.
78221715Sdelphij */
79221715Sdelphijvoid
80221715Sdelphijpjdlog_debug_set(int level)
81221715Sdelphij{
82221715Sdelphij
83221715Sdelphij	assert(level >= 0);
84221715Sdelphij
85221715Sdelphij	pjdlog_debug_level = level;
86221715Sdelphij}
87221715Sdelphij
88221715Sdelphij/*
89221715Sdelphij * Return current debug level.
90221715Sdelphij */
91221715Sdelphijint
92221715Sdelphijpjdlog_debug_get(void)
93221715Sdelphij{
94221715Sdelphij
95195941Sdelphij	return (pjdlog_debug_level);
96173685Sdelphij}
97173685Sdelphij
98195941Sdelphij/*
99195941Sdelphij * Set prefix that will be used before each log.
100195941Sdelphij * Setting prefix to NULL will remove it.
101195941Sdelphij */
102173685Sdelphijvoid
103195941Sdelphijpjdlog_prefix_set(const char *fmt, ...)
104195941Sdelphij{
105195941Sdelphij	va_list ap;
106195941Sdelphij
107195941Sdelphij	va_start(ap, fmt);
108195941Sdelphij	pjdlog_prefix_setv(fmt, ap);
109195941Sdelphij	va_end(ap);
110195941Sdelphij}
111195941Sdelphij
112195941Sdelphij/*
113195941Sdelphij * Set prefix that will be used before each log.
114195941Sdelphij * Setting prefix to NULL will remove it.
115195941Sdelphij */
116195941Sdelphijvoid
117221715Sdelphijpjdlog_prefix_setv(const char *fmt, va_list ap)
118221715Sdelphij{
119221715Sdelphij
120221715Sdelphij	assert(fmt != NULL);
121221715Sdelphij
122221715Sdelphij	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
123221715Sdelphij}
124221715Sdelphij
125221715Sdelphij/*
126221715Sdelphij * Convert log level into string.
127195941Sdelphij */
128173685Sdelphijstatic const char *
129173685Sdelphijpjdlog_level_string(int loglevel)
130173685Sdelphij{
131195941Sdelphij
132173685Sdelphij	switch (loglevel) {
13360786Sps	case LOG_EMERG:
134195941Sdelphij		return ("EMERG");
135195941Sdelphij	case LOG_ALERT:
13660786Sps		return ("ALERT");
137195941Sdelphij	case LOG_CRIT:
138195941Sdelphij		return ("CRIT");
139195941Sdelphij	case LOG_ERR:
140195941Sdelphij		return ("ERROR");
141195941Sdelphij	case LOG_WARNING:
14260786Sps		return ("WARNING");
143195941Sdelphij	case LOG_NOTICE:
144195941Sdelphij		return ("NOTICE");
145195941Sdelphij	case LOG_INFO:
146195941Sdelphij		return ("INFO");
147195941Sdelphij	case LOG_DEBUG:
148195941Sdelphij		return ("DEBUG");
149195941Sdelphij	}
150195941Sdelphij	assert(!"Invalid log level.");
151195941Sdelphij	abort();	/* XXX: gcc */
152195941Sdelphij}
153195941Sdelphij
154170259Sdelphij/*
155195941Sdelphij * Common log routine.
156195941Sdelphij */
157195941Sdelphijvoid
158195941Sdelphijpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
159195941Sdelphij{
160195941Sdelphij	va_list ap;
161195941Sdelphij
162195941Sdelphij	va_start(ap, fmt);
16360786Sps	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
16460786Sps	va_end(ap);
16560786Sps}
166195941Sdelphij
167128348Stjr/*
168128348Stjr * Common log routine, which can handle regular log level as well as debug
169128348Stjr * level. We decide here where to send the logs (stdout/stderr or syslog).
170128348Stjr */
171128348Stjrvoid
172128348Stjrpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
173128348Stjr    va_list ap)
174128348Stjr{
175128348Stjr
176128348Stjr	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
177128348Stjr	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
178128348Stjr	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
179128348Stjr	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
180128348Stjr	assert(loglevel != LOG_DEBUG || debuglevel > 0);
181128348Stjr	assert(error >= -1);
182128348Stjr
183128348Stjr	/* Ignore debug above configured level. */
184128348Stjr	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
185128348Stjr		return;
186128348Stjr
187128348Stjr	switch (pjdlog_mode) {
188128348Stjr	case PJDLOG_MODE_STD:
189128348Stjr	    {
19060786Sps		FILE *out;
19160786Sps
19260786Sps		/*
193195941Sdelphij		 * We send errors and warning to stderr and the rest to stdout.
194195941Sdelphij		 */
19560786Sps		switch (loglevel) {
196195941Sdelphij		case LOG_EMERG:
197195941Sdelphij		case LOG_ALERT:
198195941Sdelphij		case LOG_CRIT:
19960786Sps		case LOG_ERR:
20060786Sps		case LOG_WARNING:
20160786Sps			out = stderr;
20260786Sps			break;
20360786Sps		case LOG_NOTICE:
20460786Sps		case LOG_INFO:
20560786Sps		case LOG_DEBUG:
20660786Sps			out = stdout;
20760786Sps			break;
20860786Sps		default:
20960786Sps			assert(!"Invalid loglevel.");
21060786Sps			abort();	/* XXX: gcc */
21160786Sps		}
21260786Sps
21360786Sps		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
21460786Sps		/* Attach debuglevel if this is debug log. */
21560786Sps		if (loglevel == LOG_DEBUG)
21660786Sps			fprintf(out, "[%d]", debuglevel);
21760786Sps		fprintf(out, " ");
21860786Sps		fprintf(out, "%s", pjdlog_prefix);
21960786Sps		vfprintf(out, fmt, ap);
22060786Sps		if (error != -1)
22160786Sps			fprintf(out, ": %s.", strerror(error));
22260786Sps		fprintf(out, "\n");
22360786Sps		fflush(out);
22460786Sps		break;
22560786Sps	    }
22660786Sps	case PJDLOG_MODE_SYSLOG:
22760786Sps	    {
22860786Sps		char log[1024];
22960786Sps		int len;
23060786Sps
23160786Sps		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
23260786Sps		if ((size_t)len < sizeof(log))
23360786Sps			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
23460786Sps		if (error != -1 && (size_t)len < sizeof(log)) {
23560786Sps			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
23660786Sps			    strerror(error));
23760786Sps		}
23860786Sps		syslog(loglevel, "%s", log);
23960786Sps		break;
240195941Sdelphij	    }
241195941Sdelphij	default:
242195941Sdelphij		assert(!"Invalid mode.");
24360786Sps	}
244221715Sdelphij}
24560786Sps
24660786Sps/*
24760786Sps * Regular logs.
24860786Sps */
24960786Spsvoid
25060786Spspjdlogv(int loglevel, const char *fmt, va_list ap)
25160786Sps{
25260786Sps
25360786Sps	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
25460786Sps	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
25560786Sps	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
25660786Sps	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
25760786Sps	    loglevel == LOG_INFO);
25860786Sps
259170898Sdelphij	pjdlogv_common(loglevel, 0, -1, fmt, ap);
26060786Sps}
26160786Sps
26260786Sps/*
26360786Sps * Regular logs.
26460786Sps */
26560786Spsvoid
26660786Spspjdlog(int loglevel, const char *fmt, ...)
26760786Sps{
26860786Sps	va_list ap;
26960786Sps
27060786Sps	va_start(ap, fmt);
27160786Sps	pjdlogv(loglevel, fmt, ap);
27260786Sps	va_end(ap);
27360786Sps}
27460786Sps
27560786Sps/*
27660786Sps * Debug logs.
27760786Sps */
27860786Spsvoid
27960786Spspjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
28060786Sps{
28160786Sps
28260786Sps	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
28360786Sps}
28460786Sps
28560786Sps/*
28660786Sps * Debug logs.
287170898Sdelphij */
28860786Spsvoid
28960786Spspjdlog_debug(int debuglevel, const char *fmt, ...)
290170898Sdelphij{
291170898Sdelphij	va_list ap;
29260786Sps
29360786Sps	va_start(ap, fmt);
29460786Sps	pjdlogv_debug(debuglevel, fmt, ap);
29560786Sps	va_end(ap);
29660786Sps}
29760786Sps
29860786Sps/*
29960786Sps * Error logs with errno logging.
30060786Sps */
301195941Sdelphijvoid
30260786Spspjdlogv_errno(int loglevel, const char *fmt, va_list ap)
30360786Sps{
30460786Sps
30560786Sps	pjdlogv_common(loglevel, 0, errno, fmt, ap);
30660786Sps}
30760786Sps
30860786Sps/*
30960786Sps * Error logs with errno logging.
31060786Sps */
31160786Spsvoid
31260786Spspjdlog_errno(int loglevel, const char *fmt, ...)
31360786Sps{
31460786Sps	va_list ap;
31560786Sps
31660786Sps	va_start(ap, fmt);
317191930Sdelphij	pjdlogv_errno(loglevel, fmt, ap);
318191930Sdelphij	va_end(ap);
31960786Sps}
32060786Sps
32160786Sps/*
32260786Sps * Log error, errno and exit.
323191930Sdelphij */
32460786Spsvoid
32560786Spspjdlogv_exit(int exitcode, const char *fmt, va_list ap)
32660786Sps{
32760786Sps
328191930Sdelphij	pjdlogv_errno(LOG_ERR, fmt, ap);
32960786Sps	exit(exitcode);
33060786Sps	/* NOTREACHED */
33160786Sps}
332191930Sdelphij
333191930Sdelphij/*
334191930Sdelphij * Log error, errno and exit.
335191930Sdelphij */
336191930Sdelphijvoid
337191930Sdelphijpjdlog_exit(int exitcode, const char *fmt, ...)
338191930Sdelphij{
339191930Sdelphij	va_list ap;
340191930Sdelphij
341191930Sdelphij	va_start(ap, fmt);
342191930Sdelphij	pjdlogv_exit(exitcode, fmt, ap);
343191930Sdelphij	/* NOTREACHED */
34460786Sps	va_end(ap);
34560786Sps}
346161478Sdelphij
347161478Sdelphij/*
348161478Sdelphij * Log error and exit.
349161478Sdelphij */
350161478Sdelphijvoid
351161478Sdelphijpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
352161478Sdelphij{
353161478Sdelphij
354161478Sdelphij	pjdlogv(LOG_ERR, fmt, ap);
355161478Sdelphij	exit(exitcode);
356161478Sdelphij	/* NOTREACHED */
357161478Sdelphij}
358161478Sdelphij
359161478Sdelphij/*
360161478Sdelphij * Log error and exit.
361161478Sdelphij */
362161478Sdelphijvoid
363161478Sdelphijpjdlog_exitx(int exitcode, const char *fmt, ...)
364161478Sdelphij{
365161478Sdelphij	va_list ap;
366191930Sdelphij
367191930Sdelphij	va_start(ap, fmt);
368191930Sdelphij	pjdlogv_exitx(exitcode, fmt, ap);
369191930Sdelphij	/* NOTREACHED */
370191930Sdelphij	va_end(ap);
371191930Sdelphij}
372191930Sdelphij
373191930Sdelphij/*
374191930Sdelphij * Log assertion and exit.
375191930Sdelphij */
376191930Sdelphijvoid
377191930Sdelphijpjdlog_verify(const char *func, const char *file, int line,
378191930Sdelphij    const char *failedexpr)
379191930Sdelphij{
380191930Sdelphij
381191930Sdelphij	if (func == NULL) {
382191930Sdelphij		pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
383191930Sdelphij		    failedexpr, file, line);
384191930Sdelphij	} else {
385191930Sdelphij		pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
386191930Sdelphij		    failedexpr, func, file, line);
387191930Sdelphij	}
388191930Sdelphij	abort();
389191930Sdelphij        /* NOTREACHED */
390161478Sdelphij}
391161478Sdelphij
39260786Sps