From 1c33de9e1370bc56e10f3b5306e27c8aa6a18873 Mon Sep 17 00:00:00 2001 From: Michal Sekletar Date: Mon, 1 Feb 2016 10:44:58 +0100 Subject: [PATCH] journalctl: make "journalctl /dev/sda" work Currently when journalctl is called with path to block device node we add following match _KERNEL_DEVICE=b$MAJOR:$MINOR. That is not sufficient to actually obtain logs about the disk because dev_printk() kernel helper puts to /dev/kmsg information about the device in following format, +$SUBSYSTEM:$ADDRESS, e.g. "+pci:pci:0000:00:14.0". Now we will walk upward the syspath and add match for every device in format produced by dev_printk() as well as match for its device node if it exists. Cherry-picked from: 795ab08f783e78e85f1493879f13ac44cb113b00 Resolves: #947636 --- Makefile.am | 3 +- src/journal/journalctl.c | 118 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 97 insertions(+), 24 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2645f66..2559376 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4245,7 +4245,8 @@ journalctl_LDADD = \ libsystemd-journal-internal.la \ libsystemd-internal.la \ libsystemd-logs.la \ - libsystemd-shared.la + libsystemd-shared.la \ + libudev-core.la if HAVE_ACL journalctl_LDADD += \ diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 836d7d2..3db1cd2 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -63,6 +63,8 @@ #include "mkdir.h" #include "bus-util.h" #include "bus-error.h" +#include "udev.h" +#include "udev-util.h" #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) @@ -134,6 +136,80 @@ typedef struct boot_id_t { LIST_FIELDS(struct boot_id_t, boot_list); } boot_id_t; +static int add_matches_for_device(sd_journal *j, const char *devpath) { + int r; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + struct udev_device *d = NULL; + struct stat st; + + assert(j); + assert(devpath); + + if (!path_startswith(devpath, "/dev/")) { + log_error("Devpath does not start with /dev/"); + return -EINVAL; + } + + udev = udev_new(); + if (!udev) + return log_oom(); + + r = stat(devpath, &st); + if (r < 0) + log_error_errno(errno, "Couldn't stat file: %m"); + + d = device = udev_device_new_from_devnum(udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev); + if (!device) + return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev)); + + while (d) { + _cleanup_free_ char *match = NULL; + const char *subsys, *sysname, *devnode; + + subsys = udev_device_get_subsystem(d); + if (!subsys) { + d = udev_device_get_parent(d); + continue; + } + + sysname = udev_device_get_sysname(d); + if (!sysname) { + d = udev_device_get_parent(d); + continue; + } + + match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname, NULL); + if (!match) + return log_oom(); + + r = sd_journal_add_match(j, match, 0); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + + devnode = udev_device_get_devnode(d); + if (devnode) { + _cleanup_free_ char *match1 = NULL; + + r = stat(devnode, &st); + if (r < 0) + return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode); + + r = asprintf(&match1, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st.st_mode) ? 'b' : 'c', major(st.st_rdev), minor(st.st_rdev)); + if (r < 0) + return log_oom(); + + r = sd_journal_add_match(j, match1, 0); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + } + + d = udev_device_get_parent(d); + } + + return 0; +} + static void pager_open_if_enabled(void) { if (arg_no_pager) @@ -788,13 +864,12 @@ static int add_matches(sd_journal *j, char **args) { have_term = false; } else if (path_is_absolute(*i)) { - _cleanup_free_ char *p, *t = NULL, *t2 = NULL; + _cleanup_free_ char *p, *t = NULL, *t2 = NULL, *interpreter = NULL; const char *path; - _cleanup_free_ char *interpreter = NULL; struct stat st; p = canonicalize_file_name(*i); - path = p ? p : *i; + path = p ?: *i; if (stat(path, &st) < 0) return log_error_errno(errno, "Couldn't stat file: %m"); @@ -808,40 +883,37 @@ static int add_matches(sd_journal *j, char **args) { return log_oom(); t = strappend("_COMM=", comm); + if (!t) + return log_oom(); /* Append _EXE only if the interpreter is not a link. Otherwise, it might be outdated often. */ - if (lstat(interpreter, &st) == 0 && - !S_ISLNK(st.st_mode)) { + if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) { t2 = strappend("_EXE=", interpreter); if (!t2) return log_oom(); } - } else + } else { t = strappend("_EXE=", path); - } else if (S_ISCHR(st.st_mode)) { - if (asprintf(&t, "_KERNEL_DEVICE=c%u:%u", - major(st.st_rdev), - minor(st.st_rdev)) < 0) - return -ENOMEM; - } else if (S_ISBLK(st.st_mode)) { - if (asprintf(&t, "_KERNEL_DEVICE=b%u:%u", - major(st.st_rdev), - minor(st.st_rdev)) < 0) - return -ENOMEM; + if (!t) + return log_oom(); + } + + r = sd_journal_add_match(j, t, 0); + + if (r >=0 && t2) + r = sd_journal_add_match(j, t2, 0); + + } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { + r = add_matches_for_device(j, path); + if (r < 0) + return r; } else { log_error("File is neither a device node, nor regular file, nor executable: %s", *i); return -EINVAL; } - if (!t) - return log_oom(); - - r = sd_journal_add_match(j, t, 0); - if (t2) - r = sd_journal_add_match(j, t2, 0); have_term = true; - } else { r = sd_journal_add_match(j, *i, 0); have_term = true;