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