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>
34 #include "socket-util.h"
36 #define SNDBUF_SIZE (8*1024*1024)
38 static LogTarget log_target = LOG_TARGET_CONSOLE;
39 static int log_max_level = LOG_INFO;
40 static int log_facility = LOG_DAEMON;
42 static int console_fd = STDERR_FILENO;
43 static int syslog_fd = -1;
44 static int kmsg_fd = -1;
45 static int journal_fd = -1;
47 static bool syslog_is_stream = false;
49 static bool show_color = false;
50 static bool show_location = false;
52 /* Akin to glibc's __abort_msg; which is private and we hence cannot
54 static char *log_abort_msg = NULL;
56 void log_close_console(void) {
63 close_nointr_nofail(console_fd);
69 static int log_open_console(void) {
76 console_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
78 log_error("Failed to open /dev/console for logging: %s", strerror(-console_fd));
82 log_debug("Successfully opened /dev/console for logging.");
84 console_fd = STDERR_FILENO;
89 void log_close_kmsg(void) {
94 close_nointr_nofail(kmsg_fd);
98 static int log_open_kmsg(void) {
103 kmsg_fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
105 log_error("Failed to open /dev/kmsg for logging: %s", strerror(errno));
109 log_debug("Successfully opened /dev/kmsg for logging.");
114 void log_close_syslog(void) {
119 close_nointr_nofail(syslog_fd);
123 static int create_log_socket(int type) {
126 /* All output to the syslog/journal fds we do asynchronously,
127 * and if the buffers are full we just drop the messages */
129 fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
133 fd_inc_sndbuf(fd, SNDBUF_SIZE);
138 static int log_open_syslog(void) {
139 union sockaddr_union sa;
146 sa.un.sun_family = AF_UNIX;
147 strncpy(sa.un.sun_path, "/dev/log", sizeof(sa.un.sun_path));
149 syslog_fd = create_log_socket(SOCK_DGRAM);
155 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
156 close_nointr_nofail(syslog_fd);
158 /* Some legacy syslog systems still use stream
159 * sockets. They really shouldn't. But what can we
161 syslog_fd = create_log_socket(SOCK_STREAM);
167 if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
172 syslog_is_stream = true;
174 syslog_is_stream = false;
176 log_debug("Successfully opened syslog for logging.");
182 log_debug("Failed to open syslog for logging: %s", strerror(-r));
186 void log_close_journal(void) {
191 close_nointr_nofail(journal_fd);
195 static int log_open_journal(void) {
196 union sockaddr_union sa;
202 journal_fd = create_log_socket(SOCK_DGRAM);
203 if (journal_fd < 0) {
209 sa.un.sun_family = AF_UNIX;
210 strncpy(sa.un.sun_path, "/run/systemd/journal/socket", sizeof(sa.un.sun_path));
212 if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
217 log_debug("Successfully opened journal for logging.");
223 log_debug("Failed to open journal for logging: %s", strerror(-r));
230 /* If we don't use the console we close it here, to not get
231 * killed by SAK. If we don't use syslog we close it here so
232 * that we are not confused by somebody deleting the socket in
233 * the fs. If we don't use /dev/kmsg we still keep it open,
234 * because there is no reason to close it. */
236 if (log_target == LOG_TARGET_NULL) {
243 if (log_target != LOG_TARGET_AUTO ||
245 isatty(STDERR_FILENO) <= 0) {
247 if (log_target == LOG_TARGET_AUTO ||
248 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
249 log_target == LOG_TARGET_JOURNAL) {
250 r = log_open_journal();
258 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
259 log_target == LOG_TARGET_SYSLOG) {
260 r = log_open_syslog();
268 if (log_target == LOG_TARGET_AUTO ||
269 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
270 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
271 log_target == LOG_TARGET_KMSG) {
285 /* Get the real /dev/console if we are PID=1, hence reopen */
287 return log_open_console();
290 void log_set_target(LogTarget target) {
292 assert(target < _LOG_TARGET_MAX);
297 void log_close(void) {
304 void log_forget_fds(void) {
305 console_fd = kmsg_fd = syslog_fd = journal_fd = -1;
308 void log_set_max_level(int level) {
309 assert((level & LOG_PRIMASK) == level);
311 log_max_level = level;
314 void log_set_facility(int facility) {
315 log_facility = facility;
318 static int write_to_console(
323 const char *buffer) {
326 struct iovec iovec[5];
333 highlight = LOG_PRI(level) <= LOG_ERR && show_color;
338 snprintf(location, sizeof(location), "(%s:%u) ", file, line);
339 char_array_0(location);
340 IOVEC_SET_STRING(iovec[n++], location);
344 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_RED_ON);
345 IOVEC_SET_STRING(iovec[n++], buffer);
347 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
348 IOVEC_SET_STRING(iovec[n++], "\n");
350 if (writev(console_fd, iovec, n) < 0)
356 static int write_to_syslog(
361 const char *buffer) {
363 char header_priority[16], header_time[64], header_pid[16];
364 struct iovec iovec[5];
365 struct msghdr msghdr;
372 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
373 char_array_0(header_priority);
375 t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
376 if (!(tm = localtime(&t)))
379 if (strftime(header_time, sizeof(header_time), "%h %e %T ", tm) <= 0)
382 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
383 char_array_0(header_pid);
386 IOVEC_SET_STRING(iovec[0], header_priority);
387 IOVEC_SET_STRING(iovec[1], header_time);
388 IOVEC_SET_STRING(iovec[2], program_invocation_short_name);
389 IOVEC_SET_STRING(iovec[3], header_pid);
390 IOVEC_SET_STRING(iovec[4], buffer);
392 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
393 if (syslog_is_stream)
397 msghdr.msg_iov = iovec;
398 msghdr.msg_iovlen = ELEMENTSOF(iovec);
403 n = sendmsg(syslog_fd, &msghdr, MSG_NOSIGNAL);
407 if (!syslog_is_stream ||
408 (size_t) n >= IOVEC_TOTAL_SIZE(iovec, ELEMENTSOF(iovec)))
411 IOVEC_INCREMENT(iovec, ELEMENTSOF(iovec), n);
417 static int write_to_kmsg(
422 const char *buffer) {
424 char header_priority[16], header_pid[16];
425 struct iovec iovec[5];
430 snprintf(header_priority, sizeof(header_priority), "<%i>", level);
431 char_array_0(header_priority);
433 snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
434 char_array_0(header_pid);
437 IOVEC_SET_STRING(iovec[0], header_priority);
438 IOVEC_SET_STRING(iovec[1], program_invocation_short_name);
439 IOVEC_SET_STRING(iovec[2], header_pid);
440 IOVEC_SET_STRING(iovec[3], buffer);
441 IOVEC_SET_STRING(iovec[4], "\n");
443 if (writev(kmsg_fd, iovec, ELEMENTSOF(iovec)) < 0)
449 static int write_to_journal(
454 const char *buffer) {
456 char header[LINE_MAX];
457 struct iovec iovec[3];
463 snprintf(header, sizeof(header),
465 "SYSLOG_FACILITY=%i\n"
469 "SYSLOG_IDENTIFIER=%s\n"
476 program_invocation_short_name);
478 char_array_0(header);
481 IOVEC_SET_STRING(iovec[0], header);
482 IOVEC_SET_STRING(iovec[1], buffer);
483 IOVEC_SET_STRING(iovec[2], "\n");
487 mh.msg_iovlen = ELEMENTSOF(iovec);
489 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
495 static int log_dispatch(
504 if (log_target == LOG_TARGET_NULL)
507 /* Patch in LOG_DAEMON facility if necessary */
508 if ((level & LOG_FACMASK) == 0)
509 level = log_facility | LOG_PRI(level);
515 buffer += strspn(buffer, NEWLINE);
520 if ((e = strpbrk(buffer, NEWLINE)))
523 if (log_target == LOG_TARGET_AUTO ||
524 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
525 log_target == LOG_TARGET_JOURNAL) {
527 k = write_to_journal(level, file, line, func, buffer);
536 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
537 log_target == LOG_TARGET_SYSLOG) {
539 k = write_to_syslog(level, file, line, func, buffer);
549 (log_target == LOG_TARGET_AUTO ||
550 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
551 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
552 log_target == LOG_TARGET_KMSG)) {
554 k = write_to_kmsg(level, file, line, func, buffer);
563 k = write_to_console(level, file, line, func, buffer);
574 int log_dump_internal(
583 /* This modifies the buffer... */
585 if (_likely_(LOG_PRI(level) > log_max_level))
589 r = log_dispatch(level, file, line, func, buffer);
603 char buffer[LINE_MAX];
606 if (_likely_(LOG_PRI(level) > log_max_level))
610 vsnprintf(buffer, sizeof(buffer), format, ap);
611 char_array_0(buffer);
613 r = log_dispatch(level, file, line, func, buffer);
624 const char *format, ...) {
629 va_start(ap, format);
630 r = log_metav(level, file, line, func, format, ap);
636 #pragma GCC diagnostic push
637 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
638 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
639 static char buffer[LINE_MAX];
641 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
643 char_array_0(buffer);
644 log_abort_msg = buffer;
646 log_dispatch(LOG_CRIT, file, line, func, buffer);
649 #pragma GCC diagnostic pop
651 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
652 log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
655 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
656 log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
659 int log_set_target_from_string(const char *e) {
662 t = log_target_from_string(e);
670 int log_set_max_level_from_string(const char *e) {
673 t = log_level_from_string(e);
677 log_set_max_level(t);
681 void log_parse_environment(void) {
684 if ((e = getenv("SYSTEMD_LOG_TARGET")))
685 if (log_set_target_from_string(e) < 0)
686 log_warning("Failed to parse log target %s. Ignoring.", e);
688 if ((e = getenv("SYSTEMD_LOG_LEVEL")))
689 if (log_set_max_level_from_string(e) < 0)
690 log_warning("Failed to parse log level %s. Ignoring.", e);
692 if ((e = getenv("SYSTEMD_LOG_COLOR")))
693 if (log_show_color_from_string(e) < 0)
694 log_warning("Failed to parse bool %s. Ignoring.", e);
696 if ((e = getenv("SYSTEMD_LOG_LOCATION")))
697 if (log_show_location_from_string(e) < 0)
698 log_warning("Failed to parse bool %s. Ignoring.", e);
701 LogTarget log_get_target(void) {
705 int log_get_max_level(void) {
706 return log_max_level;
709 void log_show_color(bool b) {
713 void log_show_location(bool b) {
717 int log_show_color_from_string(const char *e) {
720 t = parse_boolean(e);
728 int log_show_location_from_string(const char *e) {
731 t = parse_boolean(e);
735 log_show_location(t);
739 static const char *const log_target_table[] = {
740 [LOG_TARGET_CONSOLE] = "console",
741 [LOG_TARGET_KMSG] = "kmsg",
742 [LOG_TARGET_JOURNAL] = "journal",
743 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
744 [LOG_TARGET_SYSLOG] = "syslog",
745 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
746 [LOG_TARGET_AUTO] = "auto",
747 [LOG_TARGET_NULL] = "null"
750 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);