summaryrefslogtreecommitdiffstats
path: root/src/shared/logs-show.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/logs-show.c')
-rw-r--r--src/shared/logs-show.c642
1 files changed, 293 insertions, 349 deletions
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 0a31be3..c71c868 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -5,7 +5,6 @@
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
-#include <sys/socket.h>
#include <syslog.h>
#include <unistd.h>
@@ -27,11 +26,9 @@
#include "log.h"
#include "logs-show.h"
#include "macro.h"
-#include "namespace-util.h"
#include "output-mode.h"
#include "parse-util.h"
#include "pretty-print.h"
-#include "process-util.h"
#include "sparse-endian.h"
#include "stdio-util.h"
#include "string-table.h"
@@ -367,39 +364,37 @@ static int output_timestamp_realtime(
sd_journal *j,
OutputMode mode,
OutputFlags flags,
- const dual_timestamp *display_ts) {
+ usec_t usec) {
char buf[CONST_MAX(FORMAT_TIMESTAMP_MAX, 64U)];
- int r;
assert(f);
assert(j);
- assert(display_ts);
- if (!VALID_REALTIME(display_ts->realtime))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No valid realtime timestamp available");
+ if (!VALID_REALTIME(usec))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No valid realtime timestamp available.");
if (IN_SET(mode, OUTPUT_SHORT_FULL, OUTPUT_WITH_UNIT)) {
const char *k;
if (flags & OUTPUT_UTC)
- k = format_timestamp_style(buf, sizeof(buf), display_ts->realtime, TIMESTAMP_UTC);
+ k = format_timestamp_style(buf, sizeof(buf), usec, TIMESTAMP_UTC);
else
- k = format_timestamp(buf, sizeof(buf), display_ts->realtime);
+ k = format_timestamp(buf, sizeof(buf), usec);
if (!k)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to format timestamp: %" PRIu64, display_ts->realtime);
+ "Failed to format timestamp: %" PRIu64, usec);
} else {
struct tm tm;
time_t t;
- t = (time_t) (display_ts->realtime / USEC_PER_SEC);
+ t = (time_t) (usec / USEC_PER_SEC);
switch (mode) {
case OUTPUT_SHORT_UNIX:
- xsprintf(buf, "%10"PRI_TIME".%06"PRIu64, t, display_ts->realtime % USEC_PER_SEC);
+ xsprintf(buf, "%10"PRI_TIME".%06"PRIu64, t, usec % USEC_PER_SEC);
break;
case OUTPUT_SHORT_ISO:
@@ -407,13 +402,11 @@ static int output_timestamp_realtime(
size_t tail = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S",
localtime_or_gmtime_r(&t, &tm, flags & OUTPUT_UTC));
if (tail == 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to format ISO time");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to format ISO time.");
/* No usec in strftime, need to append */
if (mode == OUTPUT_SHORT_ISO_PRECISE) {
- assert(ELEMENTSOF(buf) - tail >= 7);
- snprintf(buf + tail, ELEMENTSOF(buf) - tail, ".%06"PRI_USEC, display_ts->realtime % USEC_PER_SEC);
+ assert_se(snprintf_ok(buf + tail, ELEMENTSOF(buf) - tail, ".%06"PRI_USEC, usec % USEC_PER_SEC));
tail += 7;
}
@@ -428,19 +421,12 @@ static int output_timestamp_realtime(
if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S",
localtime_or_gmtime_r(&t, &tm, flags & OUTPUT_UTC)) <= 0)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to format syslog time");
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to format syslog time.");
if (mode == OUTPUT_SHORT_PRECISE) {
- size_t k;
-
assert(sizeof(buf) > strlen(buf));
- k = sizeof(buf) - strlen(buf);
-
- r = snprintf(buf + strlen(buf), k, ".%06"PRIu64, display_ts->realtime % USEC_PER_SEC);
- if (r <= 0 || (size_t) r >= k) /* too long? */
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to format precise time");
+ if (!snprintf_ok(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%06"PRIu64, usec % USEC_PER_SEC))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to format precise time.");
}
break;
@@ -453,6 +439,77 @@ static int output_timestamp_realtime(
return (int) strlen(buf);
}
+static void parse_display_realtime(
+ sd_journal *j,
+ const char *source_realtime,
+ const char *source_monotonic,
+ usec_t *ret) {
+
+ usec_t t, s, u;
+
+ assert(j);
+ assert(ret);
+
+ /* First, try _SOURCE_REALTIME_TIMESTAMP. */
+ if (source_realtime && safe_atou64(source_realtime, &t) >= 0 && VALID_REALTIME(t)) {
+ *ret = t;
+ return;
+ }
+
+ /* Read realtime timestamp in the entry header. */
+ if (sd_journal_get_realtime_usec(j, &t) < 0) {
+ *ret = USEC_INFINITY;
+ return;
+ }
+
+ /* If _SOURCE_MONOTONIC_TIMESTAMP is provided, adjust the header timestamp. */
+ if (source_monotonic && safe_atou64(source_monotonic, &s) >= 0 && VALID_MONOTONIC(s) &&
+ sd_journal_get_monotonic_usec(j, &u, &(sd_id128_t) {}) >= 0) {
+ *ret = map_clock_usec_raw(t, u, s);
+ return;
+ }
+
+ /* Otherwise, use the header timestamp as is. */
+ *ret = t;
+}
+
+static void parse_display_timestamp(
+ sd_journal *j,
+ const char *source_realtime,
+ const char *source_monotonic,
+ dual_timestamp *ret_display_ts,
+ sd_id128_t *ret_boot_id) {
+
+ dual_timestamp header_ts = DUAL_TIMESTAMP_INFINITY, source_ts = DUAL_TIMESTAMP_INFINITY;
+ sd_id128_t boot_id = SD_ID128_NULL;
+ usec_t t;
+
+ assert(j);
+ assert(ret_display_ts);
+ assert(ret_boot_id);
+
+ if (source_realtime && safe_atou64(source_realtime, &t) >= 0 && VALID_REALTIME(t))
+ source_ts.realtime = t;
+
+ if (source_monotonic && safe_atou64(source_monotonic, &t) >= 0 && VALID_MONOTONIC(t))
+ source_ts.monotonic = t;
+
+ (void) sd_journal_get_realtime_usec(j, &header_ts.realtime);
+ (void) sd_journal_get_monotonic_usec(j, &header_ts.monotonic, &boot_id);
+
+ /* Adjust timestamp if possible. */
+ if (header_ts.realtime != USEC_INFINITY && header_ts.monotonic != USEC_INFINITY) {
+ if (source_ts.realtime == USEC_INFINITY && source_ts.monotonic != USEC_INFINITY)
+ source_ts.realtime = map_clock_usec_raw(header_ts.realtime, header_ts.monotonic, source_ts.monotonic);
+ else if (source_ts.realtime != USEC_INFINITY && source_ts.monotonic == USEC_INFINITY)
+ source_ts.monotonic = map_clock_usec_raw(header_ts.monotonic, header_ts.realtime, source_ts.realtime);
+ }
+
+ ret_display_ts->realtime = source_ts.realtime != USEC_INFINITY ? source_ts.realtime : header_ts.realtime;
+ ret_display_ts->monotonic = source_ts.monotonic != USEC_INFINITY ? source_ts.monotonic : header_ts.monotonic;
+ *ret_boot_id = boot_id;
+}
+
static int output_short(
FILE *f,
sd_journal *j,
@@ -461,42 +518,43 @@ static int output_short(
OutputFlags flags,
const Set *output_fields,
const size_t highlight[2],
- const dual_timestamp *display_ts,
- const sd_id128_t *boot_id,
- const dual_timestamp *previous_display_ts,
- const sd_id128_t *previous_boot_id) {
+ dual_timestamp *previous_display_ts, /* in and out, used only when mode is OUTPUT_SHORT_MONOTONIC, OUTPUT_SHORT_DELTA. */
+ sd_id128_t *previous_boot_id) { /* in and out, used only when mode is OUTPUT_SHORT_MONOTONIC, OUTPUT_SHORT_DELTA. */
int r;
const void *data;
size_t length, n = 0;
_cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL,
*message = NULL, *priority = NULL, *transport = NULL,
- *config_file = NULL, *unit = NULL, *user_unit = NULL, *documentation_url = NULL;
+ *config_file = NULL, *unit = NULL, *user_unit = NULL, *documentation_url = NULL,
+ *realtime = NULL, *monotonic = NULL;
size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0,
priority_len = 0, transport_len = 0, config_file_len = 0,
unit_len = 0, user_unit_len = 0, documentation_url_len = 0;
+ dual_timestamp display_ts;
+ sd_id128_t boot_id;
int p = LOG_INFO;
bool ellipsized = false, audit;
const ParseFieldVec fields[] = {
- PARSE_FIELD_VEC_ENTRY("_PID=", &pid, &pid_len),
- PARSE_FIELD_VEC_ENTRY("_COMM=", &comm, &comm_len),
- PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message, &message_len),
- PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority, &priority_len),
- PARSE_FIELD_VEC_ENTRY("_TRANSPORT=", &transport, &transport_len),
- PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname, &hostname_len),
- PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid, &fake_pid_len),
- PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier, &identifier_len),
- PARSE_FIELD_VEC_ENTRY("CONFIG_FILE=", &config_file, &config_file_len),
- PARSE_FIELD_VEC_ENTRY("_SYSTEMD_UNIT=", &unit, &unit_len),
- PARSE_FIELD_VEC_ENTRY("_SYSTEMD_USER_UNIT=", &user_unit, &user_unit_len),
- PARSE_FIELD_VEC_ENTRY("DOCUMENTATION=", &documentation_url, &documentation_url_len),
+ PARSE_FIELD_VEC_ENTRY("_PID=", &pid, &pid_len ),
+ PARSE_FIELD_VEC_ENTRY("_COMM=", &comm, &comm_len ),
+ PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message, &message_len ),
+ PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority, &priority_len ),
+ PARSE_FIELD_VEC_ENTRY("_TRANSPORT=", &transport, &transport_len ),
+ PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname, &hostname_len ),
+ PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid, &fake_pid_len ),
+ PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier, &identifier_len ),
+ PARSE_FIELD_VEC_ENTRY("CONFIG_FILE=", &config_file, &config_file_len ),
+ PARSE_FIELD_VEC_ENTRY("_SYSTEMD_UNIT=", &unit, &unit_len ),
+ PARSE_FIELD_VEC_ENTRY("_SYSTEMD_USER_UNIT=", &user_unit, &user_unit_len ),
+ PARSE_FIELD_VEC_ENTRY("DOCUMENTATION=", &documentation_url, &documentation_url_len),
+ PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, NULL ),
+ PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, NULL ),
};
size_t highlight_shifted[] = {highlight ? highlight[0] : 0, highlight ? highlight[1] : 0};
assert(f);
assert(j);
- assert(display_ts);
- assert(boot_id);
assert(previous_display_ts);
assert(previous_boot_id);
@@ -523,6 +581,9 @@ static int output_short(
return 0;
}
+ if (identifier && set_contains(j->exclude_syslog_identifiers, identifier))
+ return 0;
+
if (!(flags & OUTPUT_SHOW_ALL))
strip_tab_ansi(&message, &message_len, highlight_shifted);
@@ -534,10 +595,14 @@ static int output_short(
audit = streq_ptr(transport, "audit");
- if (IN_SET(mode, OUTPUT_SHORT_MONOTONIC, OUTPUT_SHORT_DELTA))
- r = output_timestamp_monotonic(f, mode, display_ts, boot_id, previous_display_ts, previous_boot_id);
- else
- r = output_timestamp_realtime(f, j, mode, flags, display_ts);
+ if (IN_SET(mode, OUTPUT_SHORT_MONOTONIC, OUTPUT_SHORT_DELTA)) {
+ parse_display_timestamp(j, realtime, monotonic, &display_ts, &boot_id);
+ r = output_timestamp_monotonic(f, mode, &display_ts, &boot_id, previous_display_ts, previous_boot_id);
+ } else {
+ usec_t usec;
+ parse_display_realtime(j, realtime, monotonic, &usec);
+ r = output_timestamp_realtime(f, j, mode, flags, usec);
+ }
if (r < 0)
return r;
n += r;
@@ -658,9 +723,48 @@ static int output_short(
if (flags & OUTPUT_CATALOG)
(void) print_catalog(f, j);
+ if (IN_SET(mode, OUTPUT_SHORT_MONOTONIC, OUTPUT_SHORT_DELTA)) {
+ *previous_display_ts = display_ts;
+ *previous_boot_id = boot_id;
+ }
+
return ellipsized;
}
+static int get_display_realtime(sd_journal *j, usec_t *ret) {
+ const void *data;
+ _cleanup_free_ char *realtime = NULL, *monotonic = NULL;
+ size_t length;
+ const ParseFieldVec message_fields[] = {
+ PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, NULL),
+ PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, NULL),
+ };
+ int r;
+
+ assert(j);
+ assert(ret);
+
+ JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
+ r = parse_fieldv(data, length, message_fields, ELEMENTSOF(message_fields));
+ if (r < 0)
+ return r;
+
+ if (realtime && monotonic)
+ break;
+ }
+ if (r < 0)
+ return r;
+
+ (void) parse_display_realtime(j, realtime, monotonic, ret);
+
+ /* Restart all data before */
+ sd_journal_restart_data(j);
+ sd_journal_restart_unique(j);
+ sd_journal_restart_fields(j);
+
+ return 0;
+}
+
static int output_verbose(
FILE *f,
sd_journal *j,
@@ -669,35 +773,38 @@ static int output_verbose(
OutputFlags flags,
const Set *output_fields,
const size_t highlight[2],
- const dual_timestamp *display_ts,
- const sd_id128_t *boot_id,
- const dual_timestamp *previous_display_ts,
- const sd_id128_t *previous_boot_id) {
+ dual_timestamp *previous_display_ts, /* unused */
+ sd_id128_t *previous_boot_id) { /* unused */
const void *data;
size_t length;
_cleanup_free_ char *cursor = NULL;
char buf[FORMAT_TIMESTAMP_MAX + 7];
const char *timestamp;
+ usec_t usec;
int r;
assert(f);
assert(j);
- assert(display_ts);
- assert(boot_id);
- assert(previous_display_ts);
- assert(previous_boot_id);
(void) sd_journal_set_data_threshold(j, 0);
- if (!VALID_REALTIME(display_ts->realtime))
+ r = get_display_realtime(j, &usec);
+ if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
+ log_debug_errno(r, "Skipping message we can't read: %m");
+ return 0;
+ }
+ if (r < 0)
+ return log_error_errno(r, "Failed to get journal fields: %m");
+
+ if (!VALID_REALTIME(usec))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No valid realtime timestamp available");
r = sd_journal_get_cursor(j, &cursor);
if (r < 0)
return log_error_errno(r, "Failed to get cursor: %m");
- timestamp = format_timestamp_style(buf, sizeof buf, display_ts->realtime,
+ timestamp = format_timestamp_style(buf, sizeof buf, usec,
flags & OUTPUT_UTC ? TIMESTAMP_US_UTC : TIMESTAMP_US);
fprintf(f, "%s%s%s %s[%s]%s\n",
timestamp && (flags & OUTPUT_COLOR) ? ANSI_UNDERLINE : "",
@@ -786,10 +893,8 @@ static int output_export(
OutputFlags flags,
const Set *output_fields,
const size_t highlight[2],
- const dual_timestamp *display_ts,
- const sd_id128_t *boot_id,
- const dual_timestamp *previous_display_ts,
- const sd_id128_t *previous_boot_id) {
+ dual_timestamp *previous_display_ts, /* unused */
+ sd_id128_t *previous_boot_id) { /* unused */
sd_id128_t journal_boot_id, seqnum_id;
_cleanup_free_ char *cursor = NULL;
@@ -800,10 +905,6 @@ static int output_export(
int r;
assert(j);
- assert(display_ts);
- assert(boot_id);
- assert(previous_display_ts);
- assert(previous_boot_id);
(void) sd_journal_set_data_threshold(j, 0);
@@ -1055,10 +1156,8 @@ static int output_json(
OutputFlags flags,
const Set *output_fields,
const size_t highlight[2],
- const dual_timestamp *display_ts,
- const sd_id128_t *boot_id,
- const dual_timestamp *previous_display_ts,
- const sd_id128_t *previous_boot_id) {
+ dual_timestamp *previous_display_ts, /* unused */
+ sd_id128_t *previous_boot_id) { /* unused */
char usecbuf[CONST_MAX(DECIMAL_STR_MAX(usec_t), DECIMAL_STR_MAX(uint64_t))];
_cleanup_(json_variant_unrefp) JsonVariant *object = NULL;
@@ -1073,10 +1172,6 @@ static int output_json(
int r;
assert(j);
- assert(display_ts);
- assert(boot_id);
- assert(previous_display_ts);
- assert(previous_boot_id);
(void) sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
@@ -1238,20 +1333,14 @@ static int output_cat(
OutputFlags flags,
const Set *output_fields,
const size_t highlight[2],
- const dual_timestamp *display_ts,
- const sd_id128_t *boot_id,
- const dual_timestamp *previous_display_ts,
- const sd_id128_t *previous_boot_id) {
+ dual_timestamp *previous_display_ts, /* unused */
+ sd_id128_t *previous_boot_id) { /* unused */
int r, prio = LOG_INFO;
const char *field;
assert(j);
assert(f);
- assert(display_ts);
- assert(boot_id);
- assert(previous_display_ts);
- assert(previous_boot_id);
(void) sd_journal_set_data_threshold(j, 0);
@@ -1291,63 +1380,6 @@ static int output_cat(
return 0;
}
-static int get_display_timestamp(
- sd_journal *j,
- dual_timestamp *ret_display_ts,
- sd_id128_t *ret_boot_id) {
-
- const void *data;
- _cleanup_free_ char *realtime = NULL, *monotonic = NULL;
- size_t length = 0, realtime_len = 0, monotonic_len = 0;
- const ParseFieldVec message_fields[] = {
- PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len),
- PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len),
- };
- int r;
- bool realtime_good = false, monotonic_good = false, boot_id_good = false;
-
- assert(j);
- assert(ret_display_ts);
- assert(ret_boot_id);
-
- JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
- r = parse_fieldv(data, length, message_fields, ELEMENTSOF(message_fields));
- if (r < 0)
- return r;
-
- if (realtime && monotonic)
- break;
- }
- if (r < 0)
- return r;
-
- if (realtime)
- realtime_good = safe_atou64(realtime, &ret_display_ts->realtime) >= 0;
- if (!realtime_good || !VALID_REALTIME(ret_display_ts->realtime))
- realtime_good = sd_journal_get_realtime_usec(j, &ret_display_ts->realtime) >= 0;
- if (!realtime_good)
- ret_display_ts->realtime = USEC_INFINITY;
-
- if (monotonic)
- monotonic_good = safe_atou64(monotonic, &ret_display_ts->monotonic) >= 0;
- if (!monotonic_good || !VALID_MONOTONIC(ret_display_ts->monotonic))
- monotonic_good = boot_id_good = sd_journal_get_monotonic_usec(j, &ret_display_ts->monotonic, ret_boot_id) >= 0;
- if (!monotonic_good)
- ret_display_ts->monotonic = USEC_INFINITY;
-
- if (!boot_id_good)
- boot_id_good = sd_journal_get_monotonic_usec(j, NULL, ret_boot_id) >= 0;
- if (!boot_id_good)
- *ret_boot_id = SD_ID128_NULL;
-
- /* Restart all data before */
- sd_journal_restart_data(j);
- sd_journal_restart_unique(j);
- sd_journal_restart_fields(j);
-
- return 0;
-}
-
typedef int (*output_func_t)(
FILE *f,
sd_journal *j,
@@ -1356,10 +1388,8 @@ typedef int (*output_func_t)(
OutputFlags flags,
const Set *output_fields,
const size_t highlight[2],
- const dual_timestamp *display_ts,
- const sd_id128_t *boot_id,
- const dual_timestamp *previous_display_ts,
- const sd_id128_t *previous_boot_id);
+ dual_timestamp *previous_display_ts,
+ sd_id128_t *previous_boot_id);
static output_func_t output_funcs[_OUTPUT_MODE_MAX] = {
@@ -1393,8 +1423,6 @@ int show_journal_entry(
dual_timestamp *previous_display_ts,
sd_id128_t *previous_boot_id) {
- dual_timestamp display_ts = DUAL_TIMESTAMP_NULL;
- sd_id128_t boot_id = SD_ID128_NULL;
int r;
assert(mode >= 0);
@@ -1405,14 +1433,6 @@ int show_journal_entry(
if (n_columns <= 0)
n_columns = columns();
- r = get_display_timestamp(j, &display_ts, &boot_id);
- if (IN_SET(r, -EBADMSG, -EADDRNOTAVAIL)) {
- log_debug_errno(r, "Skipping message we can't read: %m");
- return 0;
- }
- if (r < 0)
- return log_error_errno(r, "Failed to get journal fields: %m");
-
r = output_funcs[mode](
f,
j,
@@ -1421,15 +1441,9 @@ int show_journal_entry(
flags,
output_fields,
highlight,
- &display_ts,
- &boot_id,
previous_display_ts,
previous_boot_id);
- /* Store timestamp and boot ID for next iteration */
- *previous_display_ts = display_ts;
- *previous_boot_id = boot_id;
-
if (ellipsized && r > 0)
*ellipsized = true;
@@ -1570,202 +1584,115 @@ int show_journal(
}
int add_matches_for_unit(sd_journal *j, const char *unit) {
- const char *m1, *m2, *m3, *m4;
int r;
assert(j);
assert(unit);
- m1 = strjoina("_SYSTEMD_UNIT=", unit);
- m2 = strjoina("COREDUMP_UNIT=", unit);
- m3 = strjoina("UNIT=", unit);
- m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
-
- (void)(
+ (void) (
/* Look for messages from the service itself */
- (r = sd_journal_add_match(j, m1, 0)) ||
+ (r = journal_add_match_pair(j, "_SYSTEMD_UNIT", unit)) ||
/* Look for coredumps of the service */
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0)) ||
- (r = sd_journal_add_match(j, m2, 0)) ||
+ (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", SIZE_MAX)) ||
+ (r = sd_journal_add_match(j, "_UID=0", SIZE_MAX)) ||
+ (r = journal_add_match_pair(j, "COREDUMP_UNIT", unit)) ||
/* Look for messages from PID 1 about this service */
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, "_PID=1", 0)) ||
- (r = sd_journal_add_match(j, m3, 0)) ||
+ (r = sd_journal_add_match(j, "_PID=1", SIZE_MAX)) ||
+ (r = journal_add_match_pair(j, "UNIT", unit)) ||
/* Look for messages from authorized daemons about this service */
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0)) ||
- (r = sd_journal_add_match(j, m4, 0))
+ (r = sd_journal_add_match(j, "_UID=0", SIZE_MAX)) ||
+ (r = journal_add_match_pair(j, "OBJECT_SYSTEMD_UNIT", unit))
);
- if (r == 0 && endswith(unit, ".slice")) {
- const char *m5;
-
- m5 = strjoina("_SYSTEMD_SLICE=", unit);
-
+ if (r == 0 && endswith(unit, ".slice"))
/* Show all messages belonging to a slice */
- (void)(
+ (void) (
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m5, 0))
- );
- }
+ (r = journal_add_match_pair(j, "_SYSTEMD_SLICE", unit))
+ );
return r;
}
-int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
+int add_matches_for_user_unit(sd_journal *j, const char *unit) {
+ uid_t uid = getuid();
int r;
- char *m1, *m2, *m3, *m4;
- char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
assert(j);
assert(unit);
- m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
- m2 = strjoina("USER_UNIT=", unit);
- m3 = strjoina("COREDUMP_USER_UNIT=", unit);
- m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
- sprintf(muid, "_UID="UID_FMT, uid);
-
(void) (
/* Look for messages from the user service itself */
- (r = sd_journal_add_match(j, m1, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
+ (r = journal_add_match_pair(j, "_SYSTEMD_USER_UNIT", unit)) ||
+ (r = journal_add_matchf(j, "_UID="UID_FMT, uid)) ||
/* Look for messages from systemd about this service */
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m2, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
+ (r = journal_add_match_pair(j, "USER_UNIT", unit)) ||
+ (r = journal_add_matchf(j, "_UID="UID_FMT, uid)) ||
/* Look for coredumps of the service */
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m3, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0)) ||
+ (r = journal_add_match_pair(j, "COREDUMP_USER_UNIT", unit)) ||
+ (r = journal_add_matchf(j, "_UID="UID_FMT, uid)) ||
+ (r = sd_journal_add_match(j, "_UID=0", SIZE_MAX)) ||
/* Look for messages from authorized daemons about this service */
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m4, 0)) ||
- (r = sd_journal_add_match(j, muid, 0)) ||
- (r = sd_journal_add_match(j, "_UID=0", 0))
+ (r = journal_add_match_pair(j, "OBJECT_SYSTEMD_USER_UNIT", unit)) ||
+ (r = journal_add_matchf(j, "_UID="UID_FMT, uid)) ||
+ (r = sd_journal_add_match(j, "_UID=0", SIZE_MAX))
);
- if (r == 0 && endswith(unit, ".slice")) {
- const char *m5;
-
- m5 = strjoina("_SYSTEMD_USER_SLICE=", unit);
-
+ if (r == 0 && endswith(unit, ".slice"))
/* Show all messages belonging to a slice */
- (void)(
+ (void) (
(r = sd_journal_add_disjunction(j)) ||
- (r = sd_journal_add_match(j, m5, 0)) ||
- (r = sd_journal_add_match(j, muid, 0))
- );
- }
+ (r = journal_add_match_pair(j, "_SYSTEMD_USER_SLICE", unit)) ||
+ (r = journal_add_matchf(j, "_UID="UID_FMT, uid))
+ );
return r;
}
-static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
- _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
- _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, rootfd = -EBADF;
- char buf[SD_ID128_UUID_STRING_MAX];
- pid_t pid, child;
- ssize_t k;
+int add_match_boot_id(sd_journal *j, sd_id128_t id) {
int r;
- assert(machine);
- assert(boot_id);
-
- r = container_get_leader(machine, &pid);
- if (r < 0)
- return r;
-
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
- if (r < 0)
- return r;
-
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
- return -errno;
-
- r = namespace_fork("(sd-bootidns)", "(sd-bootid)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
- pidnsfd, mntnsfd, -1, -1, rootfd, &child);
- if (r < 0)
- return r;
- if (r == 0) {
- int fd;
-
- pair[0] = safe_close(pair[0]);
-
- fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- _exit(EXIT_FAILURE);
+ assert(j);
- r = loop_read_exact(fd, buf, 36, false);
- safe_close(fd);
+ if (sd_id128_is_null(id)) {
+ r = sd_id128_get_boot(&id);
if (r < 0)
- _exit(EXIT_FAILURE);
-
- k = send(pair[1], buf, 36, MSG_NOSIGNAL);
- if (k != 36)
- _exit(EXIT_FAILURE);
-
- _exit(EXIT_SUCCESS);
+ return log_error_errno(r, "Failed to get boot ID: %m");
}
- pair[1] = safe_close(pair[1]);
-
- r = wait_for_terminate_and_check("(sd-bootidns)", child, 0);
- if (r < 0)
- return r;
- if (r != EXIT_SUCCESS)
- return -EIO;
-
- k = recv(pair[0], buf, 36, 0);
- if (k != 36)
- return -EIO;
-
- buf[36] = 0;
- r = sd_id128_from_string(buf, boot_id);
+ r = journal_add_match_pair(j, "_BOOT_ID", SD_ID128_TO_STRING(id));
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to add match: %m");
return 0;
}
-int add_match_boot_id(sd_journal *j, sd_id128_t id) {
- char match[STRLEN("_BOOT_ID=") + SD_ID128_STRING_MAX];
-
- assert(j);
- assert(!sd_id128_is_null(id));
-
- sd_id128_to_string(id, stpcpy(match, "_BOOT_ID="));
- return sd_journal_add_match(j, match, strlen(match));
-}
-
int add_match_this_boot(sd_journal *j, const char *machine) {
sd_id128_t boot_id;
int r;
assert(j);
- if (machine) {
- r = get_boot_id_for_machine(machine, &boot_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
- } else {
- r = sd_id128_get_boot(&boot_id);
- if (r < 0)
- return log_error_errno(r, "Failed to get boot id: %m");
- }
+ r = id128_get_boot_for_machine(machine, &boot_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get boot ID%s%s: %m",
+ isempty(machine) ? "" : " of container ", strempty(machine));
r = add_match_boot_id(j, boot_id);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
+ return r;
r = sd_journal_add_conjunction(j);
if (r < 0)
@@ -1782,7 +1709,6 @@ int show_journal_by_unit(
unsigned n_columns,
usec_t not_before,
unsigned how_many,
- uid_t uid,
OutputFlags flags,
int journal_open_flags,
bool system_unit,
@@ -1798,14 +1724,17 @@ int show_journal_by_unit(
if (how_many <= 0)
return 0;
- r = sd_journal_open_namespace(&j, log_namespace, journal_open_flags | SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE);
+ r = sd_journal_open_namespace(&j, log_namespace,
+ journal_open_flags |
+ SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE |
+ SD_JOURNAL_ASSUME_IMMUTABLE);
if (r < 0)
return log_error_errno(r, "Failed to open journal: %m");
if (system_unit)
r = add_matches_for_unit(j, unit);
else
- r = add_matches_for_user_unit(j, unit, uid);
+ r = add_matches_for_user_unit(j, unit);
if (r < 0)
return log_error_errno(r, "Failed to add unit matches: %m");
@@ -1861,6 +1790,7 @@ static int discover_next_boot(
if (r < 0)
return r;
if (r == 0) {
+ sd_journal_flush_matches(j);
*ret = (BootId) {};
return 0; /* End of journal, yay. */
}
@@ -1911,7 +1841,7 @@ static int discover_next_boot(
goto try_again;
}
- r = sd_journal_get_realtime_usec(j, &boot.first_usec);
+ r = sd_journal_get_realtime_usec(j, advance_older ? &boot.last_usec : &boot.first_usec);
if (r < 0)
return r;
@@ -1933,7 +1863,7 @@ static int discover_next_boot(
goto try_again;
}
- r = sd_journal_get_realtime_usec(j, &boot.last_usec);
+ r = sd_journal_get_realtime_usec(j, advance_older ? &boot.first_usec : &boot.last_usec);
if (r < 0)
return r;
@@ -1979,37 +1909,9 @@ static int discover_next_boot(
}
}
-int journal_find_boot_by_id(sd_journal *j, sd_id128_t boot_id) {
- int r;
-
- assert(j);
- assert(!sd_id128_is_null(boot_id));
-
- sd_journal_flush_matches(j);
-
- r = add_match_boot_id(j, boot_id);
- if (r < 0)
- return r;
-
- r = sd_journal_seek_head(j); /* seek to oldest */
- if (r < 0)
- return r;
-
- r = sd_journal_next(j); /* read the oldest entry */
- if (r < 0)
- return r;
-
- /* At this point the read pointer is positioned at the oldest occurrence of the reference boot ID.
- * After flushing the matches, one more invocation of _previous() will hence place us at the
- * following entry, which must then have an older boot ID */
-
- sd_journal_flush_matches(j);
- return r > 0;
-}
-
-int journal_find_boot_by_offset(sd_journal *j, int offset, sd_id128_t *ret) {
+int journal_find_boot(sd_journal *j, sd_id128_t boot_id, int offset, sd_id128_t *ret) {
bool advance_older;
- int r;
+ int r, offset_start;
assert(j);
assert(ret);
@@ -2018,21 +1920,52 @@ int journal_find_boot_by_offset(sd_journal *j, int offset, sd_id128_t *ret) {
* (chronological) first boot in the journal. */
advance_older = offset <= 0;
- if (advance_older)
- r = sd_journal_seek_tail(j); /* seek to newest */
- else
- r = sd_journal_seek_head(j); /* seek to oldest */
- if (r < 0)
- return r;
+ sd_journal_flush_matches(j);
- /* No sd_journal_next()/_previous() here.
- *
- * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
- * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
- * entry we have. */
+ if (!sd_id128_is_null(boot_id)) {
+ r = add_match_boot_id(j, boot_id);
+ if (r < 0)
+ return r;
- sd_id128_t boot_id = SD_ID128_NULL;
- for (int off = !advance_older; ; off += advance_older ? -1 : 1) {
+ if (advance_older)
+ r = sd_journal_seek_head(j); /* seek to oldest */
+ else
+ r = sd_journal_seek_tail(j); /* seek to newest */
+ if (r < 0)
+ return r;
+
+ r = sd_journal_step_one(j, advance_older);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ sd_journal_flush_matches(j);
+ *ret = SD_ID128_NULL;
+ return false;
+ }
+ if (offset == 0) {
+ /* If boot ID is specified without an offset, then let's short cut the loop below. */
+ sd_journal_flush_matches(j);
+ *ret = boot_id;
+ return true;
+ }
+
+ offset_start = advance_older ? -1 : 1;
+ } else {
+ if (advance_older)
+ r = sd_journal_seek_tail(j); /* seek to newest */
+ else
+ r = sd_journal_seek_head(j); /* seek to oldest */
+ if (r < 0)
+ return r;
+
+ offset_start = advance_older ? 0 : 1;
+ }
+
+ /* At this point the cursor is positioned at the newest/oldest entry of the reference boot ID if
+ * specified, or whole journal otherwise. The next invocation of _previous()/_next() will hence
+ * position us at the newest/oldest entry we have. */
+
+ for (int off = offset_start; ; off += advance_older ? -1 : 1) {
BootId boot;
r = discover_next_boot(j, boot_id, advance_older, &boot);
@@ -2046,15 +1979,20 @@ int journal_find_boot_by_offset(sd_journal *j, int offset, sd_id128_t *ret) {
boot_id = boot.id;
log_debug("Found boot ID %s by offset %i", SD_ID128_TO_STRING(boot_id), off);
- if (off == offset)
- break;
+ if (off == offset) {
+ *ret = boot_id;
+ return true;
+ }
}
-
- *ret = boot_id;
- return true;
}
-int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
+int journal_get_boots(
+ sd_journal *j,
+ bool advance_older,
+ size_t max_ids,
+ BootId **ret_boots,
+ size_t *ret_n_boots) {
+
_cleanup_free_ BootId *boots = NULL;
size_t n_boots = 0;
int r;
@@ -2063,7 +2001,12 @@ int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
assert(ret_boots);
assert(ret_n_boots);
- r = sd_journal_seek_head(j); /* seek to oldest */
+ sd_journal_flush_matches(j);
+
+ if (advance_older)
+ r = sd_journal_seek_tail(j); /* seek to newest */
+ else
+ r = sd_journal_seek_head(j); /* seek to oldest */
if (r < 0)
return r;
@@ -2076,7 +2019,10 @@ int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
for (;;) {
BootId boot;
- r = discover_next_boot(j, previous_boot_id, /* advance_older = */ false, &boot);
+ if (n_boots >= max_ids)
+ break;
+
+ r = discover_next_boot(j, previous_boot_id, advance_older, &boot);
if (r < 0)
return r;
if (r == 0)
@@ -2090,10 +2036,8 @@ int journal_get_boots(sd_journal *j, BootId **ret_boots, size_t *ret_n_boots) {
* Exiting as otherwise this problem would cause an infinite loop. */
goto finish;
- if (!GREEDY_REALLOC(boots, n_boots + 1))
+ if (!GREEDY_REALLOC_APPEND(boots, n_boots, &boot, 1))
return -ENOMEM;
-
- boots[n_boots++] = boot;
}
finish: