pjdlog.c revision 218132
1204076Spjd/*-
2217964Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation
3217964Spjd * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4204076Spjd * All rights reserved.
5204076Spjd *
6204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
7204076Spjd * the FreeBSD Foundation.
8204076Spjd *
9204076Spjd * Redistribution and use in source and binary forms, with or without
10204076Spjd * modification, are permitted provided that the following conditions
11204076Spjd * are met:
12204076Spjd * 1. Redistributions of source code must retain the above copyright
13204076Spjd *    notice, this list of conditions and the following disclaimer.
14204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
15204076Spjd *    notice, this list of conditions and the following disclaimer in the
16204076Spjd *    documentation and/or other materials provided with the distribution.
17204076Spjd *
18204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28204076Spjd * SUCH DAMAGE.
29204076Spjd */
30204076Spjd
31204076Spjd#include <sys/cdefs.h>
32204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 218132 2011-01-31 15:52:00Z pjd $");
33204076Spjd
34204076Spjd#include <assert.h>
35204076Spjd#include <errno.h>
36204076Spjd#include <stdarg.h>
37217965Spjd#include <stdbool.h>
38204076Spjd#include <stdio.h>
39204076Spjd#include <stdlib.h>
40204076Spjd#include <string.h>
41204076Spjd#include <syslog.h>
42204076Spjd
43204076Spjd#include "pjdlog.h"
44204076Spjd
45217965Spjdstatic bool pjdlog_initialized = false;
46218040Spjdstatic int pjdlog_mode, pjdlog_debug_level;
47204076Spjdstatic char pjdlog_prefix[128];
48204076Spjd
49217965Spjdvoid
50217965Spjdpjdlog_init(int mode)
51217965Spjd{
52217965Spjd
53217965Spjd	assert(!pjdlog_initialized);
54217965Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
55217965Spjd
56217965Spjd	if (mode == PJDLOG_MODE_SYSLOG)
57217965Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
58217965Spjd	pjdlog_mode = mode;
59218040Spjd	pjdlog_debug_level = 0;
60218040Spjd	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
61217965Spjd
62217965Spjd	pjdlog_initialized = true;
63217965Spjd}
64217965Spjd
65217965Spjdvoid
66217965Spjdpjdlog_fini(void)
67217965Spjd{
68217965Spjd
69217965Spjd	assert(pjdlog_initialized);
70217965Spjd
71217965Spjd	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
72217965Spjd		closelog();
73217965Spjd
74217965Spjd	pjdlog_initialized = false;
75217965Spjd}
76217965Spjd
77204076Spjd/*
78204076Spjd * Configure where the logs should go.
79204076Spjd * By default they are send to stdout/stderr, but after going into background
80204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to
81204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
82204076Spjd */
83204076Spjdvoid
84204076Spjdpjdlog_mode_set(int mode)
85204076Spjd{
86204076Spjd
87217965Spjd	assert(pjdlog_initialized);
88204076Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
89204076Spjd
90217965Spjd	if (pjdlog_mode == mode)
91217965Spjd		return;
92212052Spjd
93212052Spjd	if (mode == PJDLOG_MODE_SYSLOG)
94217962Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
95217965Spjd	else /* if (mode == PJDLOG_MODE_STD) */
96217965Spjd		closelog();
97217965Spjd
98217965Spjd	pjdlog_mode = mode;
99204076Spjd}
100204076Spjd
101204076Spjd/*
102204076Spjd * Return current mode.
103204076Spjd */
104204076Spjdint
105204076Spjdpjdlog_mode_get(void)
106204076Spjd{
107204076Spjd
108217965Spjd	assert(pjdlog_initialized);
109217965Spjd
110204076Spjd	return (pjdlog_mode);
111204076Spjd}
112204076Spjd
113204076Spjd/*
114204076Spjd * Set debug level. All the logs above the level specified here will be
115204076Spjd * ignored.
116204076Spjd */
117204076Spjdvoid
118204076Spjdpjdlog_debug_set(int level)
119204076Spjd{
120204076Spjd
121217965Spjd	assert(pjdlog_initialized);
122204076Spjd	assert(level >= 0);
123204076Spjd
124204076Spjd	pjdlog_debug_level = level;
125204076Spjd}
126204076Spjd
127204076Spjd/*
128204076Spjd * Return current debug level.
129204076Spjd */
130204076Spjdint
131204076Spjdpjdlog_debug_get(void)
132204076Spjd{
133204076Spjd
134217965Spjd	assert(pjdlog_initialized);
135217965Spjd
136204076Spjd	return (pjdlog_debug_level);
137204076Spjd}
138204076Spjd
139204076Spjd/*
140204076Spjd * Set prefix that will be used before each log.
141204076Spjd * Setting prefix to NULL will remove it.
142204076Spjd */
143204076Spjdvoid
144204076Spjdpjdlog_prefix_set(const char *fmt, ...)
145204076Spjd{
146204076Spjd	va_list ap;
147204076Spjd
148217965Spjd	assert(pjdlog_initialized);
149217965Spjd
150204076Spjd	va_start(ap, fmt);
151217731Spjd	pjdlogv_prefix_set(fmt, ap);
152204076Spjd	va_end(ap);
153204076Spjd}
154204076Spjd
155204076Spjd/*
156204076Spjd * Set prefix that will be used before each log.
157204076Spjd * Setting prefix to NULL will remove it.
158204076Spjd */
159204076Spjdvoid
160217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap)
161204076Spjd{
162204076Spjd
163217965Spjd	assert(pjdlog_initialized);
164204076Spjd	assert(fmt != NULL);
165204076Spjd
166204076Spjd	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
167204076Spjd}
168204076Spjd
169204076Spjd/*
170204076Spjd * Convert log level into string.
171204076Spjd */
172204076Spjdstatic const char *
173204076Spjdpjdlog_level_string(int loglevel)
174204076Spjd{
175204076Spjd
176204076Spjd	switch (loglevel) {
177204076Spjd	case LOG_EMERG:
178204076Spjd		return ("EMERG");
179204076Spjd	case LOG_ALERT:
180204076Spjd		return ("ALERT");
181204076Spjd	case LOG_CRIT:
182204076Spjd		return ("CRIT");
183204076Spjd	case LOG_ERR:
184204076Spjd		return ("ERROR");
185204076Spjd	case LOG_WARNING:
186204076Spjd		return ("WARNING");
187204076Spjd	case LOG_NOTICE:
188204076Spjd		return ("NOTICE");
189204076Spjd	case LOG_INFO:
190204076Spjd		return ("INFO");
191204076Spjd	case LOG_DEBUG:
192204076Spjd		return ("DEBUG");
193204076Spjd	}
194204076Spjd	assert(!"Invalid log level.");
195204076Spjd	abort();	/* XXX: gcc */
196204076Spjd}
197204076Spjd
198204076Spjd/*
199204076Spjd * Common log routine.
200204076Spjd */
201204076Spjdvoid
202204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
203204076Spjd{
204204076Spjd	va_list ap;
205204076Spjd
206217965Spjd	assert(pjdlog_initialized);
207217965Spjd
208204076Spjd	va_start(ap, fmt);
209204076Spjd	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
210204076Spjd	va_end(ap);
211204076Spjd}
212204076Spjd
213204076Spjd/*
214204076Spjd * Common log routine, which can handle regular log level as well as debug
215204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog).
216204076Spjd */
217204076Spjdvoid
218204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
219204076Spjd    va_list ap)
220204076Spjd{
221204076Spjd
222217965Spjd	assert(pjdlog_initialized);
223204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
224204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
225204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
226204076Spjd	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
227204076Spjd	assert(loglevel != LOG_DEBUG || debuglevel > 0);
228204076Spjd	assert(error >= -1);
229204076Spjd
230204076Spjd	/* Ignore debug above configured level. */
231204076Spjd	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
232204076Spjd		return;
233204076Spjd
234204076Spjd	switch (pjdlog_mode) {
235204076Spjd	case PJDLOG_MODE_STD:
236204076Spjd	    {
237204076Spjd		FILE *out;
238204076Spjd
239204076Spjd		/*
240204076Spjd		 * We send errors and warning to stderr and the rest to stdout.
241204076Spjd		 */
242204076Spjd		switch (loglevel) {
243204076Spjd		case LOG_EMERG:
244204076Spjd		case LOG_ALERT:
245204076Spjd		case LOG_CRIT:
246204076Spjd		case LOG_ERR:
247204076Spjd		case LOG_WARNING:
248204076Spjd			out = stderr;
249204076Spjd			break;
250204076Spjd		case LOG_NOTICE:
251204076Spjd		case LOG_INFO:
252204076Spjd		case LOG_DEBUG:
253204076Spjd			out = stdout;
254204076Spjd			break;
255204076Spjd		default:
256204076Spjd			assert(!"Invalid loglevel.");
257204076Spjd			abort();	/* XXX: gcc */
258204076Spjd		}
259204076Spjd
260204076Spjd		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
261204076Spjd		/* Attach debuglevel if this is debug log. */
262204076Spjd		if (loglevel == LOG_DEBUG)
263204076Spjd			fprintf(out, "[%d]", debuglevel);
264213939Spjd		fprintf(out, " %s", pjdlog_prefix);
265204076Spjd		vfprintf(out, fmt, ap);
266204076Spjd		if (error != -1)
267204076Spjd			fprintf(out, ": %s.", strerror(error));
268204076Spjd		fprintf(out, "\n");
269211898Spjd		fflush(out);
270204076Spjd		break;
271204076Spjd	    }
272204076Spjd	case PJDLOG_MODE_SYSLOG:
273204076Spjd	    {
274204076Spjd		char log[1024];
275204076Spjd		int len;
276204076Spjd
277204076Spjd		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
278204076Spjd		if ((size_t)len < sizeof(log))
279206697Spjd			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
280204076Spjd		if (error != -1 && (size_t)len < sizeof(log)) {
281204076Spjd			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
282204076Spjd			    strerror(error));
283204076Spjd		}
284204076Spjd		syslog(loglevel, "%s", log);
285204076Spjd		break;
286204076Spjd	    }
287204076Spjd	default:
288204076Spjd		assert(!"Invalid mode.");
289204076Spjd	}
290204076Spjd}
291204076Spjd
292204076Spjd/*
293204076Spjd * Regular logs.
294204076Spjd */
295204076Spjdvoid
296204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap)
297204076Spjd{
298204076Spjd
299217965Spjd	assert(pjdlog_initialized);
300217965Spjd
301204076Spjd	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
302204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
303204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
304204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
305204076Spjd	    loglevel == LOG_INFO);
306204076Spjd
307204076Spjd	pjdlogv_common(loglevel, 0, -1, fmt, ap);
308204076Spjd}
309204076Spjd
310204076Spjd/*
311204076Spjd * Regular logs.
312204076Spjd */
313204076Spjdvoid
314204076Spjdpjdlog(int loglevel, const char *fmt, ...)
315204076Spjd{
316204076Spjd	va_list ap;
317204076Spjd
318217965Spjd	assert(pjdlog_initialized);
319217965Spjd
320204076Spjd	va_start(ap, fmt);
321204076Spjd	pjdlogv(loglevel, fmt, ap);
322204076Spjd	va_end(ap);
323204076Spjd}
324204076Spjd
325204076Spjd/*
326204076Spjd * Debug logs.
327204076Spjd */
328204076Spjdvoid
329204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
330204076Spjd{
331204076Spjd
332217965Spjd	assert(pjdlog_initialized);
333217965Spjd
334204076Spjd	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
335204076Spjd}
336204076Spjd
337204076Spjd/*
338204076Spjd * Debug logs.
339204076Spjd */
340204076Spjdvoid
341204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...)
342204076Spjd{
343204076Spjd	va_list ap;
344204076Spjd
345217965Spjd	assert(pjdlog_initialized);
346217965Spjd
347204076Spjd	va_start(ap, fmt);
348204076Spjd	pjdlogv_debug(debuglevel, fmt, ap);
349204076Spjd	va_end(ap);
350204076Spjd}
351204076Spjd
352204076Spjd/*
353204076Spjd * Error logs with errno logging.
354204076Spjd */
355204076Spjdvoid
356204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap)
357204076Spjd{
358204076Spjd
359217965Spjd	assert(pjdlog_initialized);
360217965Spjd
361204076Spjd	pjdlogv_common(loglevel, 0, errno, fmt, ap);
362204076Spjd}
363204076Spjd
364204076Spjd/*
365204076Spjd * Error logs with errno logging.
366204076Spjd */
367204076Spjdvoid
368204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...)
369204076Spjd{
370204076Spjd	va_list ap;
371204076Spjd
372217965Spjd	assert(pjdlog_initialized);
373217965Spjd
374204076Spjd	va_start(ap, fmt);
375204076Spjd	pjdlogv_errno(loglevel, fmt, ap);
376204076Spjd	va_end(ap);
377204076Spjd}
378204076Spjd
379204076Spjd/*
380204076Spjd * Log error, errno and exit.
381204076Spjd */
382204076Spjdvoid
383204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap)
384204076Spjd{
385204076Spjd
386217965Spjd	assert(pjdlog_initialized);
387217965Spjd
388204076Spjd	pjdlogv_errno(LOG_ERR, fmt, ap);
389204076Spjd	exit(exitcode);
390210872Spjd	/* NOTREACHED */
391204076Spjd}
392204076Spjd
393204076Spjd/*
394204076Spjd * Log error, errno and exit.
395204076Spjd */
396204076Spjdvoid
397204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...)
398204076Spjd{
399204076Spjd	va_list ap;
400204076Spjd
401217965Spjd	assert(pjdlog_initialized);
402217965Spjd
403204076Spjd	va_start(ap, fmt);
404204076Spjd	pjdlogv_exit(exitcode, fmt, ap);
405204076Spjd	/* NOTREACHED */
406204076Spjd	va_end(ap);
407204076Spjd}
408204076Spjd
409204076Spjd/*
410204076Spjd * Log error and exit.
411204076Spjd */
412204076Spjdvoid
413204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
414204076Spjd{
415204076Spjd
416217965Spjd	assert(pjdlog_initialized);
417217965Spjd
418204076Spjd	pjdlogv(LOG_ERR, fmt, ap);
419204076Spjd	exit(exitcode);
420210872Spjd	/* NOTREACHED */
421204076Spjd}
422204076Spjd
423204076Spjd/*
424204076Spjd * Log error and exit.
425204076Spjd */
426204076Spjdvoid
427204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...)
428204076Spjd{
429204076Spjd	va_list ap;
430204076Spjd
431217965Spjd	assert(pjdlog_initialized);
432217965Spjd
433204076Spjd	va_start(ap, fmt);
434204076Spjd	pjdlogv_exitx(exitcode, fmt, ap);
435204076Spjd	/* NOTREACHED */
436204076Spjd	va_end(ap);
437204076Spjd}
438210875Spjd
439210875Spjd/*
440218132Spjd * Log failure message and exit.
441210875Spjd */
442210875Spjdvoid
443218132Spjdpjdlog_abort(const char *func, const char *file, int line,
444217966Spjd    const char *failedexpr, const char *fmt, ...)
445210875Spjd{
446217966Spjd	va_list ap;
447210875Spjd
448217966Spjd	assert(pjdlog_initialized);
449217966Spjd
450217966Spjd	/*
451217966Spjd	 * When there is no message we pass __func__ as 'fmt'.
452217966Spjd	 * It would be cleaner to pass NULL or "", but gcc generates a warning
453217966Spjd	 * for both of those.
454217966Spjd	 */
455217966Spjd	if (fmt != func) {
456217966Spjd		va_start(ap, fmt);
457217966Spjd		pjdlogv_critical(fmt, ap);
458217966Spjd		va_end(ap);
459217966Spjd	}
460217966Spjd	if (failedexpr == NULL) {
461217966Spjd		if (func == NULL) {
462217966Spjd			pjdlog_critical("Aborted at file %s, line %d.", file,
463217966Spjd			    line);
464217966Spjd		} else {
465217966Spjd			pjdlog_critical("Aborted at function %s, file %s, line %d.",
466217966Spjd			    func, file, line);
467217966Spjd		}
468210875Spjd	} else {
469217966Spjd		if (func == NULL) {
470217966Spjd			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
471217966Spjd			    failedexpr, file, line);
472217966Spjd		} else {
473217966Spjd			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
474217966Spjd			    failedexpr, func, file, line);
475217966Spjd		}
476210875Spjd	}
477210875Spjd	abort();
478210875Spjd}
479