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