/* SPDX-License-Identifier: LGPL-2.1+ */
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
#include <errno.h>
#include <fcntl.h>
#include "syslog-util.h"
#include "terminal-util.h"
#include "time-util.h"
-//#include "utf8.h"
+#include "utf8.h"
#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
* use here. */
static char *log_abort_msg = NULL;
-static void log_close_console(void) {
-
- if (console_fd < 0)
- return;
-
- if (console_fd >= 3)
- safe_close(console_fd);
+/* An assert to use in logging functions that does not call recursively
+ * into our logging functions (since that might lead to a loop). */
+#define assert_raw(expr) \
+ do { \
+ if (_unlikely_(!(expr))) { \
+ fputs(#expr "\n", stderr); \
+ abort(); \
+ } \
+ } while (false)
- console_fd = -1;
+static void log_close_console(void) {
+ console_fd = safe_close_above_stdio(console_fd);
}
static int log_open_console(void) {
char location[256], prefix[1 + DECIMAL_STR_MAX(int) + 2];
struct iovec iovec[6] = {};
- unsigned n = 0;
bool highlight;
+ size_t n = 0;
if (console_fd < 0)
return 0;
highlight = LOG_PRI(level) <= LOG_ERR && show_color;
if (show_location) {
- xsprintf(location, "(%s:%i) ", file, line);
+ (void) snprintf(location, sizeof location, "(%s:%i) ", file, line);
iovec[n++] = IOVEC_MAKE_STRING(location);
}
const char *file, int line, const char *func,
const char *object_field, const char *object,
const char *extra_field, const char *extra) {
+ int r;
- snprintf(header, size,
- "PRIORITY=%i\n"
- "SYSLOG_FACILITY=%i\n"
- "%s%s%s"
- "%s%.*i%s"
- "%s%s%s"
- "%s%.*i%s"
- "%s%s%s"
- "%s%s%s"
- "SYSLOG_IDENTIFIER=%s\n",
- LOG_PRI(level),
- LOG_FAC(level),
- isempty(file) ? "" : "CODE_FILE=",
- isempty(file) ? "" : file,
- isempty(file) ? "" : "\n",
- line ? "CODE_LINE=" : "",
- line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
- line ? "\n" : "",
- isempty(func) ? "" : "CODE_FUNC=",
- isempty(func) ? "" : func,
- isempty(func) ? "" : "\n",
- error ? "ERRNO=" : "",
- error ? 1 : 0, error,
- error ? "\n" : "",
- isempty(object) ? "" : object_field,
- isempty(object) ? "" : object,
- isempty(object) ? "" : "\n",
- isempty(extra) ? "" : extra_field,
- isempty(extra) ? "" : extra,
- isempty(extra) ? "" : "\n",
- program_invocation_short_name);
+ r = snprintf(header, size,
+ "PRIORITY=%i\n"
+ "SYSLOG_FACILITY=%i\n"
+ "%s%.256s%s" /* CODE_FILE */
+ "%s%.*i%s" /* CODE_LINE */
+ "%s%.256s%s" /* CODE_FUNC */
+ "%s%.*i%s" /* ERRNO */
+ "%s%.256s%s" /* object */
+ "%s%.256s%s" /* extra */
+ "SYSLOG_IDENTIFIER=%.256s\n",
+ LOG_PRI(level),
+ LOG_FAC(level),
+ isempty(file) ? "" : "CODE_FILE=",
+ isempty(file) ? "" : file,
+ isempty(file) ? "" : "\n",
+ line ? "CODE_LINE=" : "",
+ line ? 1 : 0, line, /* %.0d means no output too, special case for 0 */
+ line ? "\n" : "",
+ isempty(func) ? "" : "CODE_FUNC=",
+ isempty(func) ? "" : func,
+ isempty(func) ? "" : "\n",
+ error ? "ERRNO=" : "",
+ error ? 1 : 0, error,
+ error ? "\n" : "",
+ isempty(object) ? "" : object_field,
+ isempty(object) ? "" : object,
+ isempty(object) ? "" : "\n",
+ isempty(extra) ? "" : extra_field,
+ isempty(extra) ? "" : extra,
+ isempty(extra) ? "" : "\n",
+ program_invocation_short_name);
+ assert_raw((size_t) r < size);
return 0;
}
const char *func,
const char *object_field,
const char *object,
- const char *extra,
const char *extra_field,
+ const char *extra,
char *buffer) {
- assert(buffer);
+ assert_raw(buffer);
if (error < 0)
error = -error;
if (_likely_(LOG_PRI(level) > log_max_level[realm]))
return -error;
- /* Make sure that %m maps to the specified error */
- if (error != 0)
- errno = error;
+ /* Make sure that %m maps to the specified error (or "Success"). */
+ errno = error;
- vsnprintf(buffer, sizeof(buffer), format, ap);
+ (void) vsnprintf(buffer, sizeof buffer, format, ap);
return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer);
}
return r;
}
-int log_object_internalv(
+_printf_(10,0)
+static int log_object_internalv(
int level,
int error,
const char *file,
if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]))
return -error;
- /* Make sure that %m maps to the specified error */
- if (error != 0)
- errno = error;
+ /* Make sure that %m maps to the specified error (or "Success"). */
+ errno = error;
/* Prepend the object name before the message */
if (object) {
} else
b = buffer = newa(char, LINE_MAX);
- vsnprintf(b, LINE_MAX, format, ap);
+ (void) vsnprintf(b, LINE_MAX, format, ap);
return log_dispatch_internal(level, error, file, line, func,
object_field, object, extra_field, extra, buffer);
return;
DISABLE_WARNING_FORMAT_NONLITERAL;
- xsprintf(buffer, format, text, file, line, func);
+ (void) snprintf(buffer, sizeof buffer, format, text, file, line, func);
REENABLE_WARNING;
log_abort_msg = buffer;
log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer);
}
-noreturn void log_assert_failed_realm(
+_noreturn_ void log_assert_failed_realm(
LogRealm realm,
const char *text,
const char *file,
abort();
}
-noreturn void log_assert_failed_unreachable_realm(
+_noreturn_ void log_assert_failed_unreachable_realm(
LogRealm realm,
const char *text,
const char *file,
* since vasprintf() leaves it afterwards at
* an undefined location */
- if (error != 0)
- errno = error;
+ errno = error;
va_copy(aq, ap);
r = vasprintf(&m, format, aq);
while (format) {
va_list aq;
- if (error != 0)
- errno = error;
+ errno = error;
va_copy(aq, ap);
- vsnprintf(buf, sizeof(buf), format, aq);
+ (void) vsnprintf(buf, sizeof buf, format, aq);
va_end(aq);
if (startswith(buf, "MESSAGE=")) {
return -error;
}
- for (i = 0; i < n_input_iovec; i++) {
- if (input_iovec[i].iov_len < STRLEN("MESSAGE="))
- continue;
-
- if (memcmp(input_iovec[i].iov_base, "MESSAGE=", STRLEN("MESSAGE=")) == 0)
+ for (i = 0; i < n_input_iovec; i++)
+ if (memory_startswith(input_iovec[i].iov_base, input_iovec[i].iov_len, "MESSAGE="))
break;
- }
if (_unlikely_(i >= n_input_iovec)) /* Couldn't find MESSAGE=? */
return -error;
if (log_target == LOG_TARGET_NULL)
return -error;
- if (error != 0)
- errno = error;
+ errno = error;
va_start(ap, format);
- vsnprintf(buffer, sizeof(buffer), format, ap);
+ (void) vsnprintf(buffer, sizeof buffer, format, ap);
va_end(ap);
if (unit)
return getpid_cached() == 1 ? LOG_EMERG : LOG_ERR;
}
+
+int log_dup_console(void) {
+ int copy;
+
+ /* Duplicate the fd we use for fd logging if it's < 3 and use the copy from now on. This call is useful
+ * whenever we want to continue logging through the original fd, but want to rearrange stderr. */
+
+ if (console_fd >= 3)
+ return 0;
+
+ copy = fcntl(console_fd, F_DUPFD_CLOEXEC, 3);
+ if (copy < 0)
+ return -errno;
+
+ console_fd = copy;
+ return 0;
+}