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"
476 char_array_0(header);
479 IOVEC_SET_STRING(iovec[0], header);
480 IOVEC_SET_STRING(iovec[1], buffer);
481 IOVEC_SET_STRING(iovec[2], "\n");
485 mh.msg_iovlen = ELEMENTSOF(iovec);
487 if (sendmsg(journal_fd, &mh, MSG_NOSIGNAL) < 0)
493 static int log_dispatch(
502 if (log_target == LOG_TARGET_NULL)
505 /* Patch in LOG_DAEMON facility if necessary */
506 if ((level & LOG_FACMASK) == 0)
507 level = log_facility | LOG_PRI(level);
513 buffer += strspn(buffer, NEWLINE);
518 if ((e = strpbrk(buffer, NEWLINE)))
521 if (log_target == LOG_TARGET_AUTO ||
522 log_target == LOG_TARGET_JOURNAL_OR_KMSG ||
523 log_target == LOG_TARGET_JOURNAL) {
525 k = write_to_journal(level, file, line, func, buffer);
534 if (log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
535 log_target == LOG_TARGET_SYSLOG) {
537 k = write_to_syslog(level, file, line, func, buffer);
547 (log_target == LOG_TARGET_AUTO ||
548 log_target == LOG_TARGET_SYSLOG_OR_KMSG ||
549 log_target == LOG_TARGET_KMSG)) {
551 k = write_to_kmsg(level, file, line, func, buffer);
560 k = write_to_console(level, file, line, func, buffer);
571 int log_dump_internal(
580 /* This modifies the buffer... */
582 if (_likely_(LOG_PRI(level) > log_max_level))
586 r = log_dispatch(level, file, line, func, buffer);
600 char buffer[LINE_MAX];
603 if (_likely_(LOG_PRI(level) > log_max_level))
607 vsnprintf(buffer, sizeof(buffer), format, ap);
608 char_array_0(buffer);
610 r = log_dispatch(level, file, line, func, buffer);
621 const char *format, ...) {
626 va_start(ap, format);
627 r = log_metav(level, file, line, func, format, ap);
633 #pragma GCC diagnostic push
634 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
635 _noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
636 static char buffer[LINE_MAX];
638 snprintf(buffer, sizeof(buffer), format, text, file, line, func);
640 char_array_0(buffer);
641 log_abort_msg = buffer;
643 log_dispatch(LOG_CRIT, file, line, func, buffer);
646 #pragma GCC diagnostic pop
648 _noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
649 log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
652 _noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
653 log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
656 int log_set_target_from_string(const char *e) {
659 t = log_target_from_string(e);
667 int log_set_max_level_from_string(const char *e) {
670 t = log_level_from_string(e);
674 log_set_max_level(t);
678 void log_parse_environment(void) {
681 if ((e = getenv("SYSTEMD_LOG_TARGET")))
682 if (log_set_target_from_string(e) < 0)
683 log_warning("Failed to parse log target %s. Ignoring.", e);
685 if ((e = getenv("SYSTEMD_LOG_LEVEL")))
686 if (log_set_max_level_from_string(e) < 0)
687 log_warning("Failed to parse log level %s. Ignoring.", e);
689 if ((e = getenv("SYSTEMD_LOG_COLOR")))
690 if (log_show_color_from_string(e) < 0)
691 log_warning("Failed to parse bool %s. Ignoring.", e);
693 if ((e = getenv("SYSTEMD_LOG_LOCATION")))
694 if (log_show_location_from_string(e) < 0)
695 log_warning("Failed to parse bool %s. Ignoring.", e);
698 LogTarget log_get_target(void) {
702 int log_get_max_level(void) {
703 return log_max_level;
706 void log_show_color(bool b) {
710 void log_show_location(bool b) {
714 int log_show_color_from_string(const char *e) {
717 t = parse_boolean(e);
725 int log_show_location_from_string(const char *e) {
728 t = parse_boolean(e);
732 log_show_location(t);
736 static const char *const log_target_table[] = {
737 [LOG_TARGET_CONSOLE] = "console",
738 [LOG_TARGET_KMSG] = "kmsg",
739 [LOG_TARGET_JOURNAL] = "journal",
740 [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg",
741 [LOG_TARGET_SYSLOG] = "syslog",
742 [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg",
743 [LOG_TARGET_AUTO] = "auto",
744 [LOG_TARGET_NULL] = "null"
747 DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget);