]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/log.c
log: Avoid pushing the same fields more than once on the log context
[thirdparty/systemd.git] / src / basic / log.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <inttypes.h>
6 #include <limits.h>
7 #include <stdarg.h>
8 #include <stddef.h>
9 #include <sys/signalfd.h>
10 #include <sys/stat.h>
11 #include <sys/time.h>
12 #include <sys/uio.h>
13 #include <sys/un.h>
14 #include <unistd.h>
15
16 #include "sd-messages.h"
17
18 #include "alloc-util.h"
19 #include "argv-util.h"
20 #include "env-util.h"
21 #include "errno-util.h"
22 #include "fd-util.h"
23 #include "format-util.h"
24 #include "io-util.h"
25 #include "log.h"
26 #include "macro.h"
27 #include "missing_syscall.h"
28 #include "missing_threads.h"
29 #include "parse-util.h"
30 #include "proc-cmdline.h"
31 #include "process-util.h"
32 #include "ratelimit.h"
33 #include "signal-util.h"
34 #include "socket-util.h"
35 #include "stdio-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
38 #include "strv.h"
39 #include "syslog-util.h"
40 #include "terminal-util.h"
41 #include "time-util.h"
42 #include "utf8.h"
43
44 #define SNDBUF_SIZE (8*1024*1024)
45 #define IOVEC_MAX 128U
46
47 static log_syntax_callback_t log_syntax_callback = NULL;
48 static void *log_syntax_callback_userdata = NULL;
49
50 static LogTarget log_target = LOG_TARGET_CONSOLE;
51 static int log_max_level = LOG_INFO;
52 static int log_facility = LOG_DAEMON;
53
54 static int console_fd = STDERR_FILENO;
55 static int syslog_fd = -EBADF;
56 static int kmsg_fd = -EBADF;
57 static int journal_fd = -EBADF;
58
59 static bool syslog_is_stream = false;
60
61 static int show_color = -1; /* tristate */
62 static bool show_location = false;
63 static bool show_time = false;
64 static bool show_tid = false;
65
66 static bool upgrade_syslog_to_journal = false;
67 static bool always_reopen_console = false;
68 static bool open_when_needed = false;
69 static bool prohibit_ipc = false;
70
71 /* Akin to glibc's __abort_msg; which is private and we hence cannot
72 * use here. */
73 static char *log_abort_msg = NULL;
74
75 typedef struct LogContext {
76 unsigned n_ref;
77 /* Depending on which destructor is used (log_context_free() or log_context_detach()) the memory
78 * referenced by this is freed or not */
79 char **fields;
80 struct iovec *input_iovec;
81 size_t n_input_iovec;
82 bool owned;
83 LIST_FIELDS(struct LogContext, ll);
84 } LogContext;
85
86 static thread_local LIST_HEAD(LogContext, _log_context) = NULL;
87 static thread_local size_t _log_context_num_fields = 0;
88
89 #if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__)
90 bool _log_message_dummy = false; /* Always false */
91 #endif
92
93 /* An assert to use in logging functions that does not call recursively
94 * into our logging functions (since that might lead to a loop). */
95 #define assert_raw(expr) \
96 do { \
97 if (_unlikely_(!(expr))) { \
98 fputs(#expr "\n", stderr); \
99 abort(); \
100 } \
101 } while (false)
102
103 static void log_close_console(void) {
104 console_fd = safe_close_above_stdio(console_fd);
105 }
106
107 static int log_open_console(void) {
108
109 if (!always_reopen_console) {
110 console_fd = STDERR_FILENO;
111 return 0;
112 }
113
114 if (console_fd < 3) {
115 int fd;
116
117 fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
118 if (fd < 0)
119 return fd;
120
121 console_fd = fd_move_above_stdio(fd);
122 }
123
124 return 0;
125 }
126
127 static void log_close_kmsg(void) {
128 kmsg_fd = safe_close(kmsg_fd);
129 }
130
131 static int log_open_kmsg(void) {
132
133 if (kmsg_fd >= 0)
134 return 0;
135
136 kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
137 if (kmsg_fd < 0)
138 return -errno;
139
140 kmsg_fd = fd_move_above_stdio(kmsg_fd);
141 return 0;
142 }
143
144 static void log_close_syslog(void) {
145 syslog_fd = safe_close(syslog_fd);
146 }
147
148 static int create_log_socket(int type) {
149 struct timeval tv;
150 int fd;
151
152 fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
153 if (fd < 0)
154 return -errno;
155
156 fd = fd_move_above_stdio(fd);
157 (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
158
159 /* We need a blocking fd here since we'd otherwise lose messages way too early. However, let's not hang forever
160 * in the unlikely case of a deadlock. */
161 if (getpid_cached() == 1)
162 timeval_store(&tv, 10 * USEC_PER_MSEC);
163 else
164 timeval_store(&tv, 10 * USEC_PER_SEC);
165 (void) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
166
167 return fd;
168 }
169
170 static int log_open_syslog(void) {
171 int r;
172
173 if (syslog_fd >= 0)
174 return 0;
175
176 syslog_fd = create_log_socket(SOCK_DGRAM);
177 if (syslog_fd < 0) {
178 r = syslog_fd;
179 goto fail;
180 }
181
182 r = connect_unix_path(syslog_fd, AT_FDCWD, "/dev/log");
183 if (r < 0) {
184 safe_close(syslog_fd);
185
186 /* Some legacy syslog systems still use stream sockets. They really shouldn't. But what can
187 * we do... */
188 syslog_fd = create_log_socket(SOCK_STREAM);
189 if (syslog_fd < 0) {
190 r = syslog_fd;
191 goto fail;
192 }
193
194 r = connect_unix_path(syslog_fd, AT_FDCWD, "/dev/log");
195 if (r < 0)
196 goto fail;
197
198 syslog_is_stream = true;
199 } else
200 syslog_is_stream = false;
201
202 return 0;
203
204 fail:
205 log_close_syslog();
206 return r;
207 }
208
209 static void log_close_journal(void) {
210 journal_fd = safe_close(journal_fd);
211 }
212
213 static int log_open_journal(void) {
214 int r;
215
216 if (journal_fd >= 0)
217 return 0;
218
219 journal_fd = create_log_socket(SOCK_DGRAM);
220 if (journal_fd < 0) {
221 r = journal_fd;
222 goto fail;
223 }
224
225 r = connect_unix_path(journal_fd, AT_FDCWD, "/run/systemd/journal/socket");
226 if (r < 0)
227 goto fail;
228
229 return 0;
230
231 fail:
232 log_close_journal();
233 return r;
234 }
235
236 static bool stderr_is_journal(void) {
237 _cleanup_free_ char *w = NULL;
238 const char *e;
239 uint64_t dev, ino;
240 struct stat st;
241
242 e = getenv("JOURNAL_STREAM");
243 if (!e)
244 return false;
245
246 if (extract_first_word(&e, &w, ":", EXTRACT_DONT_COALESCE_SEPARATORS) <= 0)
247 return false;
248 if (!e)
249 return false;
250
251 if (safe_atou64(w, &dev) < 0)
252 return false;
253 if (safe_atou64(e, &ino) < 0)
254 return false;
255
256 if (fstat(STDERR_FILENO, &st) < 0)
257 return false;
258
259 return st.st_dev == dev && st.st_ino == ino;
260 }
261
262 int log_open(void) {
263 int r;
264
265 /* Do not call from library code. */
266
267 /* This function is often called in preparation for logging. Let's make sure we don't clobber errno,
268 * so that a call to a logging function immediately following a log_open() call can still easily
269 * reference an error that happened immediately before the log_open() call. */
270 PROTECT_ERRNO;
271
272 /* If we don't use the console, we close it here to not get killed by SAK. If we don't use syslog, we
273 * close it here too, so that we are not confused by somebody deleting the socket in the fs, and to
274 * make sure we don't use it if prohibit_ipc is set. If we don't use /dev/kmsg we still keep it open,
275 * because there is no reason to close it. */
276
277 if (log_target == LOG_TARGET_NULL) {
278 log_close_journal();
279 log_close_syslog();
280 log_close_console();
281 return 0;
282 }
283
284 if (getpid_cached() == 1 ||
285 stderr_is_journal() ||
286 IN_SET(log_target,
287 LOG_TARGET_KMSG,
288 LOG_TARGET_JOURNAL,
289 LOG_TARGET_JOURNAL_OR_KMSG,
290 LOG_TARGET_SYSLOG,
291 LOG_TARGET_SYSLOG_OR_KMSG)) {
292
293 if (!prohibit_ipc) {
294 if (IN_SET(log_target,
295 LOG_TARGET_AUTO,
296 LOG_TARGET_JOURNAL_OR_KMSG,
297 LOG_TARGET_JOURNAL)) {
298
299 r = log_open_journal();
300 if (r >= 0) {
301 log_close_syslog();
302 log_close_console();
303 return r;
304 }
305 }
306
307 if (IN_SET(log_target,
308 LOG_TARGET_SYSLOG_OR_KMSG,
309 LOG_TARGET_SYSLOG)) {
310
311 r = log_open_syslog();
312 if (r >= 0) {
313 log_close_journal();
314 log_close_console();
315 return r;
316 }
317 }
318 }
319
320 if (IN_SET(log_target, LOG_TARGET_AUTO,
321 LOG_TARGET_JOURNAL_OR_KMSG,
322 LOG_TARGET_SYSLOG_OR_KMSG,
323 LOG_TARGET_KMSG)) {
324 r = log_open_kmsg();
325 if (r >= 0) {
326 log_close_journal();
327 log_close_syslog();
328 log_close_console();
329 return r;
330 }
331 }
332 }
333
334 log_close_journal();
335 log_close_syslog();
336
337 return log_open_console();
338 }
339
340 void log_set_target(LogTarget target) {
341 assert(target >= 0);
342 assert(target < _LOG_TARGET_MAX);
343
344 if (upgrade_syslog_to_journal) {
345 if (target == LOG_TARGET_SYSLOG)
346 target = LOG_TARGET_JOURNAL;
347 else if (target == LOG_TARGET_SYSLOG_OR_KMSG)
348 target = LOG_TARGET_JOURNAL_OR_KMSG;
349 }
350
351 log_target = target;
352 }
353
354 void log_set_target_and_open(LogTarget target) {
355 log_set_target(target);
356 log_open();
357 }
358
359 void log_close(void) {
360 /* Do not call from library code. */
361
362 log_close_journal();
363 log_close_syslog();
364 log_close_kmsg();
365 log_close_console();
366 }
367
368 void log_forget_fds(void) {
369 /* Do not call from library code. */
370
371 console_fd = kmsg_fd = syslog_fd = journal_fd = -EBADF;
372 }
373
374 void log_set_max_level(int level) {
375 assert(level == LOG_NULL || (level & LOG_PRIMASK) == level);
376
377 log_max_level = level;
378 }
379
380 void log_set_facility(int facility) {
381 log_facility = facility;
382 }
383
384 static int write_to_console(
385 int level,
386 int error,
387 const char *file,
388 int line,
389 const char *func,
390 const char *buffer) {
391
392 char location[256],
393 header_time[FORMAT_TIMESTAMP_MAX],
394 prefix[1 + DECIMAL_STR_MAX(int) + 2],
395 tid_string[3 + DECIMAL_STR_MAX(pid_t) + 1];
396 struct iovec iovec[9];
397 const char *on = NULL, *off = NULL;
398 size_t n = 0;
399
400 if (console_fd < 0)
401 return 0;
402
403 if (log_target == LOG_TARGET_CONSOLE_PREFIXED) {
404 xsprintf(prefix, "<%i>", level);
405 iovec[n++] = IOVEC_MAKE_STRING(prefix);
406 }
407
408 if (show_time &&
409 format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) {
410 iovec[n++] = IOVEC_MAKE_STRING(header_time);
411 iovec[n++] = IOVEC_MAKE_STRING(" ");
412 }
413
414 if (show_tid) {
415 xsprintf(tid_string, "(" PID_FMT ") ", gettid());
416 iovec[n++] = IOVEC_MAKE_STRING(tid_string);
417 }
418
419 if (log_get_show_color())
420 get_log_colors(LOG_PRI(level), &on, &off, NULL);
421
422 if (show_location) {
423 const char *lon = "", *loff = "";
424 if (log_get_show_color()) {
425 lon = ansi_highlight_yellow4();
426 loff = ansi_normal();
427 }
428
429 (void) snprintf(location, sizeof location, "%s%s:%i%s: ", lon, file, line, loff);
430 iovec[n++] = IOVEC_MAKE_STRING(location);
431 }
432
433 if (on)
434 iovec[n++] = IOVEC_MAKE_STRING(on);
435 iovec[n++] = IOVEC_MAKE_STRING(buffer);
436 if (off)
437 iovec[n++] = IOVEC_MAKE_STRING(off);
438 iovec[n++] = IOVEC_MAKE_STRING("\n");
439
440 if (writev(console_fd, iovec, n) < 0) {
441
442 if (errno == EIO && getpid_cached() == 1) {
443
444 /* If somebody tried to kick us from our console tty (via vhangup() or suchlike), try
445 * to reconnect. */
446
447 log_close_console();
448 (void) log_open_console();
449 if (console_fd < 0)
450 return 0;
451
452 if (writev(console_fd, iovec, n) < 0)
453 return -errno;
454 } else
455 return -errno;
456 }
457
458 return 1;
459 }
460
461 static int write_to_syslog(
462 int level,
463 int error,
464 const char *file,
465 int line,
466 const char *func,
467 const char *buffer) {
468
469 char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
470 header_time[64],
471 header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
472 time_t t;
473 struct tm tm;
474
475 if (syslog_fd < 0)
476 return 0;
477
478 xsprintf(header_priority, "<%i>", level);
479
480 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
481 if (!localtime_r(&t, &tm))
482 return -EINVAL;
483
484 if (strftime(header_time, sizeof(header_time), "%h %e %T ", &tm) <= 0)
485 return -EINVAL;
486
487 xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
488
489 struct iovec iovec[] = {
490 IOVEC_MAKE_STRING(header_priority),
491 IOVEC_MAKE_STRING(header_time),
492 IOVEC_MAKE_STRING(program_invocation_short_name),
493 IOVEC_MAKE_STRING(header_pid),
494 IOVEC_MAKE_STRING(buffer),
495 };
496 const struct msghdr msghdr = {
497 .msg_iov = iovec,
498 .msg_iovlen = ELEMENTSOF(iovec),
499 };
500
501 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
502 if (syslog_is_stream)
503 iovec[ELEMENTSOF(iovec) - 1].iov_len++;
504
505 for (;;) {
506 ssize_t n;
507
508 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
509 if (n < 0)
510 return -errno;
511
512 if (!syslog_is_stream)
513 break;
514
515 if (IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n))
516 break;
517 }
518
519 return 1;
520 }
521
522 static int write_to_kmsg(
523 int level,
524 int error,
525 const char *file,
526 int line,
527 const char *func,
528 const char *buffer) {
529
530 /* Set a ratelimit on the amount of messages logged to /dev/kmsg. This is mostly supposed to be a
531 * safety catch for the case where start indiscriminately logging in a loop. It will not catch cases
532 * where we log excessively, but not in a tight loop.
533 *
534 * Note that this ratelimit is per-emitter, so we might still overwhelm /dev/kmsg with multiple
535 * loggers.
536 */
537 static thread_local RateLimit ratelimit = { 5 * USEC_PER_SEC, 200 };
538
539 char header_priority[2 + DECIMAL_STR_MAX(int) + 1],
540 header_pid[4 + DECIMAL_STR_MAX(pid_t) + 1];
541
542 if (kmsg_fd < 0)
543 return 0;
544
545 if (!ratelimit_below(&ratelimit))
546 return 0;
547
548 xsprintf(header_priority, "<%i>", level);
549 xsprintf(header_pid, "["PID_FMT"]: ", getpid_cached());
550
551 const struct iovec iovec[] = {
552 IOVEC_MAKE_STRING(header_priority),
553 IOVEC_MAKE_STRING(program_invocation_short_name),
554 IOVEC_MAKE_STRING(header_pid),
555 IOVEC_MAKE_STRING(buffer),
556 IOVEC_MAKE_STRING("\n"),
557 };
558
559 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
560 return -errno;
561
562 return 1;
563 }
564
565 static int log_do_header(
566 char *header,
567 size_t size,
568 int level,
569 int error,
570 const char *file, int line, const char *func,
571 const char *object_field, const char *object,
572 const char *extra_field, const char *extra) {
573 int r;
574
575 error = IS_SYNTHETIC_ERRNO(error) ? 0 : ERRNO_VALUE(error);
576
577 r = snprintf(header, size,
578 "PRIORITY=%i\n"
579 "SYSLOG_FACILITY=%i\n"
580 "TID=" PID_FMT "\n"
581 "%s%.256s%s" /* CODE_FILE */
582 "%s%.*i%s" /* CODE_LINE */
583 "%s%.256s%s" /* CODE_FUNC */
584 "%s%.*i%s" /* ERRNO */
585 "%s%.256s%s" /* object */
586 "%s%.256s%s" /* extra */
587 "SYSLOG_IDENTIFIER=%.256s\n",
588 LOG_PRI(level),
589 LOG_FAC(level),
590 gettid(),
591 isempty(file) ? "" : "CODE_FILE=",
592 isempty(file) ? "" : file,
593 isempty(file) ? "" : "\n",
594 line ? "CODE_LINE=" : "",
595 line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
596 line ? "\n" : "",
597 isempty(func) ? "" : "CODE_FUNC=",
598 isempty(func) ? "" : func,
599 isempty(func) ? "" : "\n",
600 error ? "ERRNO=" : "",
601 error ? 1 : 0, error,
602 error ? "\n" : "",
603 isempty(object) ? "" : object_field,
604 isempty(object) ? "" : object,
605 isempty(object) ? "" : "\n",
606 isempty(extra) ? "" : extra_field,
607 isempty(extra) ? "" : extra,
608 isempty(extra) ? "" : "\n",
609 program_invocation_short_name);
610 assert_raw((size_t) r < size);
611
612 return 0;
613 }
614
615 static void log_do_context(struct iovec *iovec, size_t iovec_len, size_t *n) {
616 assert(iovec);
617 assert(n);
618
619 LIST_FOREACH(ll, c, _log_context) {
620 STRV_FOREACH(s, c->fields) {
621 if (*n + 2 >= iovec_len)
622 return;
623
624 iovec[(*n)++] = IOVEC_MAKE_STRING(*s);
625 iovec[(*n)++] = IOVEC_MAKE_STRING("\n");
626 }
627
628 for (size_t i = 0; i < c->n_input_iovec; i++) {
629 if (*n + 2 >= iovec_len)
630 return;
631
632 iovec[(*n)++] = c->input_iovec[i];
633 iovec[(*n)++] = IOVEC_MAKE_STRING("\n");
634 }
635 }
636 }
637
638 static int write_to_journal(
639 int level,
640 int error,
641 const char *file,
642 int line,
643 const char *func,
644 const char *object_field,
645 const char *object,
646 const char *extra_field,
647 const char *extra,
648 const char *buffer) {
649
650 char header[LINE_MAX];
651 size_t n = 0, iovec_len;
652 struct iovec *iovec;
653
654 if (journal_fd < 0)
655 return 0;
656
657 iovec_len = MIN(4 + _log_context_num_fields * 2, IOVEC_MAX);
658 iovec = newa(struct iovec, iovec_len);
659
660 log_do_header(header, sizeof(header), level, error, file, line, func, object_field, object, extra_field, extra);
661
662 iovec[n++] = IOVEC_MAKE_STRING(header);
663 iovec[n++] = IOVEC_MAKE_STRING("MESSAGE=");
664 iovec[n++] = IOVEC_MAKE_STRING(buffer);
665 iovec[n++] = IOVEC_MAKE_STRING("\n");
666
667 log_do_context(iovec, iovec_len, &n);
668
669 const struct msghdr msghdr = {
670 .msg_iov = iovec,
671 .msg_iovlen = n,
672 };
673
674 if (sendmsg(journal_fd, &msghdr, MSG_NOSIGNAL) < 0)
675 return -errno;
676
677 return 1;
678 }
679
680 int log_dispatch_internal(
681 int level,
682 int error,
683 const char *file,
684 int line,
685 const char *func,
686 const char *object_field,
687 const char *object,
688 const char *extra_field,
689 const char *extra,
690 char *buffer) {
691
692 assert_raw(buffer);
693
694 if (log_target == LOG_TARGET_NULL)
695 return -ERRNO_VALUE(error);
696
697 /* Patch in LOG_DAEMON facility if necessary */
698 if ((level & LOG_FACMASK) == 0)
699 level |= log_facility;
700
701 if (open_when_needed)
702 (void) log_open();
703
704 do {
705 char *e;
706 int k = 0;
707
708 buffer += strspn(buffer, NEWLINE);
709
710 if (buffer[0] == 0)
711 break;
712
713 if ((e = strpbrk(buffer, NEWLINE)))
714 *(e++) = 0;
715
716 if (IN_SET(log_target, LOG_TARGET_AUTO,
717 LOG_TARGET_JOURNAL_OR_KMSG,
718 LOG_TARGET_JOURNAL)) {
719
720 k = write_to_journal(level, error, file, line, func, object_field, object, extra_field, extra, buffer);
721 if (k < 0 && k != -EAGAIN)
722 log_close_journal();
723 }
724
725 if (IN_SET(log_target, LOG_TARGET_SYSLOG_OR_KMSG,
726 LOG_TARGET_SYSLOG)) {
727
728 k = write_to_syslog(level, error, file, line, func, buffer);
729 if (k < 0 && k != -EAGAIN)
730 log_close_syslog();
731 }
732
733 if (k <= 0 &&
734 IN_SET(log_target, LOG_TARGET_AUTO,
735 LOG_TARGET_SYSLOG_OR_KMSG,
736 LOG_TARGET_JOURNAL_OR_KMSG,
737 LOG_TARGET_KMSG)) {
738
739 if (k < 0)
740 log_open_kmsg();
741
742 k = write_to_kmsg(level, error, file, line, func, buffer);
743 if (k < 0) {
744 log_close_kmsg();
745 (void) log_open_console();
746 }
747 }
748
749 if (k <= 0)
750 (void) write_to_console(level, error, file, line, func, buffer);
751
752 buffer = e;
753 } while (buffer);
754
755 if (open_when_needed)
756 log_close();
757
758 return -ERRNO_VALUE(error);
759 }
760
761 int log_dump_internal(
762 int level,
763 int error,
764 const char *file,
765 int line,
766 const char *func,
767 char *buffer) {
768
769 PROTECT_ERRNO;
770
771 /* This modifies the buffer... */
772
773 if (_likely_(LOG_PRI(level) > log_max_level))
774 return -ERRNO_VALUE(error);
775
776 return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
777 }
778
779 int log_internalv(
780 int level,
781 int error,
782 const char *file,
783 int line,
784 const char *func,
785 const char *format,
786 va_list ap) {
787
788 if (_likely_(LOG_PRI(level) > log_max_level))
789 return -ERRNO_VALUE(error);
790
791 /* Make sure that %m maps to the specified error (or "Success"). */
792 char buffer[LINE_MAX];
793 LOCAL_ERRNO(ERRNO_VALUE(error));
794
795 (void) vsnprintf(buffer, sizeof buffer, format, ap);
796
797 return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
798 }
799
800 int log_internal(
801 int level,
802 int error,
803 const char *file,
804 int line,
805 const char *func,
806 const char *format, ...) {
807
808 va_list ap;
809 int r;
810
811 va_start(ap, format);
812 r = log_internalv(level, error, file, line, func, format, ap);
813 va_end(ap);
814
815 return r;
816 }
817
818 int log_object_internalv(
819 int level,
820 int error,
821 const char *file,
822 int line,
823 const char *func,
824 const char *object_field,
825 const char *object,
826 const char *extra_field,
827 const char *extra,
828 const char *format,
829 va_list ap) {
830
831 char *buffer, *b;
832
833 if (_likely_(LOG_PRI(level) > log_max_level))
834 return -ERRNO_VALUE(error);
835
836 /* Make sure that %m maps to the specified error (or "Success"). */
837 LOCAL_ERRNO(ERRNO_VALUE(error));
838
839 /* Prepend the object name before the message */
840 if (object) {
841 size_t n;
842
843 n = strlen(object);
844 buffer = newa(char, n + 2 + LINE_MAX);
845 b = stpcpy(stpcpy(buffer, object), ": ");
846 } else
847 b = buffer = newa(char, LINE_MAX);
848
849 (void) vsnprintf(b, LINE_MAX, format, ap);
850
851 return log_dispatch_internal(level, error, file, line, func,
852 object_field, object, extra_field, extra, buffer);
853 }
854
855 int log_object_internal(
856 int level,
857 int error,
858 const char *file,
859 int line,
860 const char *func,
861 const char *object_field,
862 const char *object,
863 const char *extra_field,
864 const char *extra,
865 const char *format, ...) {
866
867 va_list ap;
868 int r;
869
870 va_start(ap, format);
871 r = log_object_internalv(level, error, file, line, func, object_field, object, extra_field, extra, format, ap);
872 va_end(ap);
873
874 return r;
875 }
876
877 static void log_assert(
878 int level,
879 const char *text,
880 const char *file,
881 int line,
882 const char *func,
883 const char *format) {
884
885 static char buffer[LINE_MAX];
886
887 if (_likely_(LOG_PRI(level) > log_max_level))
888 return;
889
890 DISABLE_WARNING_FORMAT_NONLITERAL;
891 (void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
892 REENABLE_WARNING;
893
894 log_abort_msg = buffer;
895
896 log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
897 }
898
899 _noreturn_ void log_assert_failed(
900 const char *text,
901 const char *file,
902 int line,
903 const char *func) {
904 log_assert(LOG_CRIT, text, file, line, func,
905 "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
906 abort();
907 }
908
909 _noreturn_ void log_assert_failed_unreachable(
910 const char *file,
911 int line,
912 const char *func) {
913 log_assert(LOG_CRIT, "Code should not be reached", file, line, func,
914 "%s at %s:%u, function %s(). Aborting. 💥");
915 abort();
916 }
917
918 void log_assert_failed_return(
919 const char *text,
920 const char *file,
921 int line,
922 const char *func) {
923 PROTECT_ERRNO;
924 log_assert(LOG_DEBUG, text, file, line, func,
925 "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
926 }
927
928 int log_oom_internal(int level, const char *file, int line, const char *func) {
929 return log_internal(level, ENOMEM, file, line, func, "Out of memory.");
930 }
931
932 int log_format_iovec(
933 struct iovec *iovec,
934 size_t iovec_len,
935 size_t *n,
936 bool newline_separator,
937 int error,
938 const char *format,
939 va_list ap) {
940
941 static const char nl = '\n';
942
943 while (format && *n + 1 < iovec_len) {
944 va_list aq;
945 char *m;
946 int r;
947
948 /* We need to copy the va_list structure,
949 * since vasprintf() leaves it afterwards at
950 * an undefined location */
951
952 errno = ERRNO_VALUE(error);
953
954 va_copy(aq, ap);
955 r = vasprintf(&m, format, aq);
956 va_end(aq);
957 if (r < 0)
958 return -EINVAL;
959
960 /* Now, jump enough ahead, so that we point to
961 * the next format string */
962 VA_FORMAT_ADVANCE(format, ap);
963
964 iovec[(*n)++] = IOVEC_MAKE_STRING(m);
965 if (newline_separator)
966 iovec[(*n)++] = IOVEC_MAKE((char *)&nl, 1);
967
968 format = va_arg(ap, char *);
969 }
970 return 0;
971 }
972
973 int log_struct_internal(
974 int level,
975 int error,
976 const char *file,
977 int line,
978 const char *func,
979 const char *format, ...) {
980
981 char buf[LINE_MAX];
982 bool found = false;
983 PROTECT_ERRNO;
984 va_list ap;
985
986 if (_likely_(LOG_PRI(level) > log_max_level) ||
987 log_target == LOG_TARGET_NULL)
988 return -ERRNO_VALUE(error);
989
990 if ((level & LOG_FACMASK) == 0)
991 level |= log_facility;
992
993 if (IN_SET(log_target,
994 LOG_TARGET_AUTO,
995 LOG_TARGET_JOURNAL_OR_KMSG,
996 LOG_TARGET_JOURNAL)) {
997
998 if (open_when_needed)
999 log_open_journal();
1000
1001 if (journal_fd >= 0) {
1002 char header[LINE_MAX];
1003 struct iovec *iovec;
1004 size_t n = 0, m, iovec_len;
1005 int r;
1006 bool fallback = false;
1007
1008 iovec_len = MIN(17 + _log_context_num_fields * 2, IOVEC_MAX);
1009 iovec = newa(struct iovec, iovec_len);
1010
1011 /* If the journal is available do structured logging.
1012 * Do not report the errno if it is synthetic. */
1013 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
1014 iovec[n++] = IOVEC_MAKE_STRING(header);
1015
1016 va_start(ap, format);
1017 r = log_format_iovec(iovec, iovec_len, &n, true, error, format, ap);
1018 m = n;
1019 if (r < 0)
1020 fallback = true;
1021 else {
1022 log_do_context(iovec, iovec_len, &n);
1023
1024 const struct msghdr msghdr = {
1025 .msg_iov = iovec,
1026 .msg_iovlen = n,
1027 };
1028
1029 (void) sendmsg(journal_fd, &msghdr, MSG_NOSIGNAL);
1030 }
1031
1032 va_end(ap);
1033 for (size_t i = 1; i < m; i += 2)
1034 free(iovec[i].iov_base);
1035
1036 if (!fallback) {
1037 if (open_when_needed)
1038 log_close();
1039
1040 return -ERRNO_VALUE(error);
1041 }
1042 }
1043 }
1044
1045 /* Fallback if journal logging is not available or didn't work. */
1046
1047 va_start(ap, format);
1048 while (format) {
1049 va_list aq;
1050
1051 errno = ERRNO_VALUE(error);
1052
1053 va_copy(aq, ap);
1054 (void) vsnprintf(buf, sizeof buf, format, aq);
1055 va_end(aq);
1056
1057 if (startswith(buf, "MESSAGE=")) {
1058 found = true;
1059 break;
1060 }
1061
1062 VA_FORMAT_ADVANCE(format, ap);
1063
1064 format = va_arg(ap, char *);
1065 }
1066 va_end(ap);
1067
1068 if (!found) {
1069 if (open_when_needed)
1070 log_close();
1071
1072 return -ERRNO_VALUE(error);
1073 }
1074
1075 return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buf + 8);
1076 }
1077
1078 int log_struct_iovec_internal(
1079 int level,
1080 int error,
1081 const char *file,
1082 int line,
1083 const char *func,
1084 const struct iovec input_iovec[],
1085 size_t n_input_iovec) {
1086
1087 PROTECT_ERRNO;
1088
1089 if (_likely_(LOG_PRI(level) > log_max_level) ||
1090 log_target == LOG_TARGET_NULL)
1091 return -ERRNO_VALUE(error);
1092
1093 if ((level & LOG_FACMASK) == 0)
1094 level |= log_facility;
1095
1096 if (IN_SET(log_target, LOG_TARGET_AUTO,
1097 LOG_TARGET_JOURNAL_OR_KMSG,
1098 LOG_TARGET_JOURNAL) &&
1099 journal_fd >= 0) {
1100
1101 char header[LINE_MAX];
1102 struct iovec *iovec;
1103 size_t n = 0, iovec_len;
1104
1105 iovec_len = MIN(1 + n_input_iovec * 2 + _log_context_num_fields * 2, IOVEC_MAX);
1106 iovec = newa(struct iovec, iovec_len);
1107
1108 log_do_header(header, sizeof(header), level, error, file, line, func, NULL, NULL, NULL, NULL);
1109
1110 iovec[n++] = IOVEC_MAKE_STRING(header);
1111 for (size_t i = 0; i < n_input_iovec; i++) {
1112 iovec[n++] = input_iovec[i];
1113 iovec[n++] = IOVEC_MAKE_STRING("\n");
1114 }
1115
1116 log_do_context(iovec, iovec_len, &n);
1117
1118 const struct msghdr msghdr = {
1119 .msg_iov = iovec,
1120 .msg_iovlen = n,
1121 };
1122
1123 if (sendmsg(journal_fd, &msghdr, MSG_NOSIGNAL) >= 0)
1124 return -ERRNO_VALUE(error);
1125 }
1126
1127 for (size_t i = 0; i < n_input_iovec; i++)
1128 if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE=")) {
1129 char *m;
1130
1131 m = strndupa_safe((char*) input_iovec[i].iov_base + STRLEN("MESSAGE="),
1132 input_iovec[i].iov_len - STRLEN("MESSAGE="));
1133
1134 return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, m);
1135 }
1136
1137 /* Couldn't find MESSAGE=. */
1138 return -ERRNO_VALUE(error);
1139 }
1140
1141 int log_set_target_from_string(const char *e) {
1142 LogTarget t;
1143
1144 t = log_target_from_string(e);
1145 if (t < 0)
1146 return t;
1147
1148 log_set_target(t);
1149 return 0;
1150 }
1151
1152 int log_set_max_level_from_string(const char *e) {
1153 int t;
1154
1155 t = log_level_from_string(e);
1156 if (t < 0)
1157 return t;
1158
1159 log_set_max_level(t);
1160 return 0;
1161 }
1162
1163 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
1164
1165 /*
1166 * The systemd.log_xyz= settings are parsed by all tools, and
1167 * so is "debug".
1168 *
1169 * However, "quiet" is only parsed by PID 1, and only turns of
1170 * status output to /dev/console, but does not alter the log
1171 * level.
1172 */
1173
1174 if (streq(key, "debug") && !value)
1175 log_set_max_level(LOG_DEBUG);
1176
1177 else if (proc_cmdline_key_streq(key, "systemd.log_target")) {
1178
1179 if (proc_cmdline_value_missing(key, value))
1180 return 0;
1181
1182 if (log_set_target_from_string(value) < 0)
1183 log_warning("Failed to parse log target '%s'. Ignoring.", value);
1184
1185 } else if (proc_cmdline_key_streq(key, "systemd.log_level")) {
1186
1187 if (proc_cmdline_value_missing(key, value))
1188 return 0;
1189
1190 if (log_set_max_level_from_string(value) < 0)
1191 log_warning("Failed to parse log level '%s'. Ignoring.", value);
1192
1193 } else if (proc_cmdline_key_streq(key, "systemd.log_color")) {
1194
1195 if (log_show_color_from_string(value ?: "1") < 0)
1196 log_warning("Failed to parse log color setting '%s'. Ignoring.", value);
1197
1198 } else if (proc_cmdline_key_streq(key, "systemd.log_location")) {
1199
1200 if (log_show_location_from_string(value ?: "1") < 0)
1201 log_warning("Failed to parse log location setting '%s'. Ignoring.", value);
1202
1203 } else if (proc_cmdline_key_streq(key, "systemd.log_tid")) {
1204
1205 if (log_show_tid_from_string(value ?: "1") < 0)
1206 log_warning("Failed to parse log tid setting '%s'. Ignoring.", value);
1207
1208 } else if (proc_cmdline_key_streq(key, "systemd.log_time")) {
1209
1210 if (log_show_time_from_string(value ?: "1") < 0)
1211 log_warning("Failed to parse log time setting '%s'. Ignoring.", value);
1212
1213 }
1214
1215 return 0;
1216 }
1217
1218 static bool should_parse_proc_cmdline(void) {
1219 /* PID1 always reads the kernel command line. */
1220 if (getpid_cached() == 1)
1221 return true;
1222
1223 /* Otherwise, parse the commandline if invoked directly by systemd. */
1224 return invoked_by_systemd();
1225 }
1226
1227 void log_parse_environment_variables(void) {
1228 const char *e;
1229
1230 e = getenv("SYSTEMD_LOG_TARGET");
1231 if (e && log_set_target_from_string(e) < 0)
1232 log_warning("Failed to parse log target '%s'. Ignoring.", e);
1233
1234 e = getenv("SYSTEMD_LOG_LEVEL");
1235 if (e && log_set_max_level_from_string(e) < 0)
1236 log_warning("Failed to parse log level '%s'. Ignoring.", e);
1237
1238 e = getenv("SYSTEMD_LOG_COLOR");
1239 if (e && log_show_color_from_string(e) < 0)
1240 log_warning("Failed to parse log color '%s'. Ignoring.", e);
1241
1242 e = getenv("SYSTEMD_LOG_LOCATION");
1243 if (e && log_show_location_from_string(e) < 0)
1244 log_warning("Failed to parse log location '%s'. Ignoring.", e);
1245
1246 e = getenv("SYSTEMD_LOG_TIME");
1247 if (e && log_show_time_from_string(e) < 0)
1248 log_warning("Failed to parse log time '%s'. Ignoring.", e);
1249
1250 e = getenv("SYSTEMD_LOG_TID");
1251 if (e && log_show_tid_from_string(e) < 0)
1252 log_warning("Failed to parse log tid '%s'. Ignoring.", e);
1253 }
1254
1255 void log_parse_environment(void) {
1256 /* Do not call from library code. */
1257
1258 if (should_parse_proc_cmdline())
1259 (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
1260
1261 log_parse_environment_variables();
1262 }
1263
1264 LogTarget log_get_target(void) {
1265 return log_target;
1266 }
1267
1268 int log_get_max_level(void) {
1269 return log_max_level;
1270 }
1271
1272 void log_show_color(bool b) {
1273 show_color = b;
1274 }
1275
1276 bool log_get_show_color(void) {
1277 return show_color > 0; /* Defaults to false. */
1278 }
1279
1280 void log_show_location(bool b) {
1281 show_location = b;
1282 }
1283
1284 bool log_get_show_location(void) {
1285 return show_location;
1286 }
1287
1288 void log_show_time(bool b) {
1289 show_time = b;
1290 }
1291
1292 bool log_get_show_time(void) {
1293 return show_time;
1294 }
1295
1296 void log_show_tid(bool b) {
1297 show_tid = b;
1298 }
1299
1300 bool log_get_show_tid(void) {
1301 return show_tid;
1302 }
1303
1304 int log_show_color_from_string(const char *e) {
1305 int t;
1306
1307 t = parse_boolean(e);
1308 if (t < 0)
1309 return t;
1310
1311 log_show_color(t);
1312 return 0;
1313 }
1314
1315 int log_show_location_from_string(const char *e) {
1316 int t;
1317
1318 t = parse_boolean(e);
1319 if (t < 0)
1320 return t;
1321
1322 log_show_location(t);
1323 return 0;
1324 }
1325
1326 int log_show_time_from_string(const char *e) {
1327 int t;
1328
1329 t = parse_boolean(e);
1330 if (t < 0)
1331 return t;
1332
1333 log_show_time(t);
1334 return 0;
1335 }
1336
1337 int log_show_tid_from_string(const char *e) {
1338 int t;
1339
1340 t = parse_boolean(e);
1341 if (t < 0)
1342 return t;
1343
1344 log_show_tid(t);
1345 return 0;
1346 }
1347
1348 bool log_on_console(void) {
1349 if (IN_SET(log_target, LOG_TARGET_CONSOLE,
1350 LOG_TARGET_CONSOLE_PREFIXED))
1351 return true;
1352
1353 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
1354 }
1355
1356 static const char *const log_target_table[_LOG_TARGET_MAX] = {
1357 [LOG_TARGET_CONSOLE] = "console",
1358 [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed",
1359 [LOG_TARGET_KMSG] = "kmsg",
1360 [LOG_TARGET_JOURNAL] = "journal",
1361 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
1362 [LOG_TARGET_SYSLOG] = "syslog",
1363 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
1364 [LOG_TARGET_AUTO] = "auto",
1365 [LOG_TARGET_NULL] = "null",
1366 };
1367
1368 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);
1369
1370 void log_received_signal(int level, const struct signalfd_siginfo *si) {
1371 assert(si);
1372
1373 if (pid_is_valid(si->ssi_pid)) {
1374 _cleanup_free_ char *p = NULL;
1375
1376 (void) get_process_comm(si->ssi_pid, &p);
1377
1378 log_full(level,
1379 "Received SIG%s from PID %"PRIu32" (%s).",
1380 signal_to_string(si->ssi_signo),
1381 si->ssi_pid, strna(p));
1382 } else
1383 log_full(level,
1384 "Received SIG%s.",
1385 signal_to_string(si->ssi_signo));
1386 }
1387
1388 void set_log_syntax_callback(log_syntax_callback_t cb, void *userdata) {
1389 assert(!log_syntax_callback || !cb);
1390 assert(!log_syntax_callback_userdata || !userdata);
1391
1392 log_syntax_callback = cb;
1393 log_syntax_callback_userdata = userdata;
1394 }
1395
1396 int log_syntax_internal(
1397 const char *unit,
1398 int level,
1399 const char *config_file,
1400 unsigned config_line,
1401 int error,
1402 const char *file,
1403 int line,
1404 const char *func,
1405 const char *format, ...) {
1406
1407 PROTECT_ERRNO;
1408
1409 if (log_syntax_callback)
1410 log_syntax_callback(unit, level, log_syntax_callback_userdata);
1411
1412 if (_likely_(LOG_PRI(level) > log_max_level) ||
1413 log_target == LOG_TARGET_NULL)
1414 return -ERRNO_VALUE(error);
1415
1416 char buffer[LINE_MAX];
1417 va_list ap;
1418 const char *unit_fmt = NULL;
1419
1420 errno = ERRNO_VALUE(error);
1421
1422 va_start(ap, format);
1423 (void) vsnprintf(buffer, sizeof buffer, format, ap);
1424 va_end(ap);
1425
1426 if (unit)
1427 unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1428
1429 if (config_file) {
1430 if (config_line > 0)
1431 return log_struct_internal(
1432 level,
1433 error,
1434 file, line, func,
1435 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1436 "CONFIG_FILE=%s", config_file,
1437 "CONFIG_LINE=%u", config_line,
1438 LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
1439 unit_fmt, unit,
1440 NULL);
1441 else
1442 return log_struct_internal(
1443 level,
1444 error,
1445 file, line, func,
1446 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1447 "CONFIG_FILE=%s", config_file,
1448 LOG_MESSAGE("%s: %s", config_file, buffer),
1449 unit_fmt, unit,
1450 NULL);
1451 } else if (unit)
1452 return log_struct_internal(
1453 level,
1454 error,
1455 file, line, func,
1456 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1457 LOG_MESSAGE("%s: %s", unit, buffer),
1458 unit_fmt, unit,
1459 NULL);
1460 else
1461 return log_struct_internal(
1462 level,
1463 error,
1464 file, line, func,
1465 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
1466 LOG_MESSAGE("%s", buffer),
1467 NULL);
1468 }
1469
1470 int log_syntax_invalid_utf8_internal(
1471 const char *unit,
1472 int level,
1473 const char *config_file,
1474 unsigned config_line,
1475 const char *file,
1476 int line,
1477 const char *func,
1478 const char *rvalue) {
1479
1480 _cleanup_free_ char *p = NULL;
1481
1482 if (rvalue)
1483 p = utf8_escape_invalid(rvalue);
1484
1485 return log_syntax_internal(unit, level, config_file, config_line,
1486 SYNTHETIC_ERRNO(EINVAL), file, line, func,
1487 "String is not UTF-8 clean, ignoring assignment: %s", strna(p));
1488 }
1489
1490 void log_set_upgrade_syslog_to_journal(bool b) {
1491 upgrade_syslog_to_journal = b;
1492
1493 /* Make the change effective immediately */
1494 if (b) {
1495 if (log_target == LOG_TARGET_SYSLOG)
1496 log_target = LOG_TARGET_JOURNAL;
1497 else if (log_target == LOG_TARGET_SYSLOG_OR_KMSG)
1498 log_target = LOG_TARGET_JOURNAL_OR_KMSG;
1499 }
1500 }
1501
1502 void log_set_always_reopen_console(bool b) {
1503 always_reopen_console = b;
1504 }
1505
1506 void log_set_open_when_needed(bool b) {
1507 open_when_needed = b;
1508 }
1509
1510 void log_set_prohibit_ipc(bool b) {
1511 prohibit_ipc = b;
1512 }
1513
1514 int log_emergency_level(void) {
1515 /* Returns the log level to use for log_emergency() logging. We use LOG_EMERG only when we are PID 1, as only
1516 * then the system of the whole system is obviously affected. */
1517
1518 return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
1519 }
1520
1521 int log_dup_console(void) {
1522 int copy;
1523
1524 /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
1525 * whenever we want to continue logging through the original fd, but want to rearrange stderr. */
1526
1527 if (console_fd < 0 || console_fd >= 3)
1528 return 0;
1529
1530 copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3);
1531 if (copy < 0)
1532 return -errno;
1533
1534 console_fd = copy;
1535 return 0;
1536 }
1537
1538 void log_setup(void) {
1539 log_set_target(LOG_TARGET_AUTO);
1540 log_parse_environment();
1541 (void) log_open();
1542 if (log_on_console() && show_color < 0)
1543 log_show_color(true);
1544 }
1545
1546 static int saved_log_context_enabled = -1;
1547
1548 bool log_context_enabled(void) {
1549 int r;
1550
1551 if (log_get_max_level() == LOG_DEBUG)
1552 return true;
1553
1554 if (saved_log_context_enabled >= 0)
1555 return saved_log_context_enabled;
1556
1557 r = getenv_bool_secure("SYSTEMD_ENABLE_LOG_CONTEXT");
1558 if (r < 0 && r != -ENXIO)
1559 log_debug_errno(r, "Failed to parse $SYSTEMD_ENABLE_LOG_CONTEXT, ignoring: %m");
1560
1561 saved_log_context_enabled = r > 0;
1562
1563 return saved_log_context_enabled;
1564 }
1565
1566 static LogContext* log_context_attach(LogContext *c) {
1567 assert(c);
1568
1569 _log_context_num_fields += strv_length(c->fields);
1570 _log_context_num_fields += c->n_input_iovec;
1571
1572 return LIST_PREPEND(ll, _log_context, c);
1573 }
1574
1575 static LogContext* log_context_detach(LogContext *c) {
1576 if (!c)
1577 return NULL;
1578
1579 assert(_log_context_num_fields >= strv_length(c->fields) + c->n_input_iovec);
1580 _log_context_num_fields -= strv_length(c->fields);
1581 _log_context_num_fields -= c->n_input_iovec;
1582
1583 LIST_REMOVE(ll, _log_context, c);
1584 return NULL;
1585 }
1586
1587 LogContext* log_context_new(char **fields, bool owned) {
1588 if (!fields)
1589 return NULL;
1590
1591 LIST_FOREACH(ll, i, _log_context)
1592 if (i->fields == fields) {
1593 assert(!owned);
1594 return log_context_ref(i);
1595 }
1596
1597 LogContext *c = new(LogContext, 1);
1598 if (!c)
1599 return NULL;
1600
1601 *c = (LogContext) {
1602 .n_ref = 1,
1603 .fields = fields,
1604 .owned = owned,
1605 };
1606
1607 return log_context_attach(c);
1608 }
1609
1610 LogContext* log_context_newv(struct iovec *input_iovec, size_t n_input_iovec, bool owned) {
1611 if (!input_iovec || n_input_iovec == 0)
1612 return NULL;
1613
1614 LIST_FOREACH(ll, i, _log_context)
1615 if (i->input_iovec == input_iovec && i->n_input_iovec == n_input_iovec) {
1616 assert(!owned);
1617 return log_context_ref(i);
1618 }
1619
1620 LogContext *c = new(LogContext, 1);
1621 if (!c)
1622 return NULL;
1623
1624 *c = (LogContext) {
1625 .n_ref = 1,
1626 .input_iovec = input_iovec,
1627 .n_input_iovec = n_input_iovec,
1628 .owned = owned,
1629 };
1630
1631 return log_context_attach(c);
1632 }
1633
1634 static LogContext* log_context_free(LogContext *c) {
1635 if (!c)
1636 return NULL;
1637
1638 log_context_detach(c);
1639
1640 if (c->owned) {
1641 strv_free(c->fields);
1642 iovec_array_free(c->input_iovec, c->n_input_iovec);
1643 }
1644
1645 return mfree(c);
1646 }
1647
1648 DEFINE_TRIVIAL_REF_UNREF_FUNC(LogContext, log_context, log_context_free);
1649
1650 LogContext* log_context_new_consume(char **fields) {
1651 LogContext *c = log_context_new(fields, /*owned=*/ true);
1652 if (!c)
1653 strv_free(fields);
1654
1655 return c;
1656 }
1657
1658 LogContext* log_context_new_consumev(struct iovec *input_iovec, size_t n_input_iovec) {
1659 LogContext *c = log_context_newv(input_iovec, n_input_iovec, /*owned=*/ true);
1660 if (!c)
1661 iovec_array_free(input_iovec, n_input_iovec);
1662
1663 return c;
1664 }
1665
1666 size_t log_context_num_contexts(void) {
1667 size_t n = 0;
1668
1669 LIST_FOREACH(ll, c, _log_context)
1670 n++;
1671
1672 return n;
1673 }
1674
1675 size_t log_context_num_fields(void) {
1676 return _log_context_num_fields;
1677 }