pjdlog.c revision 218040
1237263Snp/*-
2237263Snp * Copyright (c) 2009-2010 The FreeBSD Foundation
3237263Snp * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4237263Snp * All rights reserved.
5237263Snp *
6237263Snp * This software was developed by Pawel Jakub Dawidek under sponsorship from
7237263Snp * the FreeBSD Foundation.
8237263Snp *
9237263Snp * Redistribution and use in source and binary forms, with or without
10237263Snp * modification, are permitted provided that the following conditions
11237263Snp * are met:
12237263Snp * 1. Redistributions of source code must retain the above copyright
13237263Snp *    notice, this list of conditions and the following disclaimer.
14237263Snp * 2. Redistributions in binary form must reproduce the above copyright
15237263Snp *    notice, this list of conditions and the following disclaimer in the
16237263Snp *    documentation and/or other materials provided with the distribution.
17237263Snp *
18237263Snp * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19237263Snp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20237263Snp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21237263Snp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22237263Snp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23237263Snp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24237263Snp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25237263Snp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26237263Snp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27237263Snp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28237263Snp * SUCH DAMAGE.
29237263Snp */
30237263Snp
31237263Snp#include <sys/cdefs.h>
32237263Snp__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 218040 2011-01-28 21:36:01Z pjd $");
33237263Snp
34237263Snp#include <assert.h>
35237263Snp#include <errno.h>
36237263Snp#include <stdarg.h>
37237263Snp#include <stdbool.h>
38237263Snp#include <stdio.h>
39237263Snp#include <stdlib.h>
40237263Snp#include <string.h>
41237263Snp#include <syslog.h>
42237263Snp
43237263Snp#include "pjdlog.h"
44237263Snp
45237263Snpstatic bool pjdlog_initialized = false;
46237263Snpstatic int pjdlog_mode, pjdlog_debug_level;
47237263Snpstatic char pjdlog_prefix[128];
48237263Snp
49237263Snpvoid
50237263Snppjdlog_init(int mode)
51237263Snp{
52237263Snp
53237263Snp	assert(!pjdlog_initialized);
54237263Snp	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
55237263Snp
56240169Snp	if (mode == PJDLOG_MODE_SYSLOG)
57237263Snp		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
58237263Snp	pjdlog_mode = mode;
59237263Snp	pjdlog_debug_level = 0;
60237263Snp	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
61237263Snp
62237263Snp	pjdlog_initialized = true;
63237263Snp}
64237263Snp
65237263Snpvoid
66237263Snppjdlog_fini(void)
67237263Snp{
68237263Snp
69237263Snp	assert(pjdlog_initialized);
70237263Snp
71237263Snp	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
72237263Snp		closelog();
73237263Snp
74237263Snp	pjdlog_initialized = false;
75237263Snp}
76241898Snp
77241898Snp/*
78241898Snp * Configure where the logs should go.
79237263Snp * By default they are send to stdout/stderr, but after going into background
80237263Snp * (eg. by calling daemon(3)) application is responsible for changing mode to
81237263Snp * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
82237263Snp */
83237263Snpvoid
84240169Snppjdlog_mode_set(int mode)
85237263Snp{
86237263Snp
87237263Snp	assert(pjdlog_initialized);
88237263Snp	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
89237263Snp
90237263Snp	if (pjdlog_mode == mode)
91252495Snp		return;
92237263Snp
93237263Snp	if (mode == PJDLOG_MODE_SYSLOG)
94237263Snp		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
95237263Snp	else /* if (mode == PJDLOG_MODE_STD) */
96237263Snp		closelog();
97237263Snp
98237263Snp	pjdlog_mode = mode;
99237263Snp}
100237263Snp
101237263Snp/*
102237263Snp * Return current mode.
103237263Snp */
104237263Snpint
105241898Snppjdlog_mode_get(void)
106241898Snp{
107241898Snp
108241898Snp	assert(pjdlog_initialized);
109241898Snp
110241898Snp	return (pjdlog_mode);
111241898Snp}
112237263Snp
113237263Snp/*
114237263Snp * Set debug level. All the logs above the level specified here will be
115237263Snp * ignored.
116237263Snp */
117237263Snpvoid
118237263Snppjdlog_debug_set(int level)
119237263Snp{
120237263Snp
121237263Snp	assert(pjdlog_initialized);
122237263Snp	assert(level >= 0);
123241898Snp
124241898Snp	pjdlog_debug_level = level;
125241898Snp}
126241898Snp
127241898Snp/*
128237263Snp * Return current debug level.
129237263Snp */
130237263Snpint
131237263Snppjdlog_debug_get(void)
132237263Snp{
133237263Snp
134237263Snp	assert(pjdlog_initialized);
135237263Snp
136237263Snp	return (pjdlog_debug_level);
137237263Snp}
138237263Snp
139240169Snp/*
140237263Snp * Set prefix that will be used before each log.
141237263Snp * Setting prefix to NULL will remove it.
142237263Snp */
143237263Snpvoid
144237263Snppjdlog_prefix_set(const char *fmt, ...)
145237263Snp{
146237263Snp	va_list ap;
147237263Snp
148237263Snp	assert(pjdlog_initialized);
149237263Snp
150237263Snp	va_start(ap, fmt);
151237263Snp	pjdlogv_prefix_set(fmt, ap);
152237263Snp	va_end(ap);
153237263Snp}
154237263Snp
155237263Snp/*
156237263Snp * Set prefix that will be used before each log.
157237263Snp * Setting prefix to NULL will remove it.
158237263Snp */
159240169Snpvoid
160237263Snppjdlogv_prefix_set(const char *fmt, va_list ap)
161237263Snp{
162240169Snp
163237263Snp	assert(pjdlog_initialized);
164237263Snp	assert(fmt != NULL);
165240169Snp
166237263Snp	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
167240169Snp}
168237263Snp
169237263Snp/*
170237263Snp * Convert log level into string.
171237263Snp */
172237263Snpstatic const char *
173237263Snppjdlog_level_string(int loglevel)
174237263Snp{
175237263Snp
176237263Snp	switch (loglevel) {
177237263Snp	case LOG_EMERG:
178237263Snp		return ("EMERG");
179237263Snp	case LOG_ALERT:
180237263Snp		return ("ALERT");
181237263Snp	case LOG_CRIT:
182240169Snp		return ("CRIT");
183237263Snp	case LOG_ERR:
184237263Snp		return ("ERROR");
185237263Snp	case LOG_WARNING:
186237263Snp		return ("WARNING");
187237263Snp	case LOG_NOTICE:
188237263Snp		return ("NOTICE");
189237263Snp	case LOG_INFO:
190237263Snp		return ("INFO");
191237263Snp	case LOG_DEBUG:
192237263Snp		return ("DEBUG");
193237263Snp	}
194237263Snp	assert(!"Invalid log level.");
195237263Snp	abort();	/* XXX: gcc */
196237263Snp}
197237263Snp
198237263Snp/*
199237263Snp * Common log routine.
200237263Snp */
201237263Snpvoid
202237263Snppjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
203237263Snp{
204237263Snp	va_list ap;
205237263Snp
206237263Snp	assert(pjdlog_initialized);
207237263Snp
208237263Snp	va_start(ap, fmt);
209237263Snp	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
210237263Snp	va_end(ap);
211237263Snp}
212237263Snp
213237263Snp/*
214237263Snp * Common log routine, which can handle regular log level as well as debug
215237263Snp * level. We decide here where to send the logs (stdout/stderr or syslog).
216237263Snp */
217237263Snpvoid
218237263Snppjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
219237263Snp    va_list ap)
220237263Snp{
221237263Snp
222237263Snp	assert(pjdlog_initialized);
223237263Snp	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
224237263Snp	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
225237263Snp	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
226237263Snp	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
227237263Snp	assert(loglevel != LOG_DEBUG || debuglevel > 0);
228237263Snp	assert(error >= -1);
229237263Snp
230237263Snp	/* Ignore debug above configured level. */
231237263Snp	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
232237263Snp		return;
233237263Snp
234237263Snp	switch (pjdlog_mode) {
235237263Snp	case PJDLOG_MODE_STD:
236237263Snp	    {
237237263Snp		FILE *out;
238237263Snp
239237263Snp		/*
240237263Snp		 * We send errors and warning to stderr and the rest to stdout.
241237263Snp		 */
242237263Snp		switch (loglevel) {
243237263Snp		case LOG_EMERG:
244237263Snp		case LOG_ALERT:
245237263Snp		case LOG_CRIT:
246237263Snp		case LOG_ERR:
247237263Snp		case LOG_WARNING:
248237263Snp			out = stderr;
249237263Snp			break;
250237263Snp		case LOG_NOTICE:
251237263Snp		case LOG_INFO:
252237263Snp		case LOG_DEBUG:
253237263Snp			out = stdout;
254237263Snp			break;
255237263Snp		default:
256237263Snp			assert(!"Invalid loglevel.");
257237263Snp			abort();	/* XXX: gcc */
258237263Snp		}
259237263Snp
260237263Snp		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
261237263Snp		/* Attach debuglevel if this is debug log. */
262237263Snp		if (loglevel == LOG_DEBUG)
263237263Snp			fprintf(out, "[%d]", debuglevel);
264237263Snp		fprintf(out, " %s", pjdlog_prefix);
265237263Snp		vfprintf(out, fmt, ap);
266237263Snp		if (error != -1)
267237263Snp			fprintf(out, ": %s.", strerror(error));
268237263Snp		fprintf(out, "\n");
269237263Snp		fflush(out);
270237263Snp		break;
271237263Snp	    }
272237263Snp	case PJDLOG_MODE_SYSLOG:
273237263Snp	    {
274237263Snp		char log[1024];
275237263Snp		int len;
276237263Snp
277237263Snp		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
278237263Snp		if ((size_t)len < sizeof(log))
279237263Snp			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
280237263Snp		if (error != -1 && (size_t)len < sizeof(log)) {
281237263Snp			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
282237263Snp			    strerror(error));
283237263Snp		}
284237263Snp		syslog(loglevel, "%s", log);
285237263Snp		break;
286237263Snp	    }
287237263Snp	default:
288237263Snp		assert(!"Invalid mode.");
289237263Snp	}
290237263Snp}
291237263Snp
292237263Snp/*
293237263Snp * Regular logs.
294237263Snp */
295237263Snpvoid
296237263Snppjdlogv(int loglevel, const char *fmt, va_list ap)
297237263Snp{
298237263Snp
299237263Snp	assert(pjdlog_initialized);
300237263Snp
301237263Snp	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
302237263Snp	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
303237263Snp	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
304237263Snp	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
305237263Snp	    loglevel == LOG_INFO);
306237263Snp
307237263Snp	pjdlogv_common(loglevel, 0, -1, fmt, ap);
308240169Snp}
309237263Snp
310237263Snp/*
311237263Snp * Regular logs.
312237263Snp */
313237263Snpvoid
314240169Snppjdlog(int loglevel, const char *fmt, ...)
315240169Snp{
316237263Snp	va_list ap;
317237263Snp
318237263Snp	assert(pjdlog_initialized);
319237263Snp
320237263Snp	va_start(ap, fmt);
321237263Snp	pjdlogv(loglevel, fmt, ap);
322237263Snp	va_end(ap);
323237263Snp}
324237263Snp
325237263Snp/*
326237263Snp * Debug logs.
327237263Snp */
328237263Snpvoid
329237263Snppjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
330237263Snp{
331237263Snp
332237263Snp	assert(pjdlog_initialized);
333237263Snp
334240169Snp	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
335237263Snp}
336240169Snp
337237263Snp/*
338237263Snp * Debug logs.
339237263Snp */
340240169Snpvoid
341240169Snppjdlog_debug(int debuglevel, const char *fmt, ...)
342240169Snp{
343240169Snp	va_list ap;
344240169Snp
345240169Snp	assert(pjdlog_initialized);
346240169Snp
347240169Snp	va_start(ap, fmt);
348237263Snp	pjdlogv_debug(debuglevel, fmt, ap);
349240169Snp	va_end(ap);
350240169Snp}
351237263Snp
352240169Snp/*
353240169Snp * Error logs with errno logging.
354237263Snp */
355240169Snpvoid
356237263Snppjdlogv_errno(int loglevel, const char *fmt, va_list ap)
357237263Snp{
358237263Snp
359237263Snp	assert(pjdlog_initialized);
360237263Snp
361237263Snp	pjdlogv_common(loglevel, 0, errno, fmt, ap);
362237263Snp}
363237263Snp
364237263Snp/*
365237263Snp * Error logs with errno logging.
366237263Snp */
367237263Snpvoid
368237263Snppjdlog_errno(int loglevel, const char *fmt, ...)
369237263Snp{
370237263Snp	va_list ap;
371237263Snp
372240169Snp	assert(pjdlog_initialized);
373237263Snp
374240169Snp	va_start(ap, fmt);
375237263Snp	pjdlogv_errno(loglevel, fmt, ap);
376237263Snp	va_end(ap);
377240169Snp}
378237263Snp
379237263Snp/*
380237263Snp * Log error, errno and exit.
381237263Snp */
382237263Snpvoid
383237263Snppjdlogv_exit(int exitcode, const char *fmt, va_list ap)
384237263Snp{
385237263Snp
386237263Snp	assert(pjdlog_initialized);
387237263Snp
388237263Snp	pjdlogv_errno(LOG_ERR, fmt, ap);
389237263Snp	exit(exitcode);
390237263Snp	/* NOTREACHED */
391237263Snp}
392237263Snp
393237263Snp/*
394237263Snp * Log error, errno and exit.
395240169Snp */
396240169Snpvoid
397237263Snppjdlog_exit(int exitcode, const char *fmt, ...)
398237263Snp{
399237263Snp	va_list ap;
400237263Snp
401237263Snp	assert(pjdlog_initialized);
402237263Snp
403237263Snp	va_start(ap, fmt);
404237263Snp	pjdlogv_exit(exitcode, fmt, ap);
405237263Snp	/* NOTREACHED */
406237263Snp	va_end(ap);
407237263Snp}
408237263Snp
409237263Snp/*
410237263Snp * Log error and exit.
411237263Snp */
412237263Snpvoid
413237263Snppjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
414237263Snp{
415237263Snp
416237263Snp	assert(pjdlog_initialized);
417237263Snp
418237263Snp	pjdlogv(LOG_ERR, fmt, ap);
419237263Snp	exit(exitcode);
420237263Snp	/* NOTREACHED */
421237263Snp}
422237263Snp
423237263Snp/*
424237263Snp * Log error and exit.
425237263Snp */
426237263Snpvoid
427237263Snppjdlog_exitx(int exitcode, const char *fmt, ...)
428237263Snp{
429237263Snp	va_list ap;
430237263Snp
431237263Snp	assert(pjdlog_initialized);
432237263Snp
433237263Snp	va_start(ap, fmt);
434237263Snp	pjdlogv_exitx(exitcode, fmt, ap);
435237263Snp	/* NOTREACHED */
436237263Snp	va_end(ap);
437237263Snp}
438237263Snp
439237263Snp/*
440237263Snp * Log assertion and exit.
441237263Snp */
442237263Snpvoid
443237263Snppjdlog_verify(const char *func, const char *file, int line,
444237263Snp    const char *failedexpr, const char *fmt, ...)
445237263Snp{
446237263Snp	va_list ap;
447237263Snp
448237263Snp	assert(pjdlog_initialized);
449237263Snp
450237263Snp	/*
451237263Snp	 * When there is no message we pass __func__ as 'fmt'.
452237263Snp	 * It would be cleaner to pass NULL or "", but gcc generates a warning
453237263Snp	 * for both of those.
454237263Snp	 */
455237263Snp	if (fmt != func) {
456237263Snp		va_start(ap, fmt);
457237263Snp		pjdlogv_critical(fmt, ap);
458237263Snp		va_end(ap);
459237263Snp	}
460237263Snp	if (failedexpr == NULL) {
461237263Snp		if (func == NULL) {
462237263Snp			pjdlog_critical("Aborted at file %s, line %d.", file,
463237263Snp			    line);
464237263Snp		} else {
465237263Snp			pjdlog_critical("Aborted at function %s, file %s, line %d.",
466237263Snp			    func, file, line);
467237263Snp		}
468237263Snp	} else {
469237263Snp		if (func == NULL) {
470237263Snp			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
471237263Snp			    failedexpr, file, line);
472237263Snp		} else {
473237263Snp			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
474237263Snp			    failedexpr, func, file, line);
475237263Snp		}
476237263Snp	}
477237263Snp	abort();
478237263Snp}
479237263Snp