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