1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
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.
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.
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/>.
27 #include <sys/socket.h>
35 #include "socket-util.h"
37 #define SNDBUF_SIZE (8*1024*1024)
39 static LogTarget log_target = LOG_TARGET_CONSOLE;
40 static int log_max_level = LOG_INFO;
41 static int log_facility = LOG_DAEMON;
43 static int console_fd = STDERR_FILENO;
44 static int syslog_fd = -1;
45 static int kmsg_fd = -1;
46 static int journal_fd = -1;
48 static bool syslog_is_stream = false;
50 static bool show_color = false;
51 static bool show_location = false;
53 /* Akin to glibc's __abort_msg; which is private and we hence cannot
55 static char *log_abort_msg = NULL;
57 void log_close_console(void) {
64 close_nointr_nofail(console_fd);
70 static int log_open_console(void) {
77 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
79 log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
83 log_debug("Successfully opened /dev/console for logging.");
85 console_fd = STDERR_FILENO;
90 void log_close_kmsg(void) {
95 close_nointr_nofail(kmsg_fd);
99 static int log_open_kmsg(void) {
104 kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
106 log_error("Failed to open /dev/kmsg for logging: %s", strerror(errno));
110 log_debug("Successfully opened /dev/kmsg for logging.");
115 void log_close_syslog(void) {
120 close_nointr_nofail(syslog_fd);
124 static int create_log_socket(int type) {
127 /* All output to the syslog/journal fds we do asynchronously,
128 * and if the buffers are full we just drop the messages */
130 fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
134 fd_inc_sndbuf(fd, SNDBUF_SIZE);
139 static int log_open_syslog(void) {
140 union sockaddr_union sa;
147 sa.un.sun_family = AF_UNIX;
148 strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
150 syslog_fd = create_log_socket(SOCK_DGRAM);
156 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
157 close_nointr_nofail(syslog_fd);
159 /* Some legacy syslog systems still use stream
160 * sockets. They really shouldn't. But what can we
162 syslog_fd = create_log_socket(SOCK_STREAM);
168 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
173 syslog_is_stream = true;
175 syslog_is_stream = false;
177 log_debug("Successfully opened syslog for logging.");
183 log_debug("Failed to open syslog for logging: %s", strerror(-r));
187 void log_close_journal(void) {
192 close_nointr_nofail(journal_fd);
196 static int log_open_journal(void) {
197 union sockaddr_union sa;
203 journal_fd = create_log_socket(SOCK_DGRAM);
204 if (journal_fd < 0) {
210 sa.un.sun_family = AF_UNIX;
211 strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
213 if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
218 log_debug("Successfully opened journal for logging.");
224 log_debug("Failed to open journal for logging: %s", strerror(-r));
231 /* If we don't use the console we close it here, to not get
232 * killed by SAK. If we don't use syslog we close it here so
233 * that we are not confused by somebody deleting the socket in
234 * the fs. If we don't use /dev/kmsg we still keep it open,
235 * because there is no reason to close it. */
237 if (log_target == LOG_TARGET_NULL) {
244 if ((log_target != LOG_TARGET_AUTO && log_target != LOG_TARGET_SAFE) ||
246 isatty(STDERR_FILENO) <= 0) {
248 if (log_target == LOG_TARGET_AUTO ||
249 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
250 log_target == LOG_TARGET_JOURNAL) {
251 r = log_open_journal();
259 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
260 log_target == LOG_TARGET_SYSLOG) {
261 r = log_open_syslog();
269 if (log_target == LOG_TARGET_AUTO ||
270 log_target == LOG_TARGET_SAFE ||
271 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
272 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
273 log_target == LOG_TARGET_KMSG) {
287 /* Get the real /dev/console if we are PID=1, hence reopen */
289 return log_open_console();
292 void log_set_target(LogTarget target) {
294 assert(target < _LOG_TARGET_MAX);
299 void log_close(void) {
306 void log_forget_fds(void) {
307 console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
310 void log_set_max_level(int level) {
311 assert((level & LOG_PRIMASK) == level);
313 log_max_level = level;
316 void log_set_facility(int facility) {
317 log_facility = facility;
320 static int write_to_console(
325 const char *buffer) {
328 struct iovec iovec[5];
335 highlight = LOG_PRI(level) <= LOG_ERR && show_color;
340 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
341 char_array_0(location);
342 IOVEC_SET_STRING(iovec[n++], location);
346 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
347 IOVEC_SET_STRING(iovec[n++], buffer);
349 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
350 IOVEC_SET_STRING(iovec[n++], "\n");
352 if (writev(console_fd, iovec, n) < 0)
358 static int write_to_syslog(
363 const char *buffer) {
365 char header_priority[16], header_time[64], header_pid[16];
366 struct iovec iovec[5];
367 struct msghdr msghdr;
374 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
375 char_array_0(header_priority);
377 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
378 if (!(tm = localtime(&t)))
381 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
384 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
385 char_array_0(header_pid);
388 IOVEC_SET_STRING(iovec[0], header_priority);
389 IOVEC_SET_STRING(iovec[1], header_time);
390 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
391 IOVEC_SET_STRING(iovec[3], header_pid);
392 IOVEC_SET_STRING(iovec[4], buffer);
394 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
395 if (syslog_is_stream)
399 msghdr.msg_iov = iovec;
400 msghdr.msg_iovlen = ELEMENTSOF(iovec);
405 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
409 if (!syslog_is_stream ||
410 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
413 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
419 static int write_to_kmsg(
424 const char *buffer) {
426 char header_priority[16], header_pid[16];
427 struct iovec iovec[5];
432 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
433 char_array_0(header_priority);
435 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
436 char_array_0(header_pid);
439 IOVEC_SET_STRING(iovec[0], header_priority);
440 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
441 IOVEC_SET_STRING(iovec[2], header_pid);
442 IOVEC_SET_STRING(iovec[3], buffer);
443 IOVEC_SET_STRING(iovec[4], "\n");
445 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
451 static int write_to_journal(
456 const char *buffer) {
458 char header[LINE_MAX];
459 struct iovec iovec[3];
465 snprintf(header, sizeof(header),
467 "SYSLOG_FACILITY=%i\n"
471 "SYSLOG_IDENTIFIER=%s\n"
478 program_invocation_short_name);
480 char_array_0(header);
483 IOVEC_SET_STRING(iovec[0], header);
484 IOVEC_SET_STRING(iovec[1], buffer);
485 IOVEC_SET_STRING(iovec[2], "\n");
489 mh.msg_iovlen = ELEMENTSOF(iovec);
491 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
497 static int log_dispatch(
506 if (log_target == LOG_TARGET_NULL)
509 /* Patch in LOG_DAEMON facility if necessary */
510 if ((level & LOG_FACMASK) == 0)
511 level = log_facility | LOG_PRI(level);
517 buffer += strspn(buffer, NEWLINE);
522 if ((e = strpbrk(buffer, NEWLINE)))
525 if (log_target == LOG_TARGET_AUTO ||
526 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
527 log_target == LOG_TARGET_JOURNAL) {
529 k = write_to_journal(level, file, line, func, buffer);
538 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
539 log_target == LOG_TARGET_SYSLOG) {
541 k = write_to_syslog(level, file, line, func, buffer);
551 (log_target == LOG_TARGET_AUTO ||
552 log_target == LOG_TARGET_SAFE ||
553 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
554 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
555 log_target == LOG_TARGET_KMSG)) {
557 k = write_to_kmsg(level, file, line, func, buffer);
566 k = write_to_console(level, file, line, func, buffer);
577 int log_dump_internal(
586 /* This modifies the buffer... */
588 if (_likely_(LOG_PRI(level) > log_max_level))
592 r = log_dispatch(level, file, line, func, buffer);
606 char buffer[LINE_MAX];
609 if (_likely_(LOG_PRI(level) > log_max_level))
613 vsnprintf(buffer, sizeof(buffer), format, ap);
614 char_array_0(buffer);
616 r = log_dispatch(level, file, line, func, buffer);
627 const char *format, ...) {
632 va_start(ap, format);
633 r = log_metav(level, file, line, func, format, ap);
639 #pragma GCC diagnostic push
640 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
641 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
642 static char buffer[LINE_MAX];
644 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
646 char_array_0(buffer);
647 log_abort_msg = buffer;
649 log_dispatch(LOG_CRIT, file, line, func, buffer);
652 #pragma GCC diagnostic pop
654 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
655 log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
658 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
659 log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
662 int log_oom_internal(const char *file, int line, const char *func) {
663 log_meta(LOG_ERR, file, line, func, "Out of memory.");
667 int log_struct_internal(
672 const char *format, ...) {
678 if (_likely_(LOG_PRI(level) > log_max_level))
681 if (log_target == LOG_TARGET_NULL)
684 if ((level & LOG_FACMASK) == 0)
685 level = log_facility | LOG_PRI(level);
689 if ((log_target == LOG_TARGET_AUTO ||
690 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
691 log_target == LOG_TARGET_JOURNAL) &&
694 char header[LINE_MAX];
695 struct iovec iovec[17];
698 const char nl = '\n';
700 /* If the journal is available do structured logging */
702 snprintf(header, sizeof(header),
704 "SYSLOG_FACILITY=%i\n"
708 "SYSLOG_IDENTIFIER=%s\n",
714 program_invocation_short_name);
715 char_array_0(header);
718 IOVEC_SET_STRING(iovec[n++], header);
720 va_start(ap, format);
721 while (format && n + 1 < ELEMENTSOF(iovec)) {
724 if (vasprintf(&buf, format, ap) < 0) {
729 IOVEC_SET_STRING(iovec[n++], buf);
731 iovec[n].iov_base = (char*) &nl;
732 iovec[n].iov_len = 1;
735 format = va_arg(ap, char *);
743 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
749 for (i = 1; i < n; i += 2)
750 free(iovec[i].iov_base);
756 /* Fallback if journal logging is not available */
758 va_start(ap, format);
761 vsnprintf(buf, sizeof(buf), format, ap);
764 if (startswith(buf, "MESSAGE=")) {
769 format = va_arg(ap, char *);
774 r = log_dispatch(level, file, line, func, buf + 8);
783 int log_set_target_from_string(const char *e) {
786 t = log_target_from_string(e);
794 int log_set_max_level_from_string(const char *e) {
797 t = log_level_from_string(e);
801 log_set_max_level(t);
805 void log_parse_environment(void) {
808 e = secure_getenv("SYSTEMD_LOG_TARGET");
809 if (e && log_set_target_from_string(e) < 0)
810 log_warning("Failed to parse log target %s. Ignoring.", e);
812 e = secure_getenv("SYSTEMD_LOG_LEVEL");
813 if (e && log_set_max_level_from_string(e) < 0)
814 log_warning("Failed to parse log level %s. Ignoring.", e);
816 e = secure_getenv("SYSTEMD_LOG_COLOR");
817 if (e && log_show_color_from_string(e) < 0)
818 log_warning("Failed to parse bool %s. Ignoring.", e);
820 e = secure_getenv("SYSTEMD_LOG_LOCATION");
821 if (e && log_show_location_from_string(e) < 0)
822 log_warning("Failed to parse bool %s. Ignoring.", e);
825 LogTarget log_get_target(void) {
829 int log_get_max_level(void) {
830 return log_max_level;
833 void log_show_color(bool b) {
837 void log_show_location(bool b) {
841 int log_show_color_from_string(const char *e) {
844 t = parse_boolean(e);
852 int log_show_location_from_string(const char *e) {
855 t = parse_boolean(e);
859 log_show_location(t);
863 bool log_on_console(void) {
864 if (log_target == LOG_TARGET_CONSOLE)
867 return syslog_fd < 0 && kmsg_fd < 0 && journal_fd < 0;
870 static const char *const log_target_table[] = {
871 [LOG_TARGET_CONSOLE] = "console",
872 [LOG_TARGET_KMSG] = "kmsg",
873 [LOG_TARGET_JOURNAL] = "journal",
874 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
875 [LOG_TARGET_SYSLOG] = "syslog",
876 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
877 [LOG_TARGET_AUTO] = "auto",
878 [LOG_TARGET_SAFE] = "safe",
879 [LOG_TARGET_NULL] = "null"
882 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);