]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/log.c
strv: multiple cleanups
[thirdparty/systemd.git] / src / shared / log.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29 #include <stddef.h>
30 #include <printf.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "missing.h"
35 #include "macro.h"
36 #include "socket-util.h"
37
38 #define SNDBUF_SIZE (8*1024*1024)
39
40 static LogTarget log_target = LOG_TARGET_CONSOLE;
41 static int log_max_level = LOG_INFO;
42 static int log_facility = LOG_DAEMON;
43
44 static int console_fd = STDERR_FILENO;
45 static int syslog_fd = -1;
46 static int kmsg_fd = -1;
47 static int journal_fd = -1;
48
49 static bool syslog_is_stream = false;
50
51 static bool show_color = false;
52 static bool show_location = false;
53
54 /* Akin to glibc's __abort_msg; which is private and we hence cannot
55 * use here. */
56 static char *log_abort_msg = NULL;
57
58 void log_close_console(void) {
59
60 if (console_fd < 0)
61 return;
62
63 if (getpid() == 1) {
64 if (console_fd >= 3)
65 close_nointr_nofail(console_fd);
66
67 console_fd = -1;
68 }
69 }
70
71 static int log_open_console(void) {
72
73 if (console_fd >= 0)
74 return 0;
75
76 if (getpid() == 1) {
77 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
78 if (console_fd < 0)
79 return console_fd;
80 } else
81 console_fd = STDERR_FILENO;
82
83 return 0;
84 }
85
86 void log_close_kmsg(void) {
87
88 if (kmsg_fd < 0)
89 return;
90
91 close_nointr_nofail(kmsg_fd);
92 kmsg_fd = -1;
93 }
94
95 static int log_open_kmsg(void) {
96
97 if (kmsg_fd >= 0)
98 return 0;
99
100 kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
101 if (kmsg_fd < 0)
102 return -errno;
103
104 return 0;
105 }
106
107 void log_close_syslog(void) {
108
109 if (syslog_fd < 0)
110 return;
111
112 close_nointr_nofail(syslog_fd);
113 syslog_fd = -1;
114 }
115
116 static int create_log_socket(int type) {
117 int fd;
118 struct timeval tv;
119
120 fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
121 if (fd < 0)
122 return -errno;
123
124 fd_inc_sndbuf(fd, SNDBUF_SIZE);
125
126 /* We need a blocking fd here since we'd otherwise lose
127 messages way too early. However, let's not hang forever in the
128 unlikely case of a deadlock. */
129 if (getpid() == 1)
130 timeval_store(&tv, 10 * USEC_PER_MSEC);
131 else
132 timeval_store(&tv, 10 * USEC_PER_SEC);
133 setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
134
135 return fd;
136 }
137
138 static int log_open_syslog(void) {
139 int r;
140 union sockaddr_union sa = {
141 .un.sun_family = AF_UNIX,
142 .un.sun_path = "/dev/log",
143 };
144
145 if (syslog_fd >= 0)
146 return 0;
147
148 syslog_fd = create_log_socket(SOCK_DGRAM);
149 if (syslog_fd < 0) {
150 r = syslog_fd;
151 goto fail;
152 }
153
154 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
155 close_nointr_nofail(syslog_fd);
156
157 /* Some legacy syslog systems still use stream
158 * sockets. They really shouldn't. But what can we
159 * do... */
160 syslog_fd = create_log_socket(SOCK_STREAM);
161 if (syslog_fd < 0) {
162 r = syslog_fd;
163 goto fail;
164 }
165
166 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
167 r = -errno;
168 goto fail;
169 }
170
171 syslog_is_stream = true;
172 } else
173 syslog_is_stream = false;
174
175 return 0;
176
177 fail:
178 log_close_syslog();
179 return r;
180 }
181
182 void log_close_journal(void) {
183
184 if (journal_fd < 0)
185 return;
186
187 close_nointr_nofail(journal_fd);
188 journal_fd = -1;
189 }
190
191 static int log_open_journal(void) {
192 union sockaddr_union sa = {
193 .un.sun_family = AF_UNIX,
194 .un.sun_path = "/run/systemd/journal/socket",
195 };
196 int r;
197
198 if (journal_fd >= 0)
199 return 0;
200
201 journal_fd = create_log_socket(SOCK_DGRAM);
202 if (journal_fd < 0) {
203 r = journal_fd;
204 goto fail;
205 }
206
207 if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
208 r = -errno;
209 goto fail;
210 }
211
212 return 0;
213
214 fail:
215 log_close_journal();
216 return r;
217 }
218
219 int log_open(void) {
220 int r;
221
222 /* If we don't use the console we close it here, to not get
223 * killed by SAK. If we don't use syslog we close it here so
224 * that we are not confused by somebody deleting the socket in
225 * the fs. If we don't use /dev/kmsg we still keep it open,
226 * because there is no reason to close it. */
227
228 if (log_target == LOG_TARGET_NULL) {
229 log_close_journal();
230 log_close_syslog();
231 log_close_console();
232 return 0;
233 }
234
235 if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
236 getpid() == 1 ||
237 isatty(STDERR_FILENO) <= 0) {
238
239 if (log_target == LOG_TARGET_AUTO ||
240 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
241 log_target == LOG_TARGET_JOURNAL) {
242 r = log_open_journal();
243 if (r >= 0) {
244 log_close_syslog();
245 log_close_console();
246 return r;
247 }
248 }
249
250 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
251 log_target == LOG_TARGET_SYSLOG) {
252 r = log_open_syslog();
253 if (r >= 0) {
254 log_close_journal();
255 log_close_console();
256 return r;
257 }
258 }
259
260 if (log_target == LOG_TARGET_AUTO ||
261 log_target == LOG_TARGET_SAFE ||
262 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
263 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
264 log_target == LOG_TARGET_KMSG) {
265 r = log_open_kmsg();
266 if (r >= 0) {
267 log_close_journal();
268 log_close_syslog();
269 log_close_console();
270 return r;
271 }
272 }
273 }
274
275 log_close_journal();
276 log_close_syslog();
277
278 return log_open_console();
279 }
280
281 void log_set_target(LogTarget target) {
282 assert(target >= 0);
283 assert(target < _LOG_TARGET_MAX);
284
285 log_target = target;
286 }
287
288 void log_close(void) {
289 log_close_journal();
290 log_close_syslog();
291 log_close_kmsg();
292 log_close_console();
293 }
294
295 void log_forget_fds(void) {
296 console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
297 }
298
299 void log_set_max_level(int level) {
300 assert((level & LOG_PRIMASK) == level);
301
302 log_max_level = level;
303 }
304
305 void log_set_facility(int facility) {
306 log_facility = facility;
307 }
308
309 static int write_to_console(
310 int level,
311 const char*file,
312 int line,
313 const char *func,
314 const char *object_name,
315 const char *object,
316 const char *buffer) {
317
318 char location[64];
319 struct iovec iovec[5] = {};
320 unsigned n = 0;
321 bool highlight;
322
323 if (console_fd < 0)
324 return 0;
325
326 highlight = LOG_PRI(level) <= LOG_ERR && show_color;
327
328 if (show_location) {
329 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
330 char_array_0(location);
331 IOVEC_SET_STRING(iovec[n++], location);
332 }
333
334 if (highlight)
335 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
336 IOVEC_SET_STRING(iovec[n++], buffer);
337 if (highlight)
338 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
339 IOVEC_SET_STRING(iovec[n++], "\n");
340
341 if (writev(console_fd, iovec, n) < 0) {
342
343 if (errno == EIO && getpid() == 1) {
344
345 /* If somebody tried to kick us from our
346 * console tty (via vhangup() or suchlike),
347 * try to reconnect */
348
349 log_close_console();
350 log_open_console();
351
352 if (console_fd < 0)
353 return 0;
354
355 if (writev(console_fd, iovec, n) < 0)
356 return -errno;
357 } else
358 return -errno;
359 }
360
361 return 1;
362 }
363
364 static int write_to_syslog(
365 int level,
366 const char*file,
367 int line,
368 const char *func,
369 const char *object_name,
370 const char *object,
371 const char *buffer) {
372
373 char header_priority[16], header_time[64], header_pid[16];
374 struct iovec iovec[5] = {};
375 struct msghdr msghdr = {
376 .msg_iov = iovec,
377 .msg_iovlen = ELEMENTSOF(iovec),
378 };
379 time_t t;
380 struct tm *tm;
381
382 if (syslog_fd < 0)
383 return 0;
384
385 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
386 char_array_0(header_priority);
387
388 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
389 tm = localtime(&t);
390 if (!tm)
391 return -EINVAL;
392
393 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
394 return -EINVAL;
395
396 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
397 char_array_0(header_pid);
398
399 IOVEC_SET_STRING(iovec[0], header_priority);
400 IOVEC_SET_STRING(iovec[1], header_time);
401 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
402 IOVEC_SET_STRING(iovec[3], header_pid);
403 IOVEC_SET_STRING(iovec[4], buffer);
404
405 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
406 if (syslog_is_stream)
407 iovec[4].iov_len++;
408
409 for (;;) {
410 ssize_t n;
411
412 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
413 if (n < 0)
414 return -errno;
415
416 if (!syslog_is_stream ||
417 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
418 break;
419
420 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
421 }
422
423 return 1;
424 }
425
426 static int write_to_kmsg(
427 int level,
428 const char*file,
429 int line,
430 const char *func,
431 const char *object_name,
432 const char *object,
433 const char *buffer) {
434
435 char header_priority[16], header_pid[16];
436 struct iovec iovec[5] = {};
437
438 if (kmsg_fd < 0)
439 return 0;
440
441 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
442 char_array_0(header_priority);
443
444 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
445 char_array_0(header_pid);
446
447 IOVEC_SET_STRING(iovec[0], header_priority);
448 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
449 IOVEC_SET_STRING(iovec[2], header_pid);
450 IOVEC_SET_STRING(iovec[3], buffer);
451 IOVEC_SET_STRING(iovec[4], "\n");
452
453 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
454 return -errno;
455
456 return 1;
457 }
458
459 static int log_do_header(char *header, size_t size,
460 int level,
461 const char *file, int line, const char *func,
462 const char *object_name, const char *object) {
463 snprintf(header, size,
464 "PRIORITY=%i\n"
465 "SYSLOG_FACILITY=%i\n"
466 "%s%.*s%s"
467 "%s%.*i%s"
468 "%s%.*s%s"
469 "%s%.*s%s"
470 "SYSLOG_IDENTIFIER=%s\n",
471 LOG_PRI(level),
472 LOG_FAC(level),
473 file ? "CODE_FILE=" : "",
474 file ? LINE_MAX : 0, file, /* %.0s means no output */
475 file ? "\n" : "",
476 line ? "CODE_LINE=" : "",
477 line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
478 line ? "\n" : "",
479 func ? "CODE_FUNCTION=" : "",
480 func ? LINE_MAX : 0, func,
481 func ? "\n" : "",
482 object ? object_name : "",
483 object ? LINE_MAX : 0, object, /* %.0s means no output */
484 object ? "\n" : "",
485 program_invocation_short_name);
486 header[size - 1] = '\0';
487 return 0;
488 }
489
490 static int write_to_journal(
491 int level,
492 const char*file,
493 int line,
494 const char *func,
495 const char *object_name,
496 const char *object,
497 const char *buffer) {
498
499 char header[LINE_MAX];
500 struct iovec iovec[4] = {};
501 struct msghdr mh = {};
502
503 if (journal_fd < 0)
504 return 0;
505
506 log_do_header(header, sizeof(header), level,
507 file, line, func, object_name, object);
508
509 IOVEC_SET_STRING(iovec[0], header);
510 IOVEC_SET_STRING(iovec[1], "MESSAGE=");
511 IOVEC_SET_STRING(iovec[2], buffer);
512 IOVEC_SET_STRING(iovec[3], "\n");
513
514 mh.msg_iov = iovec;
515 mh.msg_iovlen = ELEMENTSOF(iovec);
516
517 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
518 return -errno;
519
520 return 1;
521 }
522
523 static int log_dispatch(
524 int level,
525 const char*file,
526 int line,
527 const char *func,
528 const char *object_name,
529 const char *object,
530 char *buffer) {
531
532 int r = 0;
533
534 if (log_target == LOG_TARGET_NULL)
535 return 0;
536
537 /* Patch in LOG_DAEMON facility if necessary */
538 if ((level & LOG_FACMASK) == 0)
539 level = log_facility | LOG_PRI(level);
540
541 do {
542 char *e;
543 int k = 0;
544
545 buffer += strspn(buffer, NEWLINE);
546
547 if (buffer[0] == 0)
548 break;
549
550 if ((e = strpbrk(buffer, NEWLINE)))
551 *(e++) = 0;
552
553 if (log_target == LOG_TARGET_AUTO ||
554 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
555 log_target == LOG_TARGET_JOURNAL) {
556
557 k = write_to_journal(level, file, line, func,
558 object_name, object, buffer);
559 if (k < 0) {
560 if (k != -EAGAIN)
561 log_close_journal();
562 log_open_kmsg();
563 } else if (k > 0)
564 r++;
565 }
566
567 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
568 log_target == LOG_TARGET_SYSLOG) {
569
570 k = write_to_syslog(level, file, line, func,
571 object_name, object, buffer);
572 if (k < 0) {
573 if (k != -EAGAIN)
574 log_close_syslog();
575 log_open_kmsg();
576 } else if (k > 0)
577 r++;
578 }
579
580 if (k <= 0 &&
581 (log_target == LOG_TARGET_AUTO ||
582 log_target == LOG_TARGET_SAFE ||
583 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
584 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
585 log_target == LOG_TARGET_KMSG)) {
586
587 k = write_to_kmsg(level, file, line, func,
588 object_name, object, buffer);
589 if (k < 0) {
590 log_close_kmsg();
591 log_open_console();
592 } else if (k > 0)
593 r++;
594 }
595
596 if (k <= 0) {
597 k = write_to_console(level, file, line, func,
598 object_name, object, buffer);
599 if (k < 0)
600 return k;
601 }
602
603 buffer = e;
604 } while (buffer);
605
606 return r;
607 }
608
609 int log_dump_internal(
610 int level,
611 const char*file,
612 int line,
613 const char *func,
614 char *buffer) {
615
616 PROTECT_ERRNO;
617
618 /* This modifies the buffer... */
619
620 if (_likely_(LOG_PRI(level) > log_max_level))
621 return 0;
622
623 return log_dispatch(level, file, line, func, NULL, NULL, buffer);
624 }
625
626 int log_metav(
627 int level,
628 const char*file,
629 int line,
630 const char *func,
631 const char *format,
632 va_list ap) {
633
634 PROTECT_ERRNO;
635 char buffer[LINE_MAX];
636
637 if (_likely_(LOG_PRI(level) > log_max_level))
638 return 0;
639
640 vsnprintf(buffer, sizeof(buffer), format, ap);
641 char_array_0(buffer);
642
643 return log_dispatch(level, file, line, func, NULL, NULL, buffer);
644 }
645
646 int log_meta(
647 int level,
648 const char*file,
649 int line,
650 const char *func,
651 const char *format, ...) {
652
653 int r;
654 va_list ap;
655
656 va_start(ap, format);
657 r = log_metav(level, file, line, func, format, ap);
658 va_end(ap);
659
660 return r;
661 }
662
663 int log_metav_object(
664 int level,
665 const char*file,
666 int line,
667 const char *func,
668 const char *object_name,
669 const char *object,
670 const char *format,
671 va_list ap) {
672
673 PROTECT_ERRNO;
674 char buffer[LINE_MAX];
675
676 if (_likely_(LOG_PRI(level) > log_max_level))
677 return 0;
678
679 vsnprintf(buffer, sizeof(buffer), format, ap);
680 char_array_0(buffer);
681
682 return log_dispatch(level, file, line, func,
683 object_name, object, buffer);
684 }
685
686 int log_meta_object(
687 int level,
688 const char*file,
689 int line,
690 const char *func,
691 const char *object_name,
692 const char *object,
693 const char *format, ...) {
694
695 int r;
696 va_list ap;
697
698 va_start(ap, format);
699 r = log_metav_object(level, file, line, func,
700 object_name, object, format, ap);
701 va_end(ap);
702
703 return r;
704 }
705
706 #pragma GCC diagnostic push
707 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
708 static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) {
709 static char buffer[LINE_MAX];
710
711 if (_likely_(LOG_PRI(level) > log_max_level))
712 return;
713
714 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
715
716 char_array_0(buffer);
717 log_abort_msg = buffer;
718
719 log_dispatch(level, file, line, func, NULL, NULL, buffer);
720 }
721 #pragma GCC diagnostic pop
722
723 noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
724 log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
725 abort();
726 }
727
728 noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
729 log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
730 abort();
731 }
732
733 void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
734 PROTECT_ERRNO;
735 log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
736 }
737
738 int log_oom_internal(const char *file, int line, const char *func) {
739 log_meta(LOG_ERR, file, line, func, "Out of memory.");
740 return -ENOMEM;
741 }
742
743 int log_struct_internal(
744 int level,
745 const char *file,
746 int line,
747 const char *func,
748 const char *format, ...) {
749
750 PROTECT_ERRNO;
751 va_list ap;
752 int r;
753
754 if (_likely_(LOG_PRI(level) > log_max_level))
755 return 0;
756
757 if (log_target == LOG_TARGET_NULL)
758 return 0;
759
760 if ((level & LOG_FACMASK) == 0)
761 level = log_facility | LOG_PRI(level);
762
763 if ((log_target == LOG_TARGET_AUTO ||
764 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
765 log_target == LOG_TARGET_JOURNAL) &&
766 journal_fd >= 0) {
767
768 char header[LINE_MAX];
769 struct iovec iovec[17] = {};
770 unsigned n = 0, i;
771 struct msghdr mh = {
772 .msg_iov = iovec,
773 };
774 static const char nl = '\n';
775
776 /* If the journal is available do structured logging */
777 log_do_header(header, sizeof(header), level,
778 file, line, func, NULL, NULL);
779 IOVEC_SET_STRING(iovec[n++], header);
780
781 va_start(ap, format);
782 while (format && n + 1 < ELEMENTSOF(iovec)) {
783 char *buf;
784 va_list aq;
785
786 /* We need to copy the va_list structure,
787 * since vasprintf() leaves it afterwards at
788 * an undefined location */
789
790 va_copy(aq, ap);
791 if (vasprintf(&buf, format, aq) < 0) {
792 va_end(aq);
793 r = -ENOMEM;
794 goto finish;
795 }
796 va_end(aq);
797
798 /* Now, jump enough ahead, so that we point to
799 * the next format string */
800 VA_FORMAT_ADVANCE(format, ap);
801
802 IOVEC_SET_STRING(iovec[n++], buf);
803
804 iovec[n].iov_base = (char*) &nl;
805 iovec[n].iov_len = 1;
806 n++;
807
808 format = va_arg(ap, char *);
809 }
810
811 mh.msg_iovlen = n;
812
813 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
814 r = -errno;
815 else
816 r = 1;
817
818 finish:
819 va_end(ap);
820 for (i = 1; i < n; i += 2)
821 free(iovec[i].iov_base);
822
823 } else {
824 char buf[LINE_MAX];
825 bool found = false;
826
827 /* Fallback if journal logging is not available */
828
829 va_start(ap, format);
830 while (format) {
831 va_list aq;
832
833 va_copy(aq, ap);
834 vsnprintf(buf, sizeof(buf), format, aq);
835 va_end(aq);
836 char_array_0(buf);
837
838 if (startswith(buf, "MESSAGE=")) {
839 found = true;
840 break;
841 }
842
843 VA_FORMAT_ADVANCE(format, ap);
844
845 format = va_arg(ap, char *);
846 }
847 va_end(ap);
848
849 if (found)
850 r = log_dispatch(level, file, line, func,
851 NULL, NULL, buf + 8);
852 else
853 r = -EINVAL;
854 }
855
856 return r;
857 }
858
859 int log_set_target_from_string(const char *e) {
860 LogTarget t;
861
862 t = log_target_from_string(e);
863 if (t < 0)
864 return -EINVAL;
865
866 log_set_target(t);
867 return 0;
868 }
869
870 int log_set_max_level_from_string(const char *e) {
871 int t;
872
873 t = log_level_from_string(e);
874 if (t < 0)
875 return t;
876
877 log_set_max_level(t);
878 return 0;
879 }
880
881 void log_parse_environment(void) {
882 _cleanup_free_ char *line = NULL;
883 const char *e;
884 int r;
885
886 r = proc_cmdline(&line);
887 if (r < 0)
888 log_warning("Failed to read /proc/cmdline. Ignoring: %s", strerror(-r));
889 else if (r > 0) {
890 char *w, *state;
891 size_t l;
892
893 FOREACH_WORD_QUOTED(w, l, line, state) {
894 if (l == 5 && startswith(w, "debug")) {
895 log_set_max_level(LOG_DEBUG);
896 break;
897 }
898 }
899 }
900
901 e = secure_getenv("SYSTEMD_LOG_TARGET");
902 if (e && log_set_target_from_string(e) < 0)
903 log_warning("Failed to parse log target %s. Ignoring.", e);
904
905 e = secure_getenv("SYSTEMD_LOG_LEVEL");
906 if (e && log_set_max_level_from_string(e) < 0)
907 log_warning("Failed to parse log level %s. Ignoring.", e);
908
909 e = secure_getenv("SYSTEMD_LOG_COLOR");
910 if (e && log_show_color_from_string(e) < 0)
911 log_warning("Failed to parse bool %s. Ignoring.", e);
912
913 e = secure_getenv("SYSTEMD_LOG_LOCATION");
914 if (e && log_show_location_from_string(e) < 0)
915 log_warning("Failed to parse bool %s. Ignoring.", e);
916 }
917
918 LogTarget log_get_target(void) {
919 return log_target;
920 }
921
922 int log_get_max_level(void) {
923 return log_max_level;
924 }
925
926 void log_show_color(bool b) {
927 show_color = b;
928 }
929
930 void log_show_location(bool b) {
931 show_location = b;
932 }
933
934 int log_show_color_from_string(const char *e) {
935 int t;
936
937 t = parse_boolean(e);
938 if (t < 0)
939 return t;
940
941 log_show_color(t);
942 return 0;
943 }
944
945 int log_show_location_from_string(const char *e) {
946 int t;
947
948 t = parse_boolean(e);
949 if (t < 0)
950 return t;
951
952 log_show_location(t);
953 return 0;
954 }
955
956 bool log_on_console(void) {
957 if (log_target == LOG_TARGET_CONSOLE)
958 return true;
959
960 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
961 }
962
963 static const char *const log_target_table[] = {
964 [LOG_TARGET_CONSOLE] = "console",
965 [LOG_TARGET_KMSG] = "kmsg",
966 [LOG_TARGET_JOURNAL] = "journal",
967 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
968 [LOG_TARGET_SYSLOG] = "syslog",
969 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
970 [LOG_TARGET_AUTO] = "auto",
971 [LOG_TARGET_SAFE] = "safe",
972 [LOG_TARGET_NULL] = "null"
973 };
974
975 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);