pjdlog.c revision 217965
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 217965 2011-01-27 19:24:07Z 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;
46204076Spjdstatic int pjdlog_mode = PJDLOG_MODE_STD;
47204076Spjdstatic int pjdlog_debug_level = 0;
48204076Spjdstatic char pjdlog_prefix[128];
49204076Spjd
50217965Spjdvoid
51217965Spjdpjdlog_init(int mode)
52217965Spjd{
53217965Spjd
54217965Spjd	assert(!pjdlog_initialized);
55217965Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
56217965Spjd
57217965Spjd	if (mode == PJDLOG_MODE_SYSLOG)
58217965Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
59217965Spjd	pjdlog_mode = mode;
60217965Spjd
61217965Spjd	pjdlog_initialized = true;
62217965Spjd}
63217965Spjd
64217965Spjdvoid
65217965Spjdpjdlog_fini(void)
66217965Spjd{
67217965Spjd
68217965Spjd	assert(pjdlog_initialized);
69217965Spjd
70217965Spjd	if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
71217965Spjd		closelog();
72217965Spjd
73217965Spjd	pjdlog_initialized = false;
74217965Spjd}
75217965Spjd
76204076Spjd/*
77204076Spjd * Configure where the logs should go.
78204076Spjd * By default they are send to stdout/stderr, but after going into background
79204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to
80204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
81204076Spjd */
82204076Spjdvoid
83204076Spjdpjdlog_mode_set(int mode)
84204076Spjd{
85204076Spjd
86217965Spjd	assert(pjdlog_initialized);
87204076Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
88204076Spjd
89217965Spjd	if (pjdlog_mode == mode)
90217965Spjd		return;
91212052Spjd
92212052Spjd	if (mode == PJDLOG_MODE_SYSLOG)
93217962Spjd		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
94217965Spjd	else /* if (mode == PJDLOG_MODE_STD) */
95217965Spjd		closelog();
96217965Spjd
97217965Spjd	pjdlog_mode = mode;
98204076Spjd}
99204076Spjd
100204076Spjd/*
101204076Spjd * Return current mode.
102204076Spjd */
103204076Spjdint
104204076Spjdpjdlog_mode_get(void)
105204076Spjd{
106204076Spjd
107217965Spjd	assert(pjdlog_initialized);
108217965Spjd
109204076Spjd	return (pjdlog_mode);
110204076Spjd}
111204076Spjd
112204076Spjd/*
113204076Spjd * Set debug level. All the logs above the level specified here will be
114204076Spjd * ignored.
115204076Spjd */
116204076Spjdvoid
117204076Spjdpjdlog_debug_set(int level)
118204076Spjd{
119204076Spjd
120217965Spjd	assert(pjdlog_initialized);
121204076Spjd	assert(level >= 0);
122204076Spjd
123204076Spjd	pjdlog_debug_level = level;
124204076Spjd}
125204076Spjd
126204076Spjd/*
127204076Spjd * Return current debug level.
128204076Spjd */
129204076Spjdint
130204076Spjdpjdlog_debug_get(void)
131204076Spjd{
132204076Spjd
133217965Spjd	assert(pjdlog_initialized);
134217965Spjd
135204076Spjd	return (pjdlog_debug_level);
136204076Spjd}
137204076Spjd
138204076Spjd/*
139204076Spjd * Set prefix that will be used before each log.
140204076Spjd * Setting prefix to NULL will remove it.
141204076Spjd */
142204076Spjdvoid
143204076Spjdpjdlog_prefix_set(const char *fmt, ...)
144204076Spjd{
145204076Spjd	va_list ap;
146204076Spjd
147217965Spjd	assert(pjdlog_initialized);
148217965Spjd
149204076Spjd	va_start(ap, fmt);
150217731Spjd	pjdlogv_prefix_set(fmt, ap);
151204076Spjd	va_end(ap);
152204076Spjd}
153204076Spjd
154204076Spjd/*
155204076Spjd * Set prefix that will be used before each log.
156204076Spjd * Setting prefix to NULL will remove it.
157204076Spjd */
158204076Spjdvoid
159217731Spjdpjdlogv_prefix_set(const char *fmt, va_list ap)
160204076Spjd{
161204076Spjd
162217965Spjd	assert(pjdlog_initialized);
163204076Spjd	assert(fmt != NULL);
164204076Spjd
165204076Spjd	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
166204076Spjd}
167204076Spjd
168204076Spjd/*
169204076Spjd * Convert log level into string.
170204076Spjd */
171204076Spjdstatic const char *
172204076Spjdpjdlog_level_string(int loglevel)
173204076Spjd{
174204076Spjd
175204076Spjd	switch (loglevel) {
176204076Spjd	case LOG_EMERG:
177204076Spjd		return ("EMERG");
178204076Spjd	case LOG_ALERT:
179204076Spjd		return ("ALERT");
180204076Spjd	case LOG_CRIT:
181204076Spjd		return ("CRIT");
182204076Spjd	case LOG_ERR:
183204076Spjd		return ("ERROR");
184204076Spjd	case LOG_WARNING:
185204076Spjd		return ("WARNING");
186204076Spjd	case LOG_NOTICE:
187204076Spjd		return ("NOTICE");
188204076Spjd	case LOG_INFO:
189204076Spjd		return ("INFO");
190204076Spjd	case LOG_DEBUG:
191204076Spjd		return ("DEBUG");
192204076Spjd	}
193204076Spjd	assert(!"Invalid log level.");
194204076Spjd	abort();	/* XXX: gcc */
195204076Spjd}
196204076Spjd
197204076Spjd/*
198204076Spjd * Common log routine.
199204076Spjd */
200204076Spjdvoid
201204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
202204076Spjd{
203204076Spjd	va_list ap;
204204076Spjd
205217965Spjd	assert(pjdlog_initialized);
206217965Spjd
207204076Spjd	va_start(ap, fmt);
208204076Spjd	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
209204076Spjd	va_end(ap);
210204076Spjd}
211204076Spjd
212204076Spjd/*
213204076Spjd * Common log routine, which can handle regular log level as well as debug
214204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog).
215204076Spjd */
216204076Spjdvoid
217204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
218204076Spjd    va_list ap)
219204076Spjd{
220204076Spjd
221217965Spjd	assert(pjdlog_initialized);
222204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
223204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
224204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
225204076Spjd	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
226204076Spjd	assert(loglevel != LOG_DEBUG || debuglevel > 0);
227204076Spjd	assert(error >= -1);
228204076Spjd
229204076Spjd	/* Ignore debug above configured level. */
230204076Spjd	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
231204076Spjd		return;
232204076Spjd
233204076Spjd	switch (pjdlog_mode) {
234204076Spjd	case PJDLOG_MODE_STD:
235204076Spjd	    {
236204076Spjd		FILE *out;
237204076Spjd
238204076Spjd		/*
239204076Spjd		 * We send errors and warning to stderr and the rest to stdout.
240204076Spjd		 */
241204076Spjd		switch (loglevel) {
242204076Spjd		case LOG_EMERG:
243204076Spjd		case LOG_ALERT:
244204076Spjd		case LOG_CRIT:
245204076Spjd		case LOG_ERR:
246204076Spjd		case LOG_WARNING:
247204076Spjd			out = stderr;
248204076Spjd			break;
249204076Spjd		case LOG_NOTICE:
250204076Spjd		case LOG_INFO:
251204076Spjd		case LOG_DEBUG:
252204076Spjd			out = stdout;
253204076Spjd			break;
254204076Spjd		default:
255204076Spjd			assert(!"Invalid loglevel.");
256204076Spjd			abort();	/* XXX: gcc */
257204076Spjd		}
258204076Spjd
259204076Spjd		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
260204076Spjd		/* Attach debuglevel if this is debug log. */
261204076Spjd		if (loglevel == LOG_DEBUG)
262204076Spjd			fprintf(out, "[%d]", debuglevel);
263213939Spjd		fprintf(out, " %s", pjdlog_prefix);
264204076Spjd		vfprintf(out, fmt, ap);
265204076Spjd		if (error != -1)
266204076Spjd			fprintf(out, ": %s.", strerror(error));
267204076Spjd		fprintf(out, "\n");
268211898Spjd		fflush(out);
269204076Spjd		break;
270204076Spjd	    }
271204076Spjd	case PJDLOG_MODE_SYSLOG:
272204076Spjd	    {
273204076Spjd		char log[1024];
274204076Spjd		int len;
275204076Spjd
276204076Spjd		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
277204076Spjd		if ((size_t)len < sizeof(log))
278206697Spjd			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
279204076Spjd		if (error != -1 && (size_t)len < sizeof(log)) {
280204076Spjd			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
281204076Spjd			    strerror(error));
282204076Spjd		}
283204076Spjd		syslog(loglevel, "%s", log);
284204076Spjd		break;
285204076Spjd	    }
286204076Spjd	default:
287204076Spjd		assert(!"Invalid mode.");
288204076Spjd	}
289204076Spjd}
290204076Spjd
291204076Spjd/*
292204076Spjd * Regular logs.
293204076Spjd */
294204076Spjdvoid
295204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap)
296204076Spjd{
297204076Spjd
298217965Spjd	assert(pjdlog_initialized);
299217965Spjd
300204076Spjd	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
301204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
302204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
303204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
304204076Spjd	    loglevel == LOG_INFO);
305204076Spjd
306204076Spjd	pjdlogv_common(loglevel, 0, -1, fmt, ap);
307204076Spjd}
308204076Spjd
309204076Spjd/*
310204076Spjd * Regular logs.
311204076Spjd */
312204076Spjdvoid
313204076Spjdpjdlog(int loglevel, const char *fmt, ...)
314204076Spjd{
315204076Spjd	va_list ap;
316204076Spjd
317217965Spjd	assert(pjdlog_initialized);
318217965Spjd
319204076Spjd	va_start(ap, fmt);
320204076Spjd	pjdlogv(loglevel, fmt, ap);
321204076Spjd	va_end(ap);
322204076Spjd}
323204076Spjd
324204076Spjd/*
325204076Spjd * Debug logs.
326204076Spjd */
327204076Spjdvoid
328204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
329204076Spjd{
330204076Spjd
331217965Spjd	assert(pjdlog_initialized);
332217965Spjd
333204076Spjd	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
334204076Spjd}
335204076Spjd
336204076Spjd/*
337204076Spjd * Debug logs.
338204076Spjd */
339204076Spjdvoid
340204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...)
341204076Spjd{
342204076Spjd	va_list ap;
343204076Spjd
344217965Spjd	assert(pjdlog_initialized);
345217965Spjd
346204076Spjd	va_start(ap, fmt);
347204076Spjd	pjdlogv_debug(debuglevel, fmt, ap);
348204076Spjd	va_end(ap);
349204076Spjd}
350204076Spjd
351204076Spjd/*
352204076Spjd * Error logs with errno logging.
353204076Spjd */
354204076Spjdvoid
355204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap)
356204076Spjd{
357204076Spjd
358217965Spjd	assert(pjdlog_initialized);
359217965Spjd
360204076Spjd	pjdlogv_common(loglevel, 0, errno, fmt, ap);
361204076Spjd}
362204076Spjd
363204076Spjd/*
364204076Spjd * Error logs with errno logging.
365204076Spjd */
366204076Spjdvoid
367204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...)
368204076Spjd{
369204076Spjd	va_list ap;
370204076Spjd
371217965Spjd	assert(pjdlog_initialized);
372217965Spjd
373204076Spjd	va_start(ap, fmt);
374204076Spjd	pjdlogv_errno(loglevel, fmt, ap);
375204076Spjd	va_end(ap);
376204076Spjd}
377204076Spjd
378204076Spjd/*
379204076Spjd * Log error, errno and exit.
380204076Spjd */
381204076Spjdvoid
382204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap)
383204076Spjd{
384204076Spjd
385217965Spjd	assert(pjdlog_initialized);
386217965Spjd
387204076Spjd	pjdlogv_errno(LOG_ERR, fmt, ap);
388204076Spjd	exit(exitcode);
389210872Spjd	/* NOTREACHED */
390204076Spjd}
391204076Spjd
392204076Spjd/*
393204076Spjd * Log error, errno and exit.
394204076Spjd */
395204076Spjdvoid
396204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...)
397204076Spjd{
398204076Spjd	va_list ap;
399204076Spjd
400217965Spjd	assert(pjdlog_initialized);
401217965Spjd
402204076Spjd	va_start(ap, fmt);
403204076Spjd	pjdlogv_exit(exitcode, fmt, ap);
404204076Spjd	/* NOTREACHED */
405204076Spjd	va_end(ap);
406204076Spjd}
407204076Spjd
408204076Spjd/*
409204076Spjd * Log error and exit.
410204076Spjd */
411204076Spjdvoid
412204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
413204076Spjd{
414204076Spjd
415217965Spjd	assert(pjdlog_initialized);
416217965Spjd
417204076Spjd	pjdlogv(LOG_ERR, fmt, ap);
418204076Spjd	exit(exitcode);
419210872Spjd	/* NOTREACHED */
420204076Spjd}
421204076Spjd
422204076Spjd/*
423204076Spjd * Log error and exit.
424204076Spjd */
425204076Spjdvoid
426204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...)
427204076Spjd{
428204076Spjd	va_list ap;
429204076Spjd
430217965Spjd	assert(pjdlog_initialized);
431217965Spjd
432204076Spjd	va_start(ap, fmt);
433204076Spjd	pjdlogv_exitx(exitcode, fmt, ap);
434204076Spjd	/* NOTREACHED */
435204076Spjd	va_end(ap);
436204076Spjd}
437210875Spjd
438210875Spjd/*
439210875Spjd * Log assertion and exit.
440210875Spjd */
441210875Spjdvoid
442210875Spjdpjdlog_verify(const char *func, const char *file, int line,
443210875Spjd    const char *failedexpr)
444210875Spjd{
445210875Spjd
446210875Spjd	if (func == NULL) {
447210875Spjd		pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
448210875Spjd		    failedexpr, file, line);
449210875Spjd	} else {
450210875Spjd		pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
451210875Spjd		    failedexpr, func, file, line);
452210875Spjd	}
453210875Spjd	abort();
454210875Spjd}
455