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