pjdlog.c revision 219369
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 219369 2011-03-07 10:33:52Z pjd $");
33204076Spjd
34204076Spjd#include <assert.h>
35204076Spjd#include <errno.h>
36204076Spjd#include <stdarg.h>
37204076Spjd#include <stdio.h>
38204076Spjd#include <stdlib.h>
39204076Spjd#include <string.h>
40204076Spjd#include <syslog.h>
41204076Spjd
42204076Spjd#include "pjdlog.h"
43204076Spjd
44219369Spjd#define	PJDLOG_NEVER_INITIALIZED	0
45219369Spjd#define	PJDLOG_NOT_INITIALIZED		1
46219369Spjd#define	PJDLOG_INITIALIZED		2
47219369Spjd
48219369Spjdstatic int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
49218040Spjdstatic int pjdlog_mode, pjdlog_debug_level;
50204076Spjdstatic char pjdlog_prefix[128];
51204076Spjd
52217965Spjdvoid
53217965Spjdpjdlog_init(int mode)
54217965Spjd{
55217965Spjd
56219369Spjd	assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
57219369Spjd	    pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
58217965Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
59217965Spjd
60217965Spjd	if (mode == PJDLOG_MODE_SYSLOG)
61217965Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
62217965Spjd	pjdlog_mode = mode;
63218040Spjd	pjdlog_debug_level = 0;
64218040Spjd	bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
65217965Spjd
66219369Spjd	pjdlog_initialized = PJDLOG_INITIALIZED;
67217965Spjd}
68217965Spjd
69217965Spjdvoid
70217965Spjdpjdlog_fini(void)
71217965Spjd{
72217965Spjd
73219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
74217965Spjd
75217965Spjd	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
76217965Spjd		closelog();
77217965Spjd
78219369Spjd	pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
79217965Spjd}
80217965Spjd
81204076Spjd/*
82204076Spjd * Configure where the logs should go.
83204076Spjd * By default they are send to stdout/stderr, but after going into background
84204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to
85204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
86204076Spjd */
87204076Spjdvoid
88204076Spjdpjdlog_mode_set(int mode)
89204076Spjd{
90204076Spjd
91219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
92204076Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
93204076Spjd
94217965Spjd	if (pjdlog_mode == mode)
95217965Spjd		return;
96212052Spjd
97212052Spjd	if (mode == PJDLOG_MODE_SYSLOG)
98217962Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
99217965Spjd	else /* if (mode == PJDLOG_MODE_STD) */
100217965Spjd		closelog();
101217965Spjd
102217965Spjd	pjdlog_mode = mode;
103204076Spjd}
104204076Spjd
105204076Spjd/*
106204076Spjd * Return current mode.
107204076Spjd */
108204076Spjdint
109204076Spjdpjdlog_mode_get(void)
110204076Spjd{
111204076Spjd
112219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
113217965Spjd
114204076Spjd	return (pjdlog_mode);
115204076Spjd}
116204076Spjd
117204076Spjd/*
118204076Spjd * Set debug level. All the logs above the level specified here will be
119204076Spjd * ignored.
120204076Spjd */
121204076Spjdvoid
122204076Spjdpjdlog_debug_set(int level)
123204076Spjd{
124204076Spjd
125219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
126204076Spjd	assert(level >= 0);
127204076Spjd
128204076Spjd	pjdlog_debug_level = level;
129204076Spjd}
130204076Spjd
131204076Spjd/*
132204076Spjd * Return current debug level.
133204076Spjd */
134204076Spjdint
135204076Spjdpjdlog_debug_get(void)
136204076Spjd{
137204076Spjd
138219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
139217965Spjd
140204076Spjd	return (pjdlog_debug_level);
141204076Spjd}
142204076Spjd
143204076Spjd/*
144204076Spjd * Set prefix that will be used before each log.
145204076Spjd * Setting prefix to NULL will remove it.
146204076Spjd */
147204076Spjdvoid
148204076Spjdpjdlog_prefix_set(const char *fmt, ...)
149204076Spjd{
150204076Spjd	va_list ap;
151204076Spjd
152219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
153217965Spjd
154204076Spjd	va_start(ap, fmt);
155217731Spjd	pjdlogv_prefix_set(fmt, ap);
156204076Spjd	va_end(ap);
157204076Spjd}
158204076Spjd
159204076Spjd/*
160204076Spjd * Set prefix that will be used before each log.
161204076Spjd * Setting prefix to NULL will remove it.
162204076Spjd */
163204076Spjdvoid
164217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap)
165204076Spjd{
166204076Spjd
167219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
168204076Spjd	assert(fmt != NULL);
169204076Spjd
170204076Spjd	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
171204076Spjd}
172204076Spjd
173204076Spjd/*
174204076Spjd * Convert log level into string.
175204076Spjd */
176204076Spjdstatic const char *
177204076Spjdpjdlog_level_string(int loglevel)
178204076Spjd{
179204076Spjd
180204076Spjd	switch (loglevel) {
181204076Spjd	case LOG_EMERG:
182204076Spjd		return ("EMERG");
183204076Spjd	case LOG_ALERT:
184204076Spjd		return ("ALERT");
185204076Spjd	case LOG_CRIT:
186204076Spjd		return ("CRIT");
187204076Spjd	case LOG_ERR:
188204076Spjd		return ("ERROR");
189204076Spjd	case LOG_WARNING:
190204076Spjd		return ("WARNING");
191204076Spjd	case LOG_NOTICE:
192204076Spjd		return ("NOTICE");
193204076Spjd	case LOG_INFO:
194204076Spjd		return ("INFO");
195204076Spjd	case LOG_DEBUG:
196204076Spjd		return ("DEBUG");
197204076Spjd	}
198204076Spjd	assert(!"Invalid log level.");
199204076Spjd	abort();	/* XXX: gcc */
200204076Spjd}
201204076Spjd
202204076Spjd/*
203204076Spjd * Common log routine.
204204076Spjd */
205204076Spjdvoid
206204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
207204076Spjd{
208204076Spjd	va_list ap;
209204076Spjd
210219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
211217965Spjd
212204076Spjd	va_start(ap, fmt);
213204076Spjd	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
214204076Spjd	va_end(ap);
215204076Spjd}
216204076Spjd
217204076Spjd/*
218204076Spjd * Common log routine, which can handle regular log level as well as debug
219204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog).
220204076Spjd */
221204076Spjdvoid
222204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
223204076Spjd    va_list ap)
224204076Spjd{
225204076Spjd
226219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
227204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
228204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
229204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
230204076Spjd	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
231204076Spjd	assert(loglevel != LOG_DEBUG || debuglevel > 0);
232204076Spjd	assert(error >= -1);
233204076Spjd
234204076Spjd	/* Ignore debug above configured level. */
235204076Spjd	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
236204076Spjd		return;
237204076Spjd
238204076Spjd	switch (pjdlog_mode) {
239204076Spjd	case PJDLOG_MODE_STD:
240204076Spjd	    {
241204076Spjd		FILE *out;
242204076Spjd
243204076Spjd		/*
244204076Spjd		 * We send errors and warning to stderr and the rest to stdout.
245204076Spjd		 */
246204076Spjd		switch (loglevel) {
247204076Spjd		case LOG_EMERG:
248204076Spjd		case LOG_ALERT:
249204076Spjd		case LOG_CRIT:
250204076Spjd		case LOG_ERR:
251204076Spjd		case LOG_WARNING:
252204076Spjd			out = stderr;
253204076Spjd			break;
254204076Spjd		case LOG_NOTICE:
255204076Spjd		case LOG_INFO:
256204076Spjd		case LOG_DEBUG:
257204076Spjd			out = stdout;
258204076Spjd			break;
259204076Spjd		default:
260204076Spjd			assert(!"Invalid loglevel.");
261204076Spjd			abort();	/* XXX: gcc */
262204076Spjd		}
263204076Spjd
264204076Spjd		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
265204076Spjd		/* Attach debuglevel if this is debug log. */
266204076Spjd		if (loglevel == LOG_DEBUG)
267204076Spjd			fprintf(out, "[%d]", debuglevel);
268213939Spjd		fprintf(out, " %s", pjdlog_prefix);
269204076Spjd		vfprintf(out, fmt, ap);
270204076Spjd		if (error != -1)
271204076Spjd			fprintf(out, ": %s.", strerror(error));
272204076Spjd		fprintf(out, "\n");
273211898Spjd		fflush(out);
274204076Spjd		break;
275204076Spjd	    }
276204076Spjd	case PJDLOG_MODE_SYSLOG:
277204076Spjd	    {
278204076Spjd		char log[1024];
279204076Spjd		int len;
280204076Spjd
281204076Spjd		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
282204076Spjd		if ((size_t)len < sizeof(log))
283206697Spjd			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
284204076Spjd		if (error != -1 && (size_t)len < sizeof(log)) {
285204076Spjd			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
286204076Spjd			    strerror(error));
287204076Spjd		}
288204076Spjd		syslog(loglevel, "%s", log);
289204076Spjd		break;
290204076Spjd	    }
291204076Spjd	default:
292204076Spjd		assert(!"Invalid mode.");
293204076Spjd	}
294204076Spjd}
295204076Spjd
296204076Spjd/*
297204076Spjd * Regular logs.
298204076Spjd */
299204076Spjdvoid
300204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap)
301204076Spjd{
302204076Spjd
303219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
304217965Spjd
305204076Spjd	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
306204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
307204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
308204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
309204076Spjd	    loglevel == LOG_INFO);
310204076Spjd
311204076Spjd	pjdlogv_common(loglevel, 0, -1, fmt, ap);
312204076Spjd}
313204076Spjd
314204076Spjd/*
315204076Spjd * Regular logs.
316204076Spjd */
317204076Spjdvoid
318204076Spjdpjdlog(int loglevel, const char *fmt, ...)
319204076Spjd{
320204076Spjd	va_list ap;
321204076Spjd
322219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
323217965Spjd
324204076Spjd	va_start(ap, fmt);
325204076Spjd	pjdlogv(loglevel, fmt, ap);
326204076Spjd	va_end(ap);
327204076Spjd}
328204076Spjd
329204076Spjd/*
330204076Spjd * Debug logs.
331204076Spjd */
332204076Spjdvoid
333204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
334204076Spjd{
335204076Spjd
336219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
337217965Spjd
338204076Spjd	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
339204076Spjd}
340204076Spjd
341204076Spjd/*
342204076Spjd * Debug logs.
343204076Spjd */
344204076Spjdvoid
345204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...)
346204076Spjd{
347204076Spjd	va_list ap;
348204076Spjd
349219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
350217965Spjd
351204076Spjd	va_start(ap, fmt);
352204076Spjd	pjdlogv_debug(debuglevel, fmt, ap);
353204076Spjd	va_end(ap);
354204076Spjd}
355204076Spjd
356204076Spjd/*
357204076Spjd * Error logs with errno logging.
358204076Spjd */
359204076Spjdvoid
360204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap)
361204076Spjd{
362204076Spjd
363219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
364217965Spjd
365204076Spjd	pjdlogv_common(loglevel, 0, errno, fmt, ap);
366204076Spjd}
367204076Spjd
368204076Spjd/*
369204076Spjd * Error logs with errno logging.
370204076Spjd */
371204076Spjdvoid
372204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...)
373204076Spjd{
374204076Spjd	va_list ap;
375204076Spjd
376219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
377217965Spjd
378204076Spjd	va_start(ap, fmt);
379204076Spjd	pjdlogv_errno(loglevel, fmt, ap);
380204076Spjd	va_end(ap);
381204076Spjd}
382204076Spjd
383204076Spjd/*
384204076Spjd * Log error, errno and exit.
385204076Spjd */
386204076Spjdvoid
387204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap)
388204076Spjd{
389204076Spjd
390219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
391217965Spjd
392204076Spjd	pjdlogv_errno(LOG_ERR, fmt, ap);
393204076Spjd	exit(exitcode);
394210872Spjd	/* NOTREACHED */
395204076Spjd}
396204076Spjd
397204076Spjd/*
398204076Spjd * Log error, errno and exit.
399204076Spjd */
400204076Spjdvoid
401204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...)
402204076Spjd{
403204076Spjd	va_list ap;
404204076Spjd
405219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
406217965Spjd
407204076Spjd	va_start(ap, fmt);
408204076Spjd	pjdlogv_exit(exitcode, fmt, ap);
409204076Spjd	/* NOTREACHED */
410204076Spjd	va_end(ap);
411204076Spjd}
412204076Spjd
413204076Spjd/*
414204076Spjd * Log error and exit.
415204076Spjd */
416204076Spjdvoid
417204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
418204076Spjd{
419204076Spjd
420219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
421217965Spjd
422204076Spjd	pjdlogv(LOG_ERR, fmt, ap);
423204076Spjd	exit(exitcode);
424210872Spjd	/* NOTREACHED */
425204076Spjd}
426204076Spjd
427204076Spjd/*
428204076Spjd * Log error and exit.
429204076Spjd */
430204076Spjdvoid
431204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...)
432204076Spjd{
433204076Spjd	va_list ap;
434204076Spjd
435219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
436217965Spjd
437204076Spjd	va_start(ap, fmt);
438204076Spjd	pjdlogv_exitx(exitcode, fmt, ap);
439204076Spjd	/* NOTREACHED */
440204076Spjd	va_end(ap);
441204076Spjd}
442210875Spjd
443210875Spjd/*
444218132Spjd * Log failure message and exit.
445210875Spjd */
446210875Spjdvoid
447218132Spjdpjdlog_abort(const char *func, const char *file, int line,
448217966Spjd    const char *failedexpr, const char *fmt, ...)
449210875Spjd{
450217966Spjd	va_list ap;
451210875Spjd
452219369Spjd	assert(pjdlog_initialized == PJDLOG_INITIALIZED);
453217966Spjd
454217966Spjd	/*
455217966Spjd	 * When there is no message we pass __func__ as 'fmt'.
456217966Spjd	 * It would be cleaner to pass NULL or "", but gcc generates a warning
457217966Spjd	 * for both of those.
458217966Spjd	 */
459217966Spjd	if (fmt != func) {
460217966Spjd		va_start(ap, fmt);
461217966Spjd		pjdlogv_critical(fmt, ap);
462217966Spjd		va_end(ap);
463217966Spjd	}
464217966Spjd	if (failedexpr == NULL) {
465217966Spjd		if (func == NULL) {
466217966Spjd			pjdlog_critical("Aborted at file %s, line %d.", file,
467217966Spjd			    line);
468217966Spjd		} else {
469217966Spjd			pjdlog_critical("Aborted at function %s, file %s, line %d.",
470217966Spjd			    func, file, line);
471217966Spjd		}
472210875Spjd	} else {
473217966Spjd		if (func == NULL) {
474217966Spjd			pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
475217966Spjd			    failedexpr, file, line);
476217966Spjd		} else {
477217966Spjd			pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
478217966Spjd			    failedexpr, func, file, line);
479217966Spjd		}
480210875Spjd	}
481210875Spjd	abort();
482210875Spjd}
483