diff options
Diffstat (limited to 'src/shared/logs-show.c')
-rw-r--r-- | src/shared/logs-show.c | 642 |
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: |