pjdlog.c revision 212052
1204076Spjd/*-
2204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation
3204076Spjd * All rights reserved.
4204076Spjd *
5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6204076Spjd * the FreeBSD Foundation.
7204076Spjd *
8204076Spjd * Redistribution and use in source and binary forms, with or without
9204076Spjd * modification, are permitted provided that the following conditions
10204076Spjd * are met:
11204076Spjd * 1. Redistributions of source code must retain the above copyright
12204076Spjd *    notice, this list of conditions and the following disclaimer.
13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
14204076Spjd *    notice, this list of conditions and the following disclaimer in the
15204076Spjd *    documentation and/or other materials provided with the distribution.
16204076Spjd *
17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27204076Spjd * SUCH DAMAGE.
28204076Spjd */
29204076Spjd
30204076Spjd#include <sys/cdefs.h>
31204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 212052 2010-08-31 12:05:13Z pjd $");
32204076Spjd
33204076Spjd#include <assert.h>
34204076Spjd#include <errno.h>
35204076Spjd#include <stdarg.h>
36204076Spjd#include <stdio.h>
37204076Spjd#include <stdlib.h>
38204076Spjd#include <string.h>
39204076Spjd#include <syslog.h>
40204076Spjd
41204076Spjd#include "pjdlog.h"
42204076Spjd
43204076Spjdstatic int pjdlog_mode = PJDLOG_MODE_STD;
44204076Spjdstatic int pjdlog_debug_level = 0;
45204076Spjdstatic char pjdlog_prefix[128];
46204076Spjd
47204076Spjd/*
48204076Spjd * Configure where the logs should go.
49204076Spjd * By default they are send to stdout/stderr, but after going into background
50204076Spjd * (eg. by calling daemon(3)) application is responsible for changing mode to
51204076Spjd * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
52204076Spjd */
53204076Spjdvoid
54204076Spjdpjdlog_mode_set(int mode)
55204076Spjd{
56204076Spjd
57204076Spjd	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
58204076Spjd
59204076Spjd	pjdlog_mode = mode;
60212052Spjd
61212052Spjd	if (mode == PJDLOG_MODE_SYSLOG)
62212052Spjd		openlog(NULL, LOG_PID, LOG_DAEMON);
63204076Spjd}
64204076Spjd
65204076Spjd/*
66204076Spjd * Return current mode.
67204076Spjd */
68204076Spjdint
69204076Spjdpjdlog_mode_get(void)
70204076Spjd{
71204076Spjd
72204076Spjd	return (pjdlog_mode);
73204076Spjd}
74204076Spjd
75204076Spjd/*
76204076Spjd * Set debug level. All the logs above the level specified here will be
77204076Spjd * ignored.
78204076Spjd */
79204076Spjdvoid
80204076Spjdpjdlog_debug_set(int level)
81204076Spjd{
82204076Spjd
83204076Spjd	assert(level >= 0);
84204076Spjd
85204076Spjd	pjdlog_debug_level = level;
86204076Spjd}
87204076Spjd
88204076Spjd/*
89204076Spjd * Return current debug level.
90204076Spjd */
91204076Spjdint
92204076Spjdpjdlog_debug_get(void)
93204076Spjd{
94204076Spjd
95204076Spjd	return (pjdlog_debug_level);
96204076Spjd}
97204076Spjd
98204076Spjd/*
99204076Spjd * Set prefix that will be used before each log.
100204076Spjd * Setting prefix to NULL will remove it.
101204076Spjd */
102204076Spjdvoid
103204076Spjdpjdlog_prefix_set(const char *fmt, ...)
104204076Spjd{
105204076Spjd	va_list ap;
106204076Spjd
107204076Spjd	va_start(ap, fmt);
108204076Spjd	pjdlog_prefix_setv(fmt, ap);
109204076Spjd	va_end(ap);
110204076Spjd}
111204076Spjd
112204076Spjd/*
113204076Spjd * Set prefix that will be used before each log.
114204076Spjd * Setting prefix to NULL will remove it.
115204076Spjd */
116204076Spjdvoid
117204076Spjdpjdlog_prefix_setv(const char *fmt, va_list ap)
118204076Spjd{
119204076Spjd
120204076Spjd	assert(fmt != NULL);
121204076Spjd
122204076Spjd	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
123204076Spjd}
124204076Spjd
125204076Spjd/*
126204076Spjd * Convert log level into string.
127204076Spjd */
128204076Spjdstatic const char *
129204076Spjdpjdlog_level_string(int loglevel)
130204076Spjd{
131204076Spjd
132204076Spjd	switch (loglevel) {
133204076Spjd	case LOG_EMERG:
134204076Spjd		return ("EMERG");
135204076Spjd	case LOG_ALERT:
136204076Spjd		return ("ALERT");
137204076Spjd	case LOG_CRIT:
138204076Spjd		return ("CRIT");
139204076Spjd	case LOG_ERR:
140204076Spjd		return ("ERROR");
141204076Spjd	case LOG_WARNING:
142204076Spjd		return ("WARNING");
143204076Spjd	case LOG_NOTICE:
144204076Spjd		return ("NOTICE");
145204076Spjd	case LOG_INFO:
146204076Spjd		return ("INFO");
147204076Spjd	case LOG_DEBUG:
148204076Spjd		return ("DEBUG");
149204076Spjd	}
150204076Spjd	assert(!"Invalid log level.");
151204076Spjd	abort();	/* XXX: gcc */
152204076Spjd}
153204076Spjd
154204076Spjd/*
155204076Spjd * Common log routine.
156204076Spjd */
157204076Spjdvoid
158204076Spjdpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
159204076Spjd{
160204076Spjd	va_list ap;
161204076Spjd
162204076Spjd	va_start(ap, fmt);
163204076Spjd	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
164204076Spjd	va_end(ap);
165204076Spjd}
166204076Spjd
167204076Spjd/*
168204076Spjd * Common log routine, which can handle regular log level as well as debug
169204076Spjd * level. We decide here where to send the logs (stdout/stderr or syslog).
170204076Spjd */
171204076Spjdvoid
172204076Spjdpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
173204076Spjd    va_list ap)
174204076Spjd{
175204076Spjd
176204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
177204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
178204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
179204076Spjd	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
180204076Spjd	assert(loglevel != LOG_DEBUG || debuglevel > 0);
181204076Spjd	assert(error >= -1);
182204076Spjd
183204076Spjd	/* Ignore debug above configured level. */
184204076Spjd	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
185204076Spjd		return;
186204076Spjd
187204076Spjd	switch (pjdlog_mode) {
188204076Spjd	case PJDLOG_MODE_STD:
189204076Spjd	    {
190204076Spjd		FILE *out;
191204076Spjd
192204076Spjd		/*
193204076Spjd		 * We send errors and warning to stderr and the rest to stdout.
194204076Spjd		 */
195204076Spjd		switch (loglevel) {
196204076Spjd		case LOG_EMERG:
197204076Spjd		case LOG_ALERT:
198204076Spjd		case LOG_CRIT:
199204076Spjd		case LOG_ERR:
200204076Spjd		case LOG_WARNING:
201204076Spjd			out = stderr;
202204076Spjd			break;
203204076Spjd		case LOG_NOTICE:
204204076Spjd		case LOG_INFO:
205204076Spjd		case LOG_DEBUG:
206204076Spjd			out = stdout;
207204076Spjd			break;
208204076Spjd		default:
209204076Spjd			assert(!"Invalid loglevel.");
210204076Spjd			abort();	/* XXX: gcc */
211204076Spjd		}
212204076Spjd
213204076Spjd		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
214204076Spjd		/* Attach debuglevel if this is debug log. */
215204076Spjd		if (loglevel == LOG_DEBUG)
216204076Spjd			fprintf(out, "[%d]", debuglevel);
217204076Spjd		fprintf(out, " ");
218204076Spjd		fprintf(out, "%s", pjdlog_prefix);
219204076Spjd		vfprintf(out, fmt, ap);
220204076Spjd		if (error != -1)
221204076Spjd			fprintf(out, ": %s.", strerror(error));
222204076Spjd		fprintf(out, "\n");
223211898Spjd		fflush(out);
224204076Spjd		break;
225204076Spjd	    }
226204076Spjd	case PJDLOG_MODE_SYSLOG:
227204076Spjd	    {
228204076Spjd		char log[1024];
229204076Spjd		int len;
230204076Spjd
231204076Spjd		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
232204076Spjd		if ((size_t)len < sizeof(log))
233206697Spjd			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
234204076Spjd		if (error != -1 && (size_t)len < sizeof(log)) {
235204076Spjd			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
236204076Spjd			    strerror(error));
237204076Spjd		}
238204076Spjd		syslog(loglevel, "%s", log);
239204076Spjd		break;
240204076Spjd	    }
241204076Spjd	default:
242204076Spjd		assert(!"Invalid mode.");
243204076Spjd	}
244204076Spjd}
245204076Spjd
246204076Spjd/*
247204076Spjd * Regular logs.
248204076Spjd */
249204076Spjdvoid
250204076Spjdpjdlogv(int loglevel, const char *fmt, va_list ap)
251204076Spjd{
252204076Spjd
253204076Spjd	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
254204076Spjd	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
255204076Spjd	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
256204076Spjd	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
257204076Spjd	    loglevel == LOG_INFO);
258204076Spjd
259204076Spjd	pjdlogv_common(loglevel, 0, -1, fmt, ap);
260204076Spjd}
261204076Spjd
262204076Spjd/*
263204076Spjd * Regular logs.
264204076Spjd */
265204076Spjdvoid
266204076Spjdpjdlog(int loglevel, const char *fmt, ...)
267204076Spjd{
268204076Spjd	va_list ap;
269204076Spjd
270204076Spjd	va_start(ap, fmt);
271204076Spjd	pjdlogv(loglevel, fmt, ap);
272204076Spjd	va_end(ap);
273204076Spjd}
274204076Spjd
275204076Spjd/*
276204076Spjd * Debug logs.
277204076Spjd */
278204076Spjdvoid
279204076Spjdpjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
280204076Spjd{
281204076Spjd
282204076Spjd	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
283204076Spjd}
284204076Spjd
285204076Spjd/*
286204076Spjd * Debug logs.
287204076Spjd */
288204076Spjdvoid
289204076Spjdpjdlog_debug(int debuglevel, const char *fmt, ...)
290204076Spjd{
291204076Spjd	va_list ap;
292204076Spjd
293204076Spjd	va_start(ap, fmt);
294204076Spjd	pjdlogv_debug(debuglevel, fmt, ap);
295204076Spjd	va_end(ap);
296204076Spjd}
297204076Spjd
298204076Spjd/*
299204076Spjd * Error logs with errno logging.
300204076Spjd */
301204076Spjdvoid
302204076Spjdpjdlogv_errno(int loglevel, const char *fmt, va_list ap)
303204076Spjd{
304204076Spjd
305204076Spjd	pjdlogv_common(loglevel, 0, errno, fmt, ap);
306204076Spjd}
307204076Spjd
308204076Spjd/*
309204076Spjd * Error logs with errno logging.
310204076Spjd */
311204076Spjdvoid
312204076Spjdpjdlog_errno(int loglevel, const char *fmt, ...)
313204076Spjd{
314204076Spjd	va_list ap;
315204076Spjd
316204076Spjd	va_start(ap, fmt);
317204076Spjd	pjdlogv_errno(loglevel, fmt, ap);
318204076Spjd	va_end(ap);
319204076Spjd}
320204076Spjd
321204076Spjd/*
322204076Spjd * Log error, errno and exit.
323204076Spjd */
324204076Spjdvoid
325204076Spjdpjdlogv_exit(int exitcode, const char *fmt, va_list ap)
326204076Spjd{
327204076Spjd
328204076Spjd	pjdlogv_errno(LOG_ERR, fmt, ap);
329204076Spjd	exit(exitcode);
330210872Spjd	/* NOTREACHED */
331204076Spjd}
332204076Spjd
333204076Spjd/*
334204076Spjd * Log error, errno and exit.
335204076Spjd */
336204076Spjdvoid
337204076Spjdpjdlog_exit(int exitcode, const char *fmt, ...)
338204076Spjd{
339204076Spjd	va_list ap;
340204076Spjd
341204076Spjd	va_start(ap, fmt);
342204076Spjd	pjdlogv_exit(exitcode, fmt, ap);
343204076Spjd	/* NOTREACHED */
344204076Spjd	va_end(ap);
345204076Spjd}
346204076Spjd
347204076Spjd/*
348204076Spjd * Log error and exit.
349204076Spjd */
350204076Spjdvoid
351204076Spjdpjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
352204076Spjd{
353204076Spjd
354204076Spjd	pjdlogv(LOG_ERR, fmt, ap);
355204076Spjd	exit(exitcode);
356210872Spjd	/* NOTREACHED */
357204076Spjd}
358204076Spjd
359204076Spjd/*
360204076Spjd * Log error and exit.
361204076Spjd */
362204076Spjdvoid
363204076Spjdpjdlog_exitx(int exitcode, const char *fmt, ...)
364204076Spjd{
365204076Spjd	va_list ap;
366204076Spjd
367204076Spjd	va_start(ap, fmt);
368204076Spjd	pjdlogv_exitx(exitcode, fmt, ap);
369204076Spjd	/* NOTREACHED */
370204076Spjd	va_end(ap);
371204076Spjd}
372210875Spjd
373210875Spjd/*
374210875Spjd * Log assertion and exit.
375210875Spjd */
376210875Spjdvoid
377210875Spjdpjdlog_verify(const char *func, const char *file, int line,
378210875Spjd    const char *failedexpr)
379210875Spjd{
380210875Spjd
381210875Spjd	if (func == NULL) {
382210875Spjd		pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
383210875Spjd		    failedexpr, file, line);
384210875Spjd	} else {
385210875Spjd		pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
386210875Spjd		    failedexpr, func, file, line);
387210875Spjd	}
388210875Spjd	abort();
389210875Spjd        /* NOTREACHED */
390210875Spjd}
391210875Spjd
392