2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/signalfd.h>
29 #include <sys/socket.h>
36 #include "sd-messages.h"
38 #include "alloc-util.h"
40 #include "format-util.h"
45 #include "parse-util.h"
46 #include "proc-cmdline.h"
47 #include "process-util.h"
48 #include "signal-util.h"
49 #include "socket-util.h"
50 #include "stdio-util.h"
51 #include "string-table.h"
52 #include "string-util.h"
53 #include "syslog-util.h"
54 #include "terminal-util.h"
55 #include "time-util.h"
58 #define SNDBUF_SIZE (8*1024*1024)
60 static LogTarget log_target
= LOG_TARGET_CONSOLE
;
61 static int log_max_level
= LOG_INFO
;
62 static int log_facility
= LOG_DAEMON
;
64 static int console_fd
= STDERR_FILENO
;
65 static int syslog_fd
= -1;
66 static int kmsg_fd
= -1;
67 static int journal_fd
= -1;
69 static bool syslog_is_stream
= false;
71 static bool show_color
= false;
72 static bool show_location
= false;
74 static bool upgrade_syslog_to_journal
= false;
75 static bool always_reopen_console
= false;
77 /* Akin to glibc's __abort_msg; which is private and we hence cannot
79 static char *log_abort_msg
= NULL
;
81 void log_close_console(void) {
88 safe_close(console_fd
);
94 static int log_open_console(void) {
99 if (always_reopen_console
) {
100 console_fd
= open_terminal("/dev/console", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
104 console_fd
= STDERR_FILENO
;
109 void log_close_kmsg(void) {
110 kmsg_fd
= safe_close(kmsg_fd
);
113 static int log_open_kmsg(void) {
118 kmsg_fd
= open("/dev/kmsg", O_WRONLY
|O_NOCTTY
|O_CLOEXEC
);
125 void log_close_syslog(void) {
126 syslog_fd
= safe_close(syslog_fd
);
129 static int create_log_socket(int type
) {
133 fd
= socket(AF_UNIX
, type
|SOCK_CLOEXEC
, 0);
137 (void) fd_inc_sndbuf(fd
, SNDBUF_SIZE
);
139 /* We need a blocking fd here since we'd otherwise lose
140 messages way too early. However, let's not hang forever in the
141 unlikely case of a deadlock. */
143 timeval_store(&tv
, 10 * USEC_PER_MSEC
);
145 timeval_store(&tv
, 10 * USEC_PER_SEC
);
146 (void) setsockopt(fd
, SOL_SOCKET
, SO_SNDTIMEO
, &tv
, sizeof(tv
));
151 static int log_open_syslog(void) {
153 static const union sockaddr_union sa
= {
154 .un
.sun_family
= AF_UNIX
,
155 .un
.sun_path
= "/dev/log",
163 syslog_fd
= create_log_socket(SOCK_DGRAM
);
169 if (connect(syslog_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
170 safe_close(syslog_fd
);
172 /* Some legacy syslog systems still use stream
173 * sockets. They really shouldn't. But what can we
175 syslog_fd
= create_log_socket(SOCK_STREAM
);
181 if (connect(syslog_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
186 syslog_is_stream
= true;
188 syslog_is_stream
= false;
197 void log_close_journal(void) {
198 journal_fd
= safe_close(journal_fd
);
201 static int log_open_journal(void) {
203 static const union sockaddr_union sa
= {
204 .un
.sun_family
= AF_UNIX
,
205 .un
.sun_path
= "/run/systemd/journal/socket",
213 journal_fd
= create_log_socket(SOCK_DGRAM
);
214 if (journal_fd
< 0) {
219 if (connect(journal_fd
, &sa
.sa
, SOCKADDR_UN_LEN(sa
.un
)) < 0) {
234 /* If we don't use the console we close it here, to not get
235 * killed by SAK. If we don't use syslog we close it here so
236 * that we are not confused by somebody deleting the socket in
237 * the fs. If we don't use /dev/kmsg we still keep it open,
238 * because there is no reason to close it. */
240 if (log_target
== LOG_TARGET_NULL
) {
247 if (!IN_SET(log_target
, LOG_TARGET_AUTO
, LOG_TARGET_SAFE
) ||
249 isatty(STDERR_FILENO
) <= 0) {
251 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
252 LOG_TARGET_JOURNAL_OR_KMSG
,
253 LOG_TARGET_JOURNAL
)) {
254 r
= log_open_journal();
262 if (IN_SET(log_target
, LOG_TARGET_SYSLOG_OR_KMSG
,
263 LOG_TARGET_SYSLOG
)) {
264 r
= log_open_syslog();
272 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
274 LOG_TARGET_JOURNAL_OR_KMSG
,
275 LOG_TARGET_SYSLOG_OR_KMSG
,
290 return log_open_console();
293 void log_set_target(LogTarget target
) {
295 assert(target
< _LOG_TARGET_MAX
);
297 if (upgrade_syslog_to_journal
) {
298 if (target
== LOG_TARGET_SYSLOG
)
299 target
= LOG_TARGET_JOURNAL
;
300 else if (target
== LOG_TARGET_SYSLOG_OR_KMSG
)
301 target
= LOG_TARGET_JOURNAL_OR_KMSG
;
307 void log_close(void) {
314 void log_forget_fds(void) {
315 console_fd
= kmsg_fd
= syslog_fd
= journal_fd
= -1;
318 void log_set_max_level(int level
) {
319 assert((level
& LOG_PRIMASK
) == level
);
321 log_max_level
= level
;
324 void log_set_facility(int facility
) {
325 log_facility
= facility
;
328 static int write_to_console(
334 const char *buffer
) {
336 char location
[256], prefix
[1 + DECIMAL_STR_MAX(int) + 2];
337 struct iovec iovec
[6] = {};
344 if (log_target
== LOG_TARGET_CONSOLE_PREFIXED
) {
345 xsprintf(prefix
, "<%i>", level
);
346 IOVEC_SET_STRING(iovec
[n
++], prefix
);
349 highlight
= LOG_PRI(level
) <= LOG_ERR
&& show_color
;
352 snprintf(location
, sizeof(location
), "(%s:%i) ", file
, line
);
353 IOVEC_SET_STRING(iovec
[n
++], location
);
357 IOVEC_SET_STRING(iovec
[n
++], ANSI_HIGHLIGHT_RED
);
358 IOVEC_SET_STRING(iovec
[n
++], buffer
);
360 IOVEC_SET_STRING(iovec
[n
++], ANSI_NORMAL
);
361 IOVEC_SET_STRING(iovec
[n
++], "\n");
363 if (writev(console_fd
, iovec
, n
) < 0) {
365 if (errno
== EIO
&& getpid() == 1) {
367 /* If somebody tried to kick us from our
368 * console tty (via vhangup() or suchlike),
369 * try to reconnect */
377 if (writev(console_fd
, iovec
, n
) < 0)
386 static int write_to_syslog(
392 const char *buffer
) {
394 char header_priority
[2 + DECIMAL_STR_MAX(int) + 1],
396 header_pid
[4 + DECIMAL_STR_MAX(pid_t
) + 1];
397 struct iovec iovec
[5] = {};
398 struct msghdr msghdr
= {
400 .msg_iovlen
= ELEMENTSOF(iovec
),
408 xsprintf(header_priority
, "<%i>", level
);
410 t
= (time_t) (now(CLOCK_REALTIME
) / USEC_PER_SEC
);
415 if (strftime(header_time
, sizeof(header_time
), "%h %e %T ", tm
) <= 0)
418 xsprintf(header_pid
, "["PID_FMT
"]: ", getpid());
420 IOVEC_SET_STRING(iovec
[0], header_priority
);
421 IOVEC_SET_STRING(iovec
[1], header_time
);
422 IOVEC_SET_STRING(iovec
[2], program_invocation_short_name
);
423 IOVEC_SET_STRING(iovec
[3], header_pid
);
424 IOVEC_SET_STRING(iovec
[4], buffer
);
426 /* When using syslog via SOCK_STREAM separate the messages by NUL chars */
427 if (syslog_is_stream
)
433 n
= sendmsg(syslog_fd
, &msghdr
, MSG_NOSIGNAL
);
437 if (!syslog_is_stream
||
438 (size_t) n
>= IOVEC_TOTAL_SIZE(iovec
, ELEMENTSOF(iovec
)))
441 IOVEC_INCREMENT(iovec
, ELEMENTSOF(iovec
), n
);
447 static int write_to_kmsg(
453 const char *buffer
) {
455 char header_priority
[2 + DECIMAL_STR_MAX(int) + 1],
456 header_pid
[4 + DECIMAL_STR_MAX(pid_t
) + 1];
457 struct iovec iovec
[5] = {};
462 xsprintf(header_priority
, "<%i>", level
);
463 xsprintf(header_pid
, "["PID_FMT
"]: ", getpid());
465 IOVEC_SET_STRING(iovec
[0], header_priority
);
466 IOVEC_SET_STRING(iovec
[1], program_invocation_short_name
);
467 IOVEC_SET_STRING(iovec
[2], header_pid
);
468 IOVEC_SET_STRING(iovec
[3], buffer
);
469 IOVEC_SET_STRING(iovec
[4], "\n");
471 if (writev(kmsg_fd
, iovec
, ELEMENTSOF(iovec
)) < 0)
477 static int log_do_header(
482 const char *file
, int line
, const char *func
,
483 const char *object_field
, const char *object
,
484 const char *extra_field
, const char *extra
) {
486 snprintf(header
, size
,
488 "SYSLOG_FACILITY=%i\n"
495 "SYSLOG_IDENTIFIER=%s\n",
498 isempty(file
) ? "" : "CODE_FILE=",
499 isempty(file
) ? "" : file
,
500 isempty(file
) ? "" : "\n",
501 line
? "CODE_LINE=" : "",
502 line
? 1 : 0, line
, /* %.0d means no output too, special case for 0 */
504 isempty(func
) ? "" : "CODE_FUNC=",
505 isempty(func
) ? "" : func
,
506 isempty(func
) ? "" : "\n",
507 error
? "ERRNO=" : "",
508 error
? 1 : 0, error
,
510 isempty(object
) ? "" : object_field
,
511 isempty(object
) ? "" : object
,
512 isempty(object
) ? "" : "\n",
513 isempty(extra
) ? "" : extra_field
,
514 isempty(extra
) ? "" : extra
,
515 isempty(extra
) ? "" : "\n",
516 program_invocation_short_name
);
521 static int write_to_journal(
527 const char *object_field
,
529 const char *extra_field
,
531 const char *buffer
) {
533 char header
[LINE_MAX
];
534 struct iovec iovec
[4] = {};
535 struct msghdr mh
= {};
540 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
);
542 IOVEC_SET_STRING(iovec
[0], header
);
543 IOVEC_SET_STRING(iovec
[1], "MESSAGE=");
544 IOVEC_SET_STRING(iovec
[2], buffer
);
545 IOVEC_SET_STRING(iovec
[3], "\n");
548 mh
.msg_iovlen
= ELEMENTSOF(iovec
);
550 if (sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
) < 0)
556 int log_dispatch_internal(
562 const char *object_field
,
565 const char *extra_field
,
573 if (log_target
== LOG_TARGET_NULL
)
576 /* Patch in LOG_DAEMON facility if necessary */
577 if ((level
& LOG_FACMASK
) == 0)
578 level
= log_facility
| LOG_PRI(level
);
584 buffer
+= strspn(buffer
, NEWLINE
);
589 if ((e
= strpbrk(buffer
, NEWLINE
)))
592 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
593 LOG_TARGET_JOURNAL_OR_KMSG
,
594 LOG_TARGET_JOURNAL
)) {
596 k
= write_to_journal(level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
, buffer
);
604 if (IN_SET(log_target
, LOG_TARGET_SYSLOG_OR_KMSG
,
605 LOG_TARGET_SYSLOG
)) {
607 k
= write_to_syslog(level
, error
, file
, line
, func
, buffer
);
616 IN_SET(log_target
, LOG_TARGET_AUTO
,
618 LOG_TARGET_SYSLOG_OR_KMSG
,
619 LOG_TARGET_JOURNAL_OR_KMSG
,
622 k
= write_to_kmsg(level
, error
, file
, line
, func
, buffer
);
630 (void) write_to_console(level
, error
, file
, line
, func
, buffer
);
638 int log_dump_internal(
648 /* This modifies the buffer... */
653 if (_likely_(LOG_PRI(level
) > log_max_level
))
656 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
669 char buffer
[LINE_MAX
];
674 if (_likely_(LOG_PRI(level
) > log_max_level
))
677 /* Make sure that %m maps to the specified error */
681 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
683 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
692 const char *format
, ...) {
697 va_start(ap
, format
);
698 r
= log_internalv(level
, error
, file
, line
, func
, format
, ap
);
704 int log_object_internalv(
710 const char *object_field
,
712 const char *extra_field
,
724 if (_likely_(LOG_PRI(level
) > log_max_level
))
727 /* Make sure that %m maps to the specified error */
731 /* Prepend the object name before the message */
736 l
= n
+ 2 + LINE_MAX
;
738 buffer
= newa(char, l
);
739 b
= stpcpy(stpcpy(buffer
, object
), ": ");
742 b
= buffer
= newa(char, l
);
745 vsnprintf(b
, l
, format
, ap
);
747 return log_dispatch_internal(level
, error
, file
, line
, func
,
748 object_field
, object
, extra_field
, extra
, buffer
);
751 int log_object_internal(
757 const char *object_field
,
759 const char *extra_field
,
761 const char *format
, ...) {
766 va_start(ap
, format
);
767 r
= log_object_internalv(level
, error
, file
, line
, func
, object_field
, object
, extra_field
, extra
, format
, ap
);
773 static void log_assert(
779 const char *format
) {
781 static char buffer
[LINE_MAX
];
783 if (_likely_(LOG_PRI(level
) > log_max_level
))
786 DISABLE_WARNING_FORMAT_NONLITERAL
;
787 snprintf(buffer
, sizeof buffer
, format
, text
, file
, line
, func
);
790 log_abort_msg
= buffer
;
792 log_dispatch_internal(level
, 0, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buffer
);
795 noreturn
void log_assert_failed(const char *text
, const char *file
, int line
, const char *func
) {
796 log_assert(LOG_CRIT
, text
, file
, line
, func
, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
800 noreturn
void log_assert_failed_unreachable(const char *text
, const char *file
, int line
, const char *func
) {
801 log_assert(LOG_CRIT
, text
, file
, line
, func
, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
805 void log_assert_failed_return(const char *text
, const char *file
, int line
, const char *func
) {
807 log_assert(LOG_DEBUG
, text
, file
, line
, func
, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
810 int log_oom_internal(const char *file
, int line
, const char *func
) {
811 log_internal(LOG_ERR
, ENOMEM
, file
, line
, func
, "Out of memory.");
815 int log_format_iovec(
819 bool newline_separator
,
824 static const char nl
= '\n';
826 while (format
&& *n
+ 1 < iovec_len
) {
831 /* We need to copy the va_list structure,
832 * since vasprintf() leaves it afterwards at
833 * an undefined location */
839 r
= vasprintf(&m
, format
, aq
);
844 /* Now, jump enough ahead, so that we point to
845 * the next format string */
846 VA_FORMAT_ADVANCE(format
, ap
);
848 IOVEC_SET_STRING(iovec
[(*n
)++], m
);
850 if (newline_separator
) {
851 iovec
[*n
].iov_base
= (char*) &nl
;
852 iovec
[*n
].iov_len
= 1;
856 format
= va_arg(ap
, char *);
861 int log_struct_internal(
867 const char *format
, ...) {
877 if (_likely_(LOG_PRI(level
) > log_max_level
))
880 if (log_target
== LOG_TARGET_NULL
)
883 if ((level
& LOG_FACMASK
) == 0)
884 level
= log_facility
| LOG_PRI(level
);
886 if (IN_SET(log_target
, LOG_TARGET_AUTO
,
887 LOG_TARGET_JOURNAL_OR_KMSG
,
888 LOG_TARGET_JOURNAL
) &&
890 char header
[LINE_MAX
];
891 struct iovec iovec
[17] = {};
897 bool fallback
= false;
899 /* If the journal is available do structured logging */
900 log_do_header(header
, sizeof(header
), level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
);
901 IOVEC_SET_STRING(iovec
[n
++], header
);
903 va_start(ap
, format
);
904 r
= log_format_iovec(iovec
, ELEMENTSOF(iovec
), &n
, true, error
, format
, ap
);
909 (void) sendmsg(journal_fd
, &mh
, MSG_NOSIGNAL
);
913 for (i
= 1; i
< n
; i
+= 2)
914 free(iovec
[i
].iov_base
);
920 /* Fallback if journal logging is not available or didn't work. */
922 va_start(ap
, format
);
930 vsnprintf(buf
, sizeof(buf
), format
, aq
);
933 if (startswith(buf
, "MESSAGE=")) {
938 VA_FORMAT_ADVANCE(format
, ap
);
940 format
= va_arg(ap
, char *);
947 return log_dispatch_internal(level
, error
, file
, line
, func
, NULL
, NULL
, NULL
, NULL
, buf
+ 8);
950 int log_set_target_from_string(const char *e
) {
953 t
= log_target_from_string(e
);
961 int log_set_max_level_from_string(const char *e
) {
964 t
= log_level_from_string(e
);
968 log_set_max_level(t
);
972 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
975 * The systemd.log_xyz= settings are parsed by all tools, and
978 * However, "quiet" is only parsed by PID 1, and only turns of
979 * status output to /dev/console, but does not alter the log
983 if (streq(key
, "debug") && !value
)
984 log_set_max_level(LOG_DEBUG
);
986 else if (proc_cmdline_key_streq(key
, "systemd.log_target")) {
988 if (proc_cmdline_value_missing(key
, value
))
991 if (log_set_target_from_string(value
) < 0)
992 log_warning("Failed to parse log target '%s'. Ignoring.", value
);
994 } else if (proc_cmdline_key_streq(key
, "systemd.log_level")) {
996 if (proc_cmdline_value_missing(key
, value
))
999 if (log_set_max_level_from_string(value
) < 0)
1000 log_warning("Failed to parse log level '%s'. Ignoring.", value
);
1002 } else if (proc_cmdline_key_streq(key
, "systemd.log_color")) {
1004 if (log_show_color_from_string(value
?: "1") < 0)
1005 log_warning("Failed to parse log color setting '%s'. Ignoring.", value
);
1007 } else if (proc_cmdline_key_streq(key
, "systemd.log_location")) {
1009 if (log_show_location_from_string(value
?: "1") < 0)
1010 log_warning("Failed to parse log location setting '%s'. Ignoring.", value
);
1016 void log_parse_environment(void) {
1019 if (get_ctty_devnr(0, NULL
) < 0)
1020 /* Only try to read the command line in daemons. We assume that anything that has a controlling tty is
1022 (void) proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
1024 e
= secure_getenv("SYSTEMD_LOG_TARGET");
1025 if (e
&& log_set_target_from_string(e
) < 0)
1026 log_warning("Failed to parse log target '%s'. Ignoring.", e
);
1028 e
= secure_getenv("SYSTEMD_LOG_LEVEL");
1029 if (e
&& log_set_max_level_from_string(e
) < 0)
1030 log_warning("Failed to parse log level '%s'. Ignoring.", e
);
1032 e
= secure_getenv("SYSTEMD_LOG_COLOR");
1033 if (e
&& log_show_color_from_string(e
) < 0)
1034 log_warning("Failed to parse bool '%s'. Ignoring.", e
);
1036 e
= secure_getenv("SYSTEMD_LOG_LOCATION");
1037 if (e
&& log_show_location_from_string(e
) < 0)
1038 log_warning("Failed to parse bool '%s'. Ignoring.", e
);
1041 LogTarget
log_get_target(void) {
1045 int log_get_max_level(void) {
1046 return log_max_level
;
1049 void log_show_color(bool b
) {
1053 bool log_get_show_color(void) {
1057 void log_show_location(bool b
) {
1061 bool log_get_show_location(void) {
1062 return show_location
;
1065 int log_show_color_from_string(const char *e
) {
1068 t
= parse_boolean(e
);
1076 int log_show_location_from_string(const char *e
) {
1079 t
= parse_boolean(e
);
1083 log_show_location(t
);
1087 bool log_on_console(void) {
1088 if (IN_SET(log_target
, LOG_TARGET_CONSOLE
,
1089 LOG_TARGET_CONSOLE_PREFIXED
))
1092 return syslog_fd
< 0 && kmsg_fd
< 0 && journal_fd
< 0;
1095 static const char *const log_target_table
[_LOG_TARGET_MAX
] = {
1096 [LOG_TARGET_CONSOLE
] = "console",
1097 [LOG_TARGET_CONSOLE_PREFIXED
] = "console-prefixed",
1098 [LOG_TARGET_KMSG
] = "kmsg",
1099 [LOG_TARGET_JOURNAL
] = "journal",
1100 [LOG_TARGET_JOURNAL_OR_KMSG
] = "journal-or-kmsg",
1101 [LOG_TARGET_SYSLOG
] = "syslog",
1102 [LOG_TARGET_SYSLOG_OR_KMSG
] = "syslog-or-kmsg",
1103 [LOG_TARGET_AUTO
] = "auto",
1104 [LOG_TARGET_SAFE
] = "safe",
1105 [LOG_TARGET_NULL
] = "null"
1108 DEFINE_STRING_TABLE_LOOKUP(log_target
, LogTarget
);
1110 void log_received_signal(int level
, const struct signalfd_siginfo
*si
) {
1111 if (si
->ssi_pid
> 0) {
1112 _cleanup_free_
char *p
= NULL
;
1114 get_process_comm(si
->ssi_pid
, &p
);
1117 "Received SIG%s from PID %"PRIu32
" (%s).",
1118 signal_to_string(si
->ssi_signo
),
1119 si
->ssi_pid
, strna(p
));
1123 signal_to_string(si
->ssi_signo
));
1127 void log_set_upgrade_syslog_to_journal(bool b
) {
1128 upgrade_syslog_to_journal
= b
;
1131 int log_syntax_internal(
1134 const char *config_file
,
1135 unsigned config_line
,
1140 const char *format
, ...) {
1143 char buffer
[LINE_MAX
];
1145 const char *unit_fmt
= NULL
;
1150 if (_likely_(LOG_PRI(level
) > log_max_level
))
1153 if (log_target
== LOG_TARGET_NULL
)
1159 va_start(ap
, format
);
1160 vsnprintf(buffer
, sizeof(buffer
), format
, ap
);
1164 unit_fmt
= getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
1166 return log_struct_internal(
1169 "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR
,
1170 "CONFIG_FILE=%s", config_file
,
1171 "CONFIG_LINE=%u", config_line
,
1172 LOG_MESSAGE("%s:%u: %s", config_file
, config_line
, buffer
),
1177 void log_set_always_reopen_console(bool b
) {
1178 always_reopen_console
= b
;