X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Flogs-show.c;h=e179b8a7b4e20ddbca46bba2672b8c53c16a3907;hp=c99fc7569429d94324b1c5874baefc349591160e;hb=01c94c5d0aff09b4c0e429d483c8eeba40017071;hpb=b6741478e7661c7e580e5dcfd6a6fccd1899c1d0 diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index c99fc7569..e179b8a7b 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -20,9 +20,8 @@ ***/ #include -#include #include -#include +#include #include #include @@ -31,8 +30,8 @@ #include "util.h" #include "utf8.h" #include "hashmap.h" -#include "fileio.h" #include "journal-internal.h" +#include "formats-util.h" /* up to three lines (each up to 100 characters), or 300 characters, whichever is less */ @@ -123,6 +122,11 @@ static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, Output } } + /* A special case: make sure that we print a newline when + the message is empty. */ + if (message_len == 0) + fputs("\n", f); + for (pos = message; pos < message + message_len; pos = end + 1, line++) { @@ -289,10 +293,8 @@ static int output_short( if (r < 0) r = sd_journal_get_monotonic_usec(j, &t, &boot_id); - if (r < 0) { - log_error("Failed to get monotonic timestamp: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get monotonic timestamp: %m"); fprintf(f, "[%5llu.%06llu]", (unsigned long long) (t / USEC_PER_SEC), @@ -305,8 +307,10 @@ static int output_short( uint64_t x; time_t t; struct tm tm; + struct tm *(*gettime_r)(const time_t *, struct tm *); r = -ENOENT; + gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r; if (realtime) r = safe_atou64(realtime, &x); @@ -314,26 +318,24 @@ static int output_short( if (r < 0) r = sd_journal_get_realtime_usec(j, &x); - if (r < 0) { - log_error("Failed to get realtime timestamp: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get realtime timestamp: %m"); t = (time_t) (x / USEC_PER_SEC); switch(mode) { case OUTPUT_SHORT_ISO: - r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm)); + r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)); break; case OUTPUT_SHORT_PRECISE: - r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)); + r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)); if (r > 0) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - ".%06llu", x % USEC_PER_SEC); + ".%06llu", (unsigned long long) (x % USEC_PER_SEC)); } break; default: - r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)); + r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)); } if (r <= 0) { @@ -357,7 +359,7 @@ static int output_short( fprintf(f, " %.*s", (int) comm_len, comm); n += comm_len + 1; } else - fputc(' ', f); + fputs(" unknown", f); if (pid && shall_print(pid, pid_len, flags)) { fprintf(f, "[%.*s]", (int) pid_len, pid); @@ -414,12 +416,11 @@ static int output_verbose( r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size); if (r < 0) - log_debug("_SOURCE_REALTIME_TIMESTAMP invalid: %s", strerror(-r)); + log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m"); else { r = safe_atou64(value, &realtime); if (r < 0) - log_debug("Failed to parse realtime timestamp: %s", - strerror(-r)); + log_debug_errno(r, "Failed to parse realtime timestamp: %m"); } } @@ -433,12 +434,12 @@ static int output_verbose( } r = sd_journal_get_cursor(j, &cursor); - if (r < 0) { - log_error("Failed to get cursor: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get cursor: %m"); fprintf(f, "%s [%s]\n", + flags & OUTPUT_UTC ? + format_timestamp_us_utc(ts, sizeof(ts), realtime) : format_timestamp_us(ts, sizeof(ts), realtime), cursor); @@ -506,31 +507,25 @@ static int output_export( sd_journal_set_data_threshold(j, 0); r = sd_journal_get_realtime_usec(j, &realtime); - if (r < 0) { - log_error("Failed to get realtime timestamp: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get realtime timestamp: %m"); r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id); - if (r < 0) { - log_error("Failed to get monotonic timestamp: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get monotonic timestamp: %m"); r = sd_journal_get_cursor(j, &cursor); - if (r < 0) { - log_error("Failed to get cursor: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get cursor: %m"); fprintf(f, "__CURSOR=%s\n" - "__REALTIME_TIMESTAMP=%llu\n" - "__MONOTONIC_TIMESTAMP=%llu\n" + "__REALTIME_TIMESTAMP="USEC_FMT"\n" + "__MONOTONIC_TIMESTAMP="USEC_FMT"\n" "_BOOT_ID=%s\n", cursor, - (unsigned long long) realtime, - (unsigned long long) monotonic, + realtime, + monotonic, sd_id128_to_string(boot_id, sid)); JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) { @@ -541,7 +536,9 @@ static int output_export( startswith(data, "_BOOT_ID=")) continue; - if (!utf8_is_printable(data, length)) { + if (utf8_is_printable_newline(data, length, false)) + fwrite(data, length, 1, f); + else { const char *c; uint64_t le64; @@ -556,8 +553,7 @@ static int output_export( le64 = htole64(length - (c - (const char*) data) - 1); fwrite(&le64, sizeof(le64), 1, f); fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f); - } else - fwrite(data, length, 1, f); + } fputc('\n', f); } @@ -645,33 +641,27 @@ static int output_json( sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD); r = sd_journal_get_realtime_usec(j, &realtime); - if (r < 0) { - log_error("Failed to get realtime timestamp: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get realtime timestamp: %m"); r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id); - if (r < 0) { - log_error("Failed to get monotonic timestamp: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get monotonic timestamp: %m"); r = sd_journal_get_cursor(j, &cursor); - if (r < 0) { - log_error("Failed to get cursor: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get cursor: %m"); if (mode == OUTPUT_JSON_PRETTY) fprintf(f, "{\n" "\t\"__CURSOR\" : \"%s\",\n" - "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n" - "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n" + "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n" + "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n" "\t\"_BOOT_ID\" : \"%s\"", cursor, - (unsigned long long) realtime, - (unsigned long long) monotonic, + realtime, + monotonic, sd_id128_to_string(boot_id, sid)); else { if (mode == OUTPUT_JSON_SSE) @@ -679,16 +669,16 @@ static int output_json( fprintf(f, "{ \"__CURSOR\" : \"%s\", " - "\"__REALTIME_TIMESTAMP\" : \"%llu\", " - "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", " + "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", " + "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", " "\"_BOOT_ID\" : \"%s\"", cursor, - (unsigned long long) realtime, - (unsigned long long) monotonic, + realtime, + monotonic, sd_id128_to_string(boot_id, sid)); } - h = hashmap_new(string_hash_func, string_compare_func); + h = hashmap_new(&string_hash_ops); if (!h) return -ENOMEM; @@ -866,8 +856,7 @@ static int output_cat( if (r == -ENOENT) return 0; - log_error("Failed to get data: %s", strerror(-r)); - return r; + return log_error_errno(r, "Failed to get data: %m"); } assert(l >= 8); @@ -921,6 +910,21 @@ int output_journal( return ret; } +static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) { + assert(f); + assert(flags); + + if (!(*flags & OUTPUT_BEGIN_NEWLINE)) + return 0; + + /* Print a beginning new line if that's request, but only once + * on the first line we print. */ + + fputc('\n', f); + *flags &= ~OUTPUT_BEGIN_NEWLINE; + return 0; +} + static int show_journal(FILE *f, sd_journal *j, OutputMode mode, @@ -978,6 +982,7 @@ static int show_journal(FILE *f, } line ++; + maybe_print_begin_newline(f, &flags); r = output_journal(f, j, mode, n_columns, flags, ellipsized); if (r < 0) @@ -986,7 +991,7 @@ static int show_journal(FILE *f, if (warn_cutoff && line < how_many && not_before > 0) { sd_id128_t boot_id; - usec_t cutoff; + usec_t cutoff = 0; /* Check whether the cutoff line is too early */ @@ -998,8 +1003,10 @@ static int show_journal(FILE *f, if (r < 0) goto finish; - if (r > 0 && not_before < cutoff) + if (r > 0 && not_before < cutoff) { + maybe_print_begin_newline(f, &flags); fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n"); + } warn_cutoff = false; } @@ -1007,7 +1014,7 @@ static int show_journal(FILE *f, if (!(flags & OUTPUT_FOLLOW)) break; - r = sd_journal_wait(j, (usec_t) -1); + r = sd_journal_wait(j, USEC_INFINITY); if (r < 0) goto finish; @@ -1024,10 +1031,10 @@ int add_matches_for_unit(sd_journal *j, const char *unit) { assert(j); assert(unit); - m1 = strappenda("_SYSTEMD_UNIT=", unit); - m2 = strappenda("COREDUMP_UNIT=", unit); - m3 = strappenda("UNIT=", unit); - m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit); + m1 = strjoina("_SYSTEMD_UNIT=", unit); + m2 = strjoina("COREDUMP_UNIT=", unit); + m3 = strjoina("UNIT=", unit); + m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit); (void)( /* Look for messages from the service itself */ @@ -1071,11 +1078,11 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) { assert(j); assert(unit); - m1 = strappenda("_SYSTEMD_USER_UNIT=", unit); - m2 = strappenda("USER_UNIT=", unit); - m3 = strappenda("COREDUMP_USER_UNIT=", unit); - m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit); - sprintf(muid, "_UID=%lu", (unsigned long) uid); + 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 */ @@ -1115,10 +1122,8 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) { } static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { - _cleanup_free_ char *leader = NULL, *class = NULL; - _cleanup_close_pipe_ int sock[2] = { -1, -1 }; - _cleanup_close_ int nsfd = -1; - const char *p, *ns; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1; pid_t pid, child; siginfo_t si; char buf[37]; @@ -1128,29 +1133,18 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { assert(machine); assert(boot_id); - if (!filename_is_safe(machine)) + if (!machine_name_is_valid(machine)) return -EINVAL; - p = strappenda("/run/systemd/machines/", machine); - - r = parse_env_file(p, NEWLINE, "LEADER", &leader, "CLASS", &class, NULL); + r = container_get_leader(machine, &pid); if (r < 0) return r; - if (!leader) - return -ENODATA; - if (!streq_ptr(class, "container")) - return -EIO; - r = parse_pid(leader, &pid); + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd); if (r < 0) return r; - ns = procfs_file_alloca(pid, "ns/mnt"); - - nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (nsfd < 0) - return -errno; - - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0) + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) return -errno; child = fork(); @@ -1160,10 +1154,9 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { if (child == 0) { int fd; - close_nointr_nofail(sock[0]); - sock[0] = -1; + pair[0] = safe_close(pair[0]); - r = setns(nsfd, CLONE_NEWNS); + r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd); if (r < 0) _exit(EXIT_FAILURE); @@ -1171,29 +1164,28 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { if (fd < 0) _exit(EXIT_FAILURE); - k = loop_read(fd, buf, 36, false); - close_nointr_nofail(fd); - if (k != 36) + r = loop_read_exact(fd, buf, 36, false); + safe_close(fd); + if (r < 0) _exit(EXIT_FAILURE); - k = send(sock[1], buf, 36, MSG_NOSIGNAL); + k = send(pair[1], buf, 36, MSG_NOSIGNAL); if (k != 36) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); } - close_nointr_nofail(sock[1]); - sock[1] = -1; - - k = recv(sock[0], buf, 36, 0); - if (k != 36) - return -EIO; + pair[1] = safe_close(pair[1]); r = wait_for_terminate(child, &si); if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) return r < 0 ? r : -EIO; + k = recv(pair[0], buf, 36, 0); + if (k != 36) + return -EIO; + buf[36] = 0; r = sd_id128_from_string(buf, boot_id); if (r < 0) @@ -1211,24 +1203,18 @@ int add_match_this_boot(sd_journal *j, const char *machine) { if (machine) { r = get_boot_id_for_machine(machine, &boot_id); - if (r < 0) { - log_error("Failed to get boot id of container %s: %s", machine, strerror(-r)); - return r; - } + 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) { - log_error("Failed to get boot id: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get boot id: %m"); } sd_id128_to_string(boot_id, match + 9); r = sd_journal_add_match(j, match, strlen(match)); - if (r < 0) { - log_error("Failed to add match: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); r = sd_journal_add_conjunction(j); if (r < 0) @@ -1246,12 +1232,12 @@ int show_journal_by_unit( unsigned how_many, uid_t uid, OutputFlags flags, - bool system, + int journal_open_flags, + bool system_unit, bool *ellipsized) { _cleanup_journal_close_ sd_journal*j = NULL; int r; - int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM; assert(mode >= 0); assert(mode < _OUTPUT_MODE_MAX); @@ -1260,7 +1246,7 @@ int show_journal_by_unit( if (how_many <= 0) return 0; - r = sd_journal_open(&j, jflags); + r = sd_journal_open(&j, journal_open_flags); if (r < 0) return r; @@ -1268,14 +1254,14 @@ int show_journal_by_unit( if (r < 0) return r; - if (system) + if (system_unit) r = add_matches_for_unit(j, unit); else r = add_matches_for_user_unit(j, unit, uid); if (r < 0) return r; - if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) { + if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) { _cleanup_free_ char *filter; filter = journal_make_match_string(j);