pjdlog.c revision 217962
1219820Sjeff/*-
2219820Sjeff * Copyright (c) 2009-2011 The FreeBSD Foundation
3219820Sjeff * All rights reserved.
4219820Sjeff *
5328653Shselasky * This software was developed by Pawel Jakub Dawidek under sponsorship from
6219820Sjeff * the FreeBSD Foundation.
7219820Sjeff *
8219820Sjeff * Redistribution and use in source and binary forms, with or without
9219820Sjeff * modification, are permitted provided that the following conditions
10219820Sjeff * are met:
11219820Sjeff * 1. Redistributions of source code must retain the above copyright
12219820Sjeff *    notice, this list of conditions and the following disclaimer.
13219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright
14219820Sjeff *    notice, this list of conditions and the following disclaimer in the
15219820Sjeff *    documentation and/or other materials provided with the distribution.
16219820Sjeff *
17219820Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18219820Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19219820Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20219820Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21219820Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22219820Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23219820Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24219820Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25219820Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26219820Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27219820Sjeff * SUCH DAMAGE.
28289644Shselasky */
29289644Shselasky
30219820Sjeff#include <sys/cdefs.h>
31219820Sjeff__FBSDID("$FreeBSD: head/sbin/hastd/pjdlog.c 217962 2011-01-27 19:15:25Z pjd $");
32219820Sjeff
33219820Sjeff#include <assert.h>
34280764Shselasky#include <errno.h>
35280764Shselasky#include <stdarg.h>
36219820Sjeff#include <stdio.h>
37219820Sjeff#include <stdlib.h>
38219820Sjeff#include <string.h>
39219820Sjeff#include <syslog.h>
40219820Sjeff
41219820Sjeff#include "pjdlog.h"
42219820Sjeff
43219820Sjeffstatic int pjdlog_mode = PJDLOG_MODE_STD;
44328653Shselaskystatic int pjdlog_debug_level = 0;
45329966Shselaskystatic char pjdlog_prefix[128];
46219820Sjeff
47219820Sjeff/*
48219820Sjeff * Configure where the logs should go.
49219820Sjeff * By default they are send to stdout/stderr, but after going into background
50219820Sjeff * (eg. by calling daemon(3)) application is responsible for changing mode to
51219820Sjeff * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
52219820Sjeff */
53219820Sjeffvoid
54219820Sjeffpjdlog_mode_set(int mode)
55219820Sjeff{
56219820Sjeff
57328653Shselasky	assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
58219820Sjeff
59219820Sjeff	pjdlog_mode = mode;
60219820Sjeff
61328653Shselasky	if (mode == PJDLOG_MODE_SYSLOG)
62219820Sjeff		openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
63219820Sjeff}
64219820Sjeff
65219820Sjeff/*
66219820Sjeff * Return current mode.
67219820Sjeff */
68219820Sjeffint
69219820Sjeffpjdlog_mode_get(void)
70219820Sjeff{
71328653Shselasky
72328653Shselasky	return (pjdlog_mode);
73328653Shselasky}
74328653Shselasky
75328653Shselasky/*
76328653Shselasky * Set debug level. All the logs above the level specified here will be
77328653Shselasky * ignored.
78328653Shselasky */
79328653Shselaskyvoid
80328653Shselaskypjdlog_debug_set(int level)
81328653Shselasky{
82219820Sjeff
83219820Sjeff	assert(level >= 0);
84219820Sjeff
85331756Semaste	pjdlog_debug_level = level;
86219820Sjeff}
87219820Sjeff
88219820Sjeff/*
89219820Sjeff * Return current debug level.
90219820Sjeff */
91219820Sjeffint
92251617Sjhbpjdlog_debug_get(void)
93328653Shselasky{
94328653Shselasky
95328653Shselasky	return (pjdlog_debug_level);
96328653Shselasky}
97328653Shselasky
98328653Shselasky/*
99328653Shselasky * Set prefix that will be used before each log.
100328653Shselasky * Setting prefix to NULL will remove it.
101328653Shselasky */
102328653Shselaskyvoid
103328653Shselaskypjdlog_prefix_set(const char *fmt, ...)
104328653Shselasky{
105328653Shselasky	va_list ap;
106328653Shselasky
107328653Shselasky	va_start(ap, fmt);
108219820Sjeff	pjdlogv_prefix_set(fmt, ap);
109219820Sjeff	va_end(ap);
110219820Sjeff}
111219820Sjeff
112219820Sjeff/*
113219820Sjeff * Set prefix that will be used before each log.
114219820Sjeff * Setting prefix to NULL will remove it.
115219820Sjeff */
116219820Sjeffvoid
117219820Sjeffpjdlogv_prefix_set(const char *fmt, va_list ap)
118219820Sjeff{
119219820Sjeff
120219820Sjeff	assert(fmt != NULL);
121219820Sjeff
122219820Sjeff	vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
123219820Sjeff}
124219820Sjeff
125219820Sjeff/*
126219820Sjeff * Convert log level into string.
127219820Sjeff */
128219820Sjeffstatic const char *
129219820Sjeffpjdlog_level_string(int loglevel)
130219820Sjeff{
131219820Sjeff
132219820Sjeff	switch (loglevel) {
133219820Sjeff	case LOG_EMERG:
134219820Sjeff		return ("EMERG");
135219820Sjeff	case LOG_ALERT:
136328653Shselasky		return ("ALERT");
137219820Sjeff	case LOG_CRIT:
138219820Sjeff		return ("CRIT");
139219820Sjeff	case LOG_ERR:
140219820Sjeff		return ("ERROR");
141270710Shselasky	case LOG_WARNING:
142270710Shselasky		return ("WARNING");
143331756Semaste	case LOG_NOTICE:
144270710Shselasky		return ("NOTICE");
145270710Shselasky	case LOG_INFO:
146270710Shselasky		return ("INFO");
147219820Sjeff	case LOG_DEBUG:
148219820Sjeff		return ("DEBUG");
149219820Sjeff	}
150219820Sjeff	assert(!"Invalid log level.");
151219820Sjeff	abort();	/* XXX: gcc */
152219820Sjeff}
153219820Sjeff
154219820Sjeff/*
155219820Sjeff * Common log routine.
156219820Sjeff */
157219820Sjeffvoid
158219820Sjeffpjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
159219820Sjeff{
160219820Sjeff	va_list ap;
161219820Sjeff
162219820Sjeff	va_start(ap, fmt);
163219820Sjeff	pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
164219820Sjeff	va_end(ap);
165219820Sjeff}
166219820Sjeff
167219820Sjeff/*
168219820Sjeff * Common log routine, which can handle regular log level as well as debug
169219820Sjeff * level. We decide here where to send the logs (stdout/stderr or syslog).
170219820Sjeff */
171219820Sjeffvoid
172219820Sjeffpjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
173219820Sjeff    va_list ap)
174328653Shselasky{
175328653Shselasky
176219820Sjeff	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
177219820Sjeff	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
178219820Sjeff	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
179219820Sjeff	    loglevel == LOG_INFO || loglevel == LOG_DEBUG);
180219820Sjeff	assert(loglevel != LOG_DEBUG || debuglevel > 0);
181311803Shselasky	assert(error >= -1);
182311803Shselasky
183311803Shselasky	/* Ignore debug above configured level. */
184311803Shselasky	if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
185311803Shselasky		return;
186311803Shselasky
187311803Shselasky	switch (pjdlog_mode) {
188311803Shselasky	case PJDLOG_MODE_STD:
189311803Shselasky	    {
190311803Shselasky		FILE *out;
191311803Shselasky
192311803Shselasky		/*
193311803Shselasky		 * We send errors and warning to stderr and the rest to stdout.
194311803Shselasky		 */
195311803Shselasky		switch (loglevel) {
196311803Shselasky		case LOG_EMERG:
197311803Shselasky		case LOG_ALERT:
198219820Sjeff		case LOG_CRIT:
199311803Shselasky		case LOG_ERR:
200311803Shselasky		case LOG_WARNING:
201311803Shselasky			out = stderr;
202311803Shselasky			break;
203311803Shselasky		case LOG_NOTICE:
204311803Shselasky		case LOG_INFO:
205311803Shselasky		case LOG_DEBUG:
206311803Shselasky			out = stdout;
207311803Shselasky			break;
208311803Shselasky		default:
209311803Shselasky			assert(!"Invalid loglevel.");
210311803Shselasky			abort();	/* XXX: gcc */
211311803Shselasky		}
212311803Shselasky
213311803Shselasky		fprintf(out, "[%s]", pjdlog_level_string(loglevel));
214311803Shselasky		/* Attach debuglevel if this is debug log. */
215219820Sjeff		if (loglevel == LOG_DEBUG)
216219820Sjeff			fprintf(out, "[%d]", debuglevel);
217219820Sjeff		fprintf(out, " %s", pjdlog_prefix);
218219820Sjeff		vfprintf(out, fmt, ap);
219219820Sjeff		if (error != -1)
220219820Sjeff			fprintf(out, ": %s.", strerror(error));
221219820Sjeff		fprintf(out, "\n");
222219820Sjeff		fflush(out);
223219820Sjeff		break;
224219820Sjeff	    }
225219820Sjeff	case PJDLOG_MODE_SYSLOG:
226219820Sjeff	    {
227219820Sjeff		char log[1024];
228270710Shselasky		int len;
229270710Shselasky
230270710Shselasky		len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
231270710Shselasky		if ((size_t)len < sizeof(log))
232270710Shselasky			len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
233270710Shselasky		if (error != -1 && (size_t)len < sizeof(log)) {
234270710Shselasky			(void)snprintf(log + len, sizeof(log) - len, ": %s.",
235270710Shselasky			    strerror(error));
236270710Shselasky		}
237270710Shselasky		syslog(loglevel, "%s", log);
238270710Shselasky		break;
239270710Shselasky	    }
240270710Shselasky	default:
241270710Shselasky		assert(!"Invalid mode.");
242270710Shselasky	}
243328653Shselasky}
244328653Shselasky
245328653Shselasky/*
246328653Shselasky * Regular logs.
247328653Shselasky */
248219820Sjeffvoid
249219820Sjeffpjdlogv(int loglevel, const char *fmt, va_list ap)
250328653Shselasky{
251328653Shselasky
252219820Sjeff	/* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
253219820Sjeff	assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
254219820Sjeff	    loglevel == LOG_CRIT || loglevel == LOG_ERR ||
255219820Sjeff	    loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
256219820Sjeff	    loglevel == LOG_INFO);
257219820Sjeff
258219820Sjeff	pjdlogv_common(loglevel, 0, -1, fmt, ap);
259219820Sjeff}
260219820Sjeff
261219820Sjeff/*
262219820Sjeff * Regular logs.
263219820Sjeff */
264219820Sjeffvoid
265219820Sjeffpjdlog(int loglevel, const char *fmt, ...)
266219820Sjeff{
267219820Sjeff	va_list ap;
268219820Sjeff
269219820Sjeff	va_start(ap, fmt);
270219820Sjeff	pjdlogv(loglevel, fmt, ap);
271219820Sjeff	va_end(ap);
272219820Sjeff}
273331756Semaste
274270710Shselasky/*
275270710Shselasky * Debug logs.
276328653Shselasky */
277328653Shselaskyvoid
278270710Shselaskypjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
279270710Shselasky{
280328653Shselasky
281328653Shselasky	pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
282328653Shselasky}
283328653Shselasky
284328653Shselasky/*
285328653Shselasky * Debug logs.
286328653Shselasky */
287329967Shselaskyvoid
288329967Shselaskypjdlog_debug(int debuglevel, const char *fmt, ...)
289329967Shselasky{
290329967Shselasky	va_list ap;
291329967Shselasky
292329967Shselasky	va_start(ap, fmt);
293329967Shselasky	pjdlogv_debug(debuglevel, fmt, ap);
294329967Shselasky	va_end(ap);
295329967Shselasky}
296329967Shselasky
297329967Shselasky/*
298329967Shselasky * Error logs with errno logging.
299329967Shselasky */
300329967Shselaskyvoid
301328653Shselaskypjdlogv_errno(int loglevel, const char *fmt, va_list ap)
302328653Shselasky{
303328653Shselasky
304328653Shselasky	pjdlogv_common(loglevel, 0, errno, fmt, ap);
305328653Shselasky}
306328653Shselasky
307328653Shselasky/*
308328653Shselasky * Error logs with errno logging.
309328653Shselasky */
310328653Shselaskyvoid
311328653Shselaskypjdlog_errno(int loglevel, const char *fmt, ...)
312328653Shselasky{
313328653Shselasky	va_list ap;
314328653Shselasky
315328653Shselasky	va_start(ap, fmt);
316328653Shselasky	pjdlogv_errno(loglevel, fmt, ap);
317328653Shselasky	va_end(ap);
318328653Shselasky}
319328653Shselasky
320328653Shselasky/*
321328653Shselasky * Log error, errno and exit.
322270710Shselasky */
323void
324pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
325{
326
327	pjdlogv_errno(LOG_ERR, fmt, ap);
328	exit(exitcode);
329	/* NOTREACHED */
330}
331
332/*
333 * Log error, errno and exit.
334 */
335void
336pjdlog_exit(int exitcode, const char *fmt, ...)
337{
338	va_list ap;
339
340	va_start(ap, fmt);
341	pjdlogv_exit(exitcode, fmt, ap);
342	/* NOTREACHED */
343	va_end(ap);
344}
345
346/*
347 * Log error and exit.
348 */
349void
350pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
351{
352
353	pjdlogv(LOG_ERR, fmt, ap);
354	exit(exitcode);
355	/* NOTREACHED */
356}
357
358/*
359 * Log error and exit.
360 */
361void
362pjdlog_exitx(int exitcode, const char *fmt, ...)
363{
364	va_list ap;
365
366	va_start(ap, fmt);
367	pjdlogv_exitx(exitcode, fmt, ap);
368	/* NOTREACHED */
369	va_end(ap);
370}
371
372/*
373 * Log assertion and exit.
374 */
375void
376pjdlog_verify(const char *func, const char *file, int line,
377    const char *failedexpr)
378{
379
380	if (func == NULL) {
381		pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
382		    failedexpr, file, line);
383	} else {
384		pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
385		    failedexpr, func, file, line);
386	}
387	abort();
388}
389