1aa772005SRobert Watson /*-
2aa772005SRobert Watson * Copyright (c) 2009-2010 The FreeBSD Foundation
3aa772005SRobert Watson * Copyright (c) 2011 Pawel Jakub Dawidek <pjd@FreeBSD.org>
4aa772005SRobert Watson * All rights reserved.
5aa772005SRobert Watson *
6aa772005SRobert Watson * This software was developed by Pawel Jakub Dawidek under sponsorship from
7aa772005SRobert Watson * the FreeBSD Foundation.
8aa772005SRobert Watson *
9aa772005SRobert Watson * Redistribution and use in source and binary forms, with or without
10aa772005SRobert Watson * modification, are permitted provided that the following conditions
11aa772005SRobert Watson * are met:
12aa772005SRobert Watson * 1. Redistributions of source code must retain the above copyright
13aa772005SRobert Watson * notice, this list of conditions and the following disclaimer.
14aa772005SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright
15aa772005SRobert Watson * notice, this list of conditions and the following disclaimer in the
16aa772005SRobert Watson * documentation and/or other materials provided with the distribution.
17aa772005SRobert Watson *
18aa772005SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19aa772005SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20aa772005SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21aa772005SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
22aa772005SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23aa772005SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24aa772005SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25aa772005SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26aa772005SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27aa772005SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28aa772005SRobert Watson * SUCH DAMAGE.
29aa772005SRobert Watson */
30aa772005SRobert Watson
31aa772005SRobert Watson #include <sys/types.h>
32aa772005SRobert Watson #include <sys/socket.h>
33aa772005SRobert Watson #include <netinet/in.h>
34aa772005SRobert Watson #include <arpa/inet.h>
35aa772005SRobert Watson
36aa772005SRobert Watson #include <assert.h>
37aa772005SRobert Watson #include <errno.h>
38aa772005SRobert Watson #include <stdarg.h>
39aa772005SRobert Watson #include <stdint.h>
40aa772005SRobert Watson #include <stdio.h>
41aa772005SRobert Watson #include <stdlib.h>
42aa772005SRobert Watson #include <string.h>
43aa772005SRobert Watson #include <syslog.h>
44aa772005SRobert Watson #include <unistd.h>
45aa772005SRobert Watson
46*5e386598SRobert Watson #ifdef __FreeBSD__
47*5e386598SRobert Watson #include <libutil.h>
48*5e386598SRobert Watson #include <printf.h>
49*5e386598SRobert Watson #endif
50*5e386598SRobert Watson
51aa772005SRobert Watson #include "pjdlog.h"
52aa772005SRobert Watson
53aa772005SRobert Watson #define PJDLOG_NEVER_INITIALIZED 0
54aa772005SRobert Watson #define PJDLOG_NOT_INITIALIZED 1
55aa772005SRobert Watson #define PJDLOG_INITIALIZED 2
56aa772005SRobert Watson
57aa772005SRobert Watson static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED;
58aa772005SRobert Watson static int pjdlog_mode, pjdlog_debug_level;
59aa772005SRobert Watson static char pjdlog_prefix[128];
60aa772005SRobert Watson
61aa772005SRobert Watson #ifdef __FreeBSD__
62aa772005SRobert Watson static int
pjdlog_printf_arginfo_humanized_number(const struct printf_info * pi __unused,size_t n,int * argt)63aa772005SRobert Watson pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused,
64aa772005SRobert Watson size_t n, int *argt)
65aa772005SRobert Watson {
66aa772005SRobert Watson
67aa772005SRobert Watson assert(n >= 1);
68aa772005SRobert Watson argt[0] = PA_INT | PA_FLAG_INTMAX;
69aa772005SRobert Watson return (1);
70aa772005SRobert Watson }
71aa772005SRobert Watson
72aa772005SRobert Watson static int
pjdlog_printf_render_humanized_number(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)73aa772005SRobert Watson pjdlog_printf_render_humanized_number(struct __printf_io *io,
74aa772005SRobert Watson const struct printf_info *pi, const void * const *arg)
75aa772005SRobert Watson {
76aa772005SRobert Watson char buf[5];
77aa772005SRobert Watson intmax_t num;
78aa772005SRobert Watson int ret;
79aa772005SRobert Watson
80aa772005SRobert Watson num = *(const intmax_t *)arg[0];
81aa772005SRobert Watson humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE,
82aa772005SRobert Watson HN_NOSPACE | HN_DECIMAL);
83aa772005SRobert Watson ret = __printf_out(io, pi, buf, strlen(buf));
84aa772005SRobert Watson __printf_flush(io);
85aa772005SRobert Watson return (ret);
86aa772005SRobert Watson }
87aa772005SRobert Watson
88aa772005SRobert Watson static int
pjdlog_printf_arginfo_sockaddr(const struct printf_info * pi __unused,size_t n,int * argt)89aa772005SRobert Watson pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused,
90aa772005SRobert Watson size_t n, int *argt)
91aa772005SRobert Watson {
92aa772005SRobert Watson
93aa772005SRobert Watson assert(n >= 1);
94aa772005SRobert Watson argt[0] = PA_POINTER;
95aa772005SRobert Watson return (1);
96aa772005SRobert Watson }
97aa772005SRobert Watson
98aa772005SRobert Watson static int
pjdlog_printf_render_sockaddr(struct __printf_io * io,const struct printf_info * pi,const void * const * arg)99aa772005SRobert Watson pjdlog_printf_render_sockaddr(struct __printf_io *io,
100aa772005SRobert Watson const struct printf_info *pi, const void * const *arg)
101aa772005SRobert Watson {
102aa772005SRobert Watson const struct sockaddr_storage *ss;
103aa772005SRobert Watson char buf[64];
104aa772005SRobert Watson int ret;
105aa772005SRobert Watson
106aa772005SRobert Watson ss = *(const struct sockaddr_storage * const *)arg[0];
107aa772005SRobert Watson switch (ss->ss_family) {
108aa772005SRobert Watson case AF_INET:
109aa772005SRobert Watson {
110aa772005SRobert Watson char addr[INET_ADDRSTRLEN];
111aa772005SRobert Watson const struct sockaddr_in *sin;
112aa772005SRobert Watson unsigned int port;
113aa772005SRobert Watson
114aa772005SRobert Watson sin = (const struct sockaddr_in *)ss;
115aa772005SRobert Watson port = ntohs(sin->sin_port);
116aa772005SRobert Watson if (inet_ntop(ss->ss_family, &sin->sin_addr, addr,
117aa772005SRobert Watson sizeof(addr)) == NULL) {
118aa772005SRobert Watson PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.",
119aa772005SRobert Watson strerror(errno));
120aa772005SRobert Watson }
121aa772005SRobert Watson snprintf(buf, sizeof(buf), "%s:%u", addr, port);
122aa772005SRobert Watson break;
123aa772005SRobert Watson }
124aa772005SRobert Watson case AF_INET6:
125aa772005SRobert Watson {
126aa772005SRobert Watson char addr[INET6_ADDRSTRLEN];
127aa772005SRobert Watson const struct sockaddr_in6 *sin;
128aa772005SRobert Watson unsigned int port;
129aa772005SRobert Watson
130aa772005SRobert Watson sin = (const struct sockaddr_in6 *)ss;
131aa772005SRobert Watson port = ntohs(sin->sin6_port);
132aa772005SRobert Watson if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr,
133aa772005SRobert Watson sizeof(addr)) == NULL) {
134aa772005SRobert Watson PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.",
135aa772005SRobert Watson strerror(errno));
136aa772005SRobert Watson }
137aa772005SRobert Watson snprintf(buf, sizeof(buf), "[%s]:%u", addr, port);
138aa772005SRobert Watson break;
139aa772005SRobert Watson }
140aa772005SRobert Watson default:
141aa772005SRobert Watson snprintf(buf, sizeof(buf), "[unsupported family %hhu]",
142aa772005SRobert Watson ss->ss_family);
143aa772005SRobert Watson break;
144aa772005SRobert Watson }
145aa772005SRobert Watson ret = __printf_out(io, pi, buf, strlen(buf));
146aa772005SRobert Watson __printf_flush(io);
147aa772005SRobert Watson return (ret);
148aa772005SRobert Watson }
149aa772005SRobert Watson #endif /* __FreeBSD__ */
150aa772005SRobert Watson
151aa772005SRobert Watson void
pjdlog_init(int mode)152aa772005SRobert Watson pjdlog_init(int mode)
153aa772005SRobert Watson {
154aa772005SRobert Watson int saved_errno;
155aa772005SRobert Watson
156aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED ||
157aa772005SRobert Watson pjdlog_initialized == PJDLOG_NOT_INITIALIZED);
158aa772005SRobert Watson assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
159aa772005SRobert Watson
160aa772005SRobert Watson saved_errno = errno;
161aa772005SRobert Watson
162aa772005SRobert Watson if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) {
163aa772005SRobert Watson #ifdef __FreeBSD__
164aa772005SRobert Watson __use_xprintf = 1;
165aa772005SRobert Watson register_printf_render_std("T");
166aa772005SRobert Watson register_printf_render('N',
167aa772005SRobert Watson pjdlog_printf_render_humanized_number,
168aa772005SRobert Watson pjdlog_printf_arginfo_humanized_number);
169aa772005SRobert Watson register_printf_render('S',
170aa772005SRobert Watson pjdlog_printf_render_sockaddr,
171aa772005SRobert Watson pjdlog_printf_arginfo_sockaddr);
172aa772005SRobert Watson #endif
173aa772005SRobert Watson }
174aa772005SRobert Watson
175aa772005SRobert Watson if (mode == PJDLOG_MODE_SYSLOG)
176aa772005SRobert Watson openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
177aa772005SRobert Watson pjdlog_mode = mode;
178aa772005SRobert Watson pjdlog_debug_level = 0;
179aa772005SRobert Watson bzero(pjdlog_prefix, sizeof(pjdlog_prefix));
180aa772005SRobert Watson
181aa772005SRobert Watson pjdlog_initialized = PJDLOG_INITIALIZED;
182aa772005SRobert Watson
183aa772005SRobert Watson errno = saved_errno;
184aa772005SRobert Watson }
185aa772005SRobert Watson
186aa772005SRobert Watson void
pjdlog_fini(void)187aa772005SRobert Watson pjdlog_fini(void)
188aa772005SRobert Watson {
189aa772005SRobert Watson int saved_errno;
190aa772005SRobert Watson
191aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
192aa772005SRobert Watson
193aa772005SRobert Watson saved_errno = errno;
194aa772005SRobert Watson
195aa772005SRobert Watson if (pjdlog_mode == PJDLOG_MODE_SYSLOG)
196aa772005SRobert Watson closelog();
197aa772005SRobert Watson
198aa772005SRobert Watson pjdlog_initialized = PJDLOG_NOT_INITIALIZED;
199aa772005SRobert Watson
200aa772005SRobert Watson errno = saved_errno;
201aa772005SRobert Watson }
202aa772005SRobert Watson
203aa772005SRobert Watson /*
204aa772005SRobert Watson * Configure where the logs should go.
205aa772005SRobert Watson * By default they are send to stdout/stderr, but after going into background
206aa772005SRobert Watson * (eg. by calling daemon(3)) application is responsible for changing mode to
207aa772005SRobert Watson * PJDLOG_MODE_SYSLOG, so logs will be send to syslog.
208aa772005SRobert Watson */
209aa772005SRobert Watson void
pjdlog_mode_set(int mode)210aa772005SRobert Watson pjdlog_mode_set(int mode)
211aa772005SRobert Watson {
212aa772005SRobert Watson int saved_errno;
213aa772005SRobert Watson
214aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
215aa772005SRobert Watson assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG);
216aa772005SRobert Watson
217aa772005SRobert Watson if (pjdlog_mode == mode)
218aa772005SRobert Watson return;
219aa772005SRobert Watson
220aa772005SRobert Watson saved_errno = errno;
221aa772005SRobert Watson
222aa772005SRobert Watson if (mode == PJDLOG_MODE_SYSLOG)
223aa772005SRobert Watson openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON);
224aa772005SRobert Watson else /* if (mode == PJDLOG_MODE_STD) */
225aa772005SRobert Watson closelog();
226aa772005SRobert Watson
227aa772005SRobert Watson pjdlog_mode = mode;
228aa772005SRobert Watson
229aa772005SRobert Watson errno = saved_errno;
230aa772005SRobert Watson }
231aa772005SRobert Watson
232aa772005SRobert Watson /*
233aa772005SRobert Watson * Return current mode.
234aa772005SRobert Watson */
235aa772005SRobert Watson int
pjdlog_mode_get(void)236aa772005SRobert Watson pjdlog_mode_get(void)
237aa772005SRobert Watson {
238aa772005SRobert Watson
239aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
240aa772005SRobert Watson
241aa772005SRobert Watson return (pjdlog_mode);
242aa772005SRobert Watson }
243aa772005SRobert Watson
244aa772005SRobert Watson /*
245aa772005SRobert Watson * Set debug level. All the logs above the level specified here will be
246aa772005SRobert Watson * ignored.
247aa772005SRobert Watson */
248aa772005SRobert Watson void
pjdlog_debug_set(int level)249aa772005SRobert Watson pjdlog_debug_set(int level)
250aa772005SRobert Watson {
251aa772005SRobert Watson
252aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
253aa772005SRobert Watson assert(level >= 0);
254aa772005SRobert Watson
255aa772005SRobert Watson pjdlog_debug_level = level;
256aa772005SRobert Watson }
257aa772005SRobert Watson
258aa772005SRobert Watson /*
259aa772005SRobert Watson * Return current debug level.
260aa772005SRobert Watson */
261aa772005SRobert Watson int
pjdlog_debug_get(void)262aa772005SRobert Watson pjdlog_debug_get(void)
263aa772005SRobert Watson {
264aa772005SRobert Watson
265aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
266aa772005SRobert Watson
267aa772005SRobert Watson return (pjdlog_debug_level);
268aa772005SRobert Watson }
269aa772005SRobert Watson
270aa772005SRobert Watson /*
271aa772005SRobert Watson * Set prefix that will be used before each log.
272aa772005SRobert Watson * Setting prefix to NULL will remove it.
273aa772005SRobert Watson */
274aa772005SRobert Watson void
pjdlog_prefix_set(const char * fmt,...)275aa772005SRobert Watson pjdlog_prefix_set(const char *fmt, ...)
276aa772005SRobert Watson {
277aa772005SRobert Watson va_list ap;
278aa772005SRobert Watson
279aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
280aa772005SRobert Watson
281aa772005SRobert Watson va_start(ap, fmt);
282aa772005SRobert Watson pjdlogv_prefix_set(fmt, ap);
283aa772005SRobert Watson va_end(ap);
284aa772005SRobert Watson }
285aa772005SRobert Watson
286aa772005SRobert Watson /*
287aa772005SRobert Watson * Set prefix that will be used before each log.
288aa772005SRobert Watson * Setting prefix to NULL will remove it.
289aa772005SRobert Watson */
290aa772005SRobert Watson void
pjdlogv_prefix_set(const char * fmt,va_list ap)291aa772005SRobert Watson pjdlogv_prefix_set(const char *fmt, va_list ap)
292aa772005SRobert Watson {
293aa772005SRobert Watson int saved_errno;
294aa772005SRobert Watson
295aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
296aa772005SRobert Watson assert(fmt != NULL);
297aa772005SRobert Watson
298aa772005SRobert Watson saved_errno = errno;
299aa772005SRobert Watson
300aa772005SRobert Watson vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap);
301aa772005SRobert Watson
302aa772005SRobert Watson errno = saved_errno;
303aa772005SRobert Watson }
304aa772005SRobert Watson
305aa772005SRobert Watson /*
306aa772005SRobert Watson * Convert log level into string.
307aa772005SRobert Watson */
308aa772005SRobert Watson static const char *
pjdlog_level_string(int loglevel)309aa772005SRobert Watson pjdlog_level_string(int loglevel)
310aa772005SRobert Watson {
311aa772005SRobert Watson
312aa772005SRobert Watson switch (loglevel) {
313aa772005SRobert Watson case LOG_EMERG:
314aa772005SRobert Watson return ("EMERG");
315aa772005SRobert Watson case LOG_ALERT:
316aa772005SRobert Watson return ("ALERT");
317aa772005SRobert Watson case LOG_CRIT:
318aa772005SRobert Watson return ("CRIT");
319aa772005SRobert Watson case LOG_ERR:
320aa772005SRobert Watson return ("ERROR");
321aa772005SRobert Watson case LOG_WARNING:
322aa772005SRobert Watson return ("WARNING");
323aa772005SRobert Watson case LOG_NOTICE:
324aa772005SRobert Watson return ("NOTICE");
325aa772005SRobert Watson case LOG_INFO:
326aa772005SRobert Watson return ("INFO");
327aa772005SRobert Watson case LOG_DEBUG:
328aa772005SRobert Watson return ("DEBUG");
329aa772005SRobert Watson }
330aa772005SRobert Watson assert(!"Invalid log level.");
331aa772005SRobert Watson abort(); /* XXX: gcc */
332aa772005SRobert Watson }
333aa772005SRobert Watson
334aa772005SRobert Watson /*
335aa772005SRobert Watson * Common log routine.
336aa772005SRobert Watson */
337aa772005SRobert Watson void
pjdlog_common(int loglevel,int debuglevel,int error,const char * fmt,...)338aa772005SRobert Watson pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...)
339aa772005SRobert Watson {
340aa772005SRobert Watson va_list ap;
341aa772005SRobert Watson
342aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
343aa772005SRobert Watson
344aa772005SRobert Watson va_start(ap, fmt);
345aa772005SRobert Watson pjdlogv_common(loglevel, debuglevel, error, fmt, ap);
346aa772005SRobert Watson va_end(ap);
347aa772005SRobert Watson }
348aa772005SRobert Watson
349aa772005SRobert Watson /*
350aa772005SRobert Watson * Common log routine, which can handle regular log level as well as debug
351aa772005SRobert Watson * level. We decide here where to send the logs (stdout/stderr or syslog).
352aa772005SRobert Watson */
353aa772005SRobert Watson void
pjdlogv_common(int loglevel,int debuglevel,int error,const char * fmt,va_list ap)354aa772005SRobert Watson pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt,
355aa772005SRobert Watson va_list ap)
356aa772005SRobert Watson {
357aa772005SRobert Watson int saved_errno;
358aa772005SRobert Watson
359aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
360aa772005SRobert Watson assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
361aa772005SRobert Watson loglevel == LOG_CRIT || loglevel == LOG_ERR ||
362aa772005SRobert Watson loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
363aa772005SRobert Watson loglevel == LOG_INFO || loglevel == LOG_DEBUG);
364aa772005SRobert Watson assert(loglevel != LOG_DEBUG || debuglevel > 0);
365aa772005SRobert Watson assert(error >= -1);
366aa772005SRobert Watson
367aa772005SRobert Watson /* Ignore debug above configured level. */
368aa772005SRobert Watson if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level)
369aa772005SRobert Watson return;
370aa772005SRobert Watson
371aa772005SRobert Watson saved_errno = errno;
372aa772005SRobert Watson
373aa772005SRobert Watson switch (pjdlog_mode) {
374aa772005SRobert Watson case PJDLOG_MODE_STD:
375aa772005SRobert Watson {
376aa772005SRobert Watson FILE *out;
377aa772005SRobert Watson
378aa772005SRobert Watson /*
379aa772005SRobert Watson * We send errors and warning to stderr and the rest to stdout.
380aa772005SRobert Watson */
381aa772005SRobert Watson switch (loglevel) {
382aa772005SRobert Watson case LOG_EMERG:
383aa772005SRobert Watson case LOG_ALERT:
384aa772005SRobert Watson case LOG_CRIT:
385aa772005SRobert Watson case LOG_ERR:
386aa772005SRobert Watson case LOG_WARNING:
387aa772005SRobert Watson out = stderr;
388aa772005SRobert Watson break;
389aa772005SRobert Watson case LOG_NOTICE:
390aa772005SRobert Watson case LOG_INFO:
391aa772005SRobert Watson case LOG_DEBUG:
392aa772005SRobert Watson out = stdout;
393aa772005SRobert Watson break;
394aa772005SRobert Watson default:
395aa772005SRobert Watson assert(!"Invalid loglevel.");
396aa772005SRobert Watson abort(); /* XXX: gcc */
397aa772005SRobert Watson }
398aa772005SRobert Watson
399aa772005SRobert Watson fprintf(out, "(%d) ", getpid());
400aa772005SRobert Watson fprintf(out, "[%s]", pjdlog_level_string(loglevel));
401aa772005SRobert Watson /* Attach debuglevel if this is debug log. */
402aa772005SRobert Watson if (loglevel == LOG_DEBUG)
403aa772005SRobert Watson fprintf(out, "[%d]", debuglevel);
404aa772005SRobert Watson fprintf(out, " %s", pjdlog_prefix);
405aa772005SRobert Watson vfprintf(out, fmt, ap);
406aa772005SRobert Watson if (error != -1)
407aa772005SRobert Watson fprintf(out, ": %s.", strerror(error));
408aa772005SRobert Watson fprintf(out, "\n");
409aa772005SRobert Watson fflush(out);
410aa772005SRobert Watson break;
411aa772005SRobert Watson }
412aa772005SRobert Watson case PJDLOG_MODE_SYSLOG:
413aa772005SRobert Watson {
414aa772005SRobert Watson char log[1024];
415aa772005SRobert Watson int len;
416aa772005SRobert Watson
417aa772005SRobert Watson len = snprintf(log, sizeof(log), "%s", pjdlog_prefix);
418aa772005SRobert Watson if ((size_t)len < sizeof(log))
419aa772005SRobert Watson len += vsnprintf(log + len, sizeof(log) - len, fmt, ap);
420aa772005SRobert Watson if (error != -1 && (size_t)len < sizeof(log)) {
421aa772005SRobert Watson (void)snprintf(log + len, sizeof(log) - len, ": %s.",
422aa772005SRobert Watson strerror(error));
423aa772005SRobert Watson }
424aa772005SRobert Watson syslog(loglevel, "%s", log);
425aa772005SRobert Watson break;
426aa772005SRobert Watson }
427aa772005SRobert Watson default:
428aa772005SRobert Watson assert(!"Invalid mode.");
429aa772005SRobert Watson }
430aa772005SRobert Watson
431aa772005SRobert Watson errno = saved_errno;
432aa772005SRobert Watson }
433aa772005SRobert Watson
434aa772005SRobert Watson /*
435aa772005SRobert Watson * Regular logs.
436aa772005SRobert Watson */
437aa772005SRobert Watson void
pjdlogv(int loglevel,const char * fmt,va_list ap)438aa772005SRobert Watson pjdlogv(int loglevel, const char *fmt, va_list ap)
439aa772005SRobert Watson {
440aa772005SRobert Watson
441aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
442aa772005SRobert Watson
443aa772005SRobert Watson /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */
444aa772005SRobert Watson assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT ||
445aa772005SRobert Watson loglevel == LOG_CRIT || loglevel == LOG_ERR ||
446aa772005SRobert Watson loglevel == LOG_WARNING || loglevel == LOG_NOTICE ||
447aa772005SRobert Watson loglevel == LOG_INFO);
448aa772005SRobert Watson
449aa772005SRobert Watson pjdlogv_common(loglevel, 0, -1, fmt, ap);
450aa772005SRobert Watson }
451aa772005SRobert Watson
452aa772005SRobert Watson /*
453aa772005SRobert Watson * Regular logs.
454aa772005SRobert Watson */
455aa772005SRobert Watson void
pjdlog(int loglevel,const char * fmt,...)456aa772005SRobert Watson pjdlog(int loglevel, const char *fmt, ...)
457aa772005SRobert Watson {
458aa772005SRobert Watson va_list ap;
459aa772005SRobert Watson
460aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
461aa772005SRobert Watson
462aa772005SRobert Watson va_start(ap, fmt);
463aa772005SRobert Watson pjdlogv(loglevel, fmt, ap);
464aa772005SRobert Watson va_end(ap);
465aa772005SRobert Watson }
466aa772005SRobert Watson
467aa772005SRobert Watson /*
468aa772005SRobert Watson * Debug logs.
469aa772005SRobert Watson */
470aa772005SRobert Watson void
pjdlogv_debug(int debuglevel,const char * fmt,va_list ap)471aa772005SRobert Watson pjdlogv_debug(int debuglevel, const char *fmt, va_list ap)
472aa772005SRobert Watson {
473aa772005SRobert Watson
474aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
475aa772005SRobert Watson
476aa772005SRobert Watson pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap);
477aa772005SRobert Watson }
478aa772005SRobert Watson
479aa772005SRobert Watson /*
480aa772005SRobert Watson * Debug logs.
481aa772005SRobert Watson */
482aa772005SRobert Watson void
pjdlog_debug(int debuglevel,const char * fmt,...)483aa772005SRobert Watson pjdlog_debug(int debuglevel, const char *fmt, ...)
484aa772005SRobert Watson {
485aa772005SRobert Watson va_list ap;
486aa772005SRobert Watson
487aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
488aa772005SRobert Watson
489aa772005SRobert Watson va_start(ap, fmt);
490aa772005SRobert Watson pjdlogv_debug(debuglevel, fmt, ap);
491aa772005SRobert Watson va_end(ap);
492aa772005SRobert Watson }
493aa772005SRobert Watson
494aa772005SRobert Watson /*
495aa772005SRobert Watson * Error logs with errno logging.
496aa772005SRobert Watson */
497aa772005SRobert Watson void
pjdlogv_errno(int loglevel,const char * fmt,va_list ap)498aa772005SRobert Watson pjdlogv_errno(int loglevel, const char *fmt, va_list ap)
499aa772005SRobert Watson {
500aa772005SRobert Watson
501aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
502aa772005SRobert Watson
503aa772005SRobert Watson pjdlogv_common(loglevel, 0, errno, fmt, ap);
504aa772005SRobert Watson }
505aa772005SRobert Watson
506aa772005SRobert Watson /*
507aa772005SRobert Watson * Error logs with errno logging.
508aa772005SRobert Watson */
509aa772005SRobert Watson void
pjdlog_errno(int loglevel,const char * fmt,...)510aa772005SRobert Watson pjdlog_errno(int loglevel, const char *fmt, ...)
511aa772005SRobert Watson {
512aa772005SRobert Watson va_list ap;
513aa772005SRobert Watson
514aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
515aa772005SRobert Watson
516aa772005SRobert Watson va_start(ap, fmt);
517aa772005SRobert Watson pjdlogv_errno(loglevel, fmt, ap);
518aa772005SRobert Watson va_end(ap);
519aa772005SRobert Watson }
520aa772005SRobert Watson
521aa772005SRobert Watson /*
522aa772005SRobert Watson * Log error, errno and exit.
523aa772005SRobert Watson */
524aa772005SRobert Watson void
pjdlogv_exit(int exitcode,const char * fmt,va_list ap)525aa772005SRobert Watson pjdlogv_exit(int exitcode, const char *fmt, va_list ap)
526aa772005SRobert Watson {
527aa772005SRobert Watson
528aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
529aa772005SRobert Watson
530aa772005SRobert Watson pjdlogv_errno(LOG_ERR, fmt, ap);
531aa772005SRobert Watson exit(exitcode);
532aa772005SRobert Watson /* NOTREACHED */
533aa772005SRobert Watson }
534aa772005SRobert Watson
535aa772005SRobert Watson /*
536aa772005SRobert Watson * Log error, errno and exit.
537aa772005SRobert Watson */
538aa772005SRobert Watson void
pjdlog_exit(int exitcode,const char * fmt,...)539aa772005SRobert Watson pjdlog_exit(int exitcode, const char *fmt, ...)
540aa772005SRobert Watson {
541aa772005SRobert Watson va_list ap;
542aa772005SRobert Watson
543aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
544aa772005SRobert Watson
545aa772005SRobert Watson va_start(ap, fmt);
546aa772005SRobert Watson pjdlogv_exit(exitcode, fmt, ap);
547aa772005SRobert Watson /* NOTREACHED */
548aa772005SRobert Watson va_end(ap);
549aa772005SRobert Watson }
550aa772005SRobert Watson
551aa772005SRobert Watson /*
552aa772005SRobert Watson * Log error and exit.
553aa772005SRobert Watson */
554aa772005SRobert Watson void
pjdlogv_exitx(int exitcode,const char * fmt,va_list ap)555aa772005SRobert Watson pjdlogv_exitx(int exitcode, const char *fmt, va_list ap)
556aa772005SRobert Watson {
557aa772005SRobert Watson
558aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
559aa772005SRobert Watson
560aa772005SRobert Watson pjdlogv(LOG_ERR, fmt, ap);
561aa772005SRobert Watson exit(exitcode);
562aa772005SRobert Watson /* NOTREACHED */
563aa772005SRobert Watson }
564aa772005SRobert Watson
565aa772005SRobert Watson /*
566aa772005SRobert Watson * Log error and exit.
567aa772005SRobert Watson */
568aa772005SRobert Watson void
pjdlog_exitx(int exitcode,const char * fmt,...)569aa772005SRobert Watson pjdlog_exitx(int exitcode, const char *fmt, ...)
570aa772005SRobert Watson {
571aa772005SRobert Watson va_list ap;
572aa772005SRobert Watson
573aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
574aa772005SRobert Watson
575aa772005SRobert Watson va_start(ap, fmt);
576aa772005SRobert Watson pjdlogv_exitx(exitcode, fmt, ap);
577aa772005SRobert Watson /* NOTREACHED */
578aa772005SRobert Watson va_end(ap);
579aa772005SRobert Watson }
580aa772005SRobert Watson
581aa772005SRobert Watson /*
582aa772005SRobert Watson * Log failure message and exit.
583aa772005SRobert Watson */
584aa772005SRobert Watson void
pjdlog_abort(const char * func,const char * file,int line,const char * failedexpr,const char * fmt,...)585aa772005SRobert Watson pjdlog_abort(const char *func, const char *file, int line,
586aa772005SRobert Watson const char *failedexpr, const char *fmt, ...)
587aa772005SRobert Watson {
588aa772005SRobert Watson va_list ap;
589aa772005SRobert Watson
590aa772005SRobert Watson assert(pjdlog_initialized == PJDLOG_INITIALIZED);
591aa772005SRobert Watson
592aa772005SRobert Watson /*
593aa772005SRobert Watson * When there is no message we pass __func__ as 'fmt'.
594aa772005SRobert Watson * It would be cleaner to pass NULL or "", but gcc generates a warning
595aa772005SRobert Watson * for both of those.
596aa772005SRobert Watson */
597aa772005SRobert Watson if (fmt != func) {
598aa772005SRobert Watson va_start(ap, fmt);
599aa772005SRobert Watson pjdlogv_critical(fmt, ap);
600aa772005SRobert Watson va_end(ap);
601aa772005SRobert Watson }
602aa772005SRobert Watson if (failedexpr == NULL) {
603aa772005SRobert Watson if (func == NULL) {
604aa772005SRobert Watson pjdlog_critical("Aborted at file %s, line %d.", file,
605aa772005SRobert Watson line);
606aa772005SRobert Watson } else {
607aa772005SRobert Watson pjdlog_critical("Aborted at function %s, file %s, line %d.",
608aa772005SRobert Watson func, file, line);
609aa772005SRobert Watson }
610aa772005SRobert Watson } else {
611aa772005SRobert Watson if (func == NULL) {
612aa772005SRobert Watson pjdlog_critical("Assertion failed: (%s), file %s, line %d.",
613aa772005SRobert Watson failedexpr, file, line);
614aa772005SRobert Watson } else {
615aa772005SRobert Watson pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.",
616aa772005SRobert Watson failedexpr, func, file, line);
617aa772005SRobert Watson }
618aa772005SRobert Watson }
619aa772005SRobert Watson abort();
620aa772005SRobert Watson }
621