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