From 96a7f3fc75c4ba39129b5205911e8b1dca53f197 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 22 Mar 2024 04:19:42 +0900 Subject: [PATCH] journalctl-filter: several cleanups for add_matches() - split it into small pieces to reduce indentation, - return earlier if no filter specified, - use journal_add_matchf() and journal_add_match_pair(), chase_and_stat(), is_symlink(), and sd_device_new_from_devname(), - replace sd_device_get_devname() + stat() with sd_device_get_devnum(), - refuse to install filter by path with --root, --image, or --machine at least now, as previously it has not worked anyway. --- src/journal/journalctl-filter.c | 174 +++++++++++++++----------------- 1 file changed, 82 insertions(+), 92 deletions(-) diff --git a/src/journal/journalctl-filter.c b/src/journal/journalctl-filter.c index f013c42470a..3129e776769 100644 --- a/src/journal/journalctl-filter.c +++ b/src/journal/journalctl-filter.c @@ -314,30 +314,50 @@ static int add_facilities(sd_journal *j) { return sd_journal_add_conjunction(j); } +static int add_matches_for_executable(sd_journal *j, const char *path) { + _cleanup_free_ char *interpreter = NULL; + int r; + + assert(j); + assert(path); + + if (executable_is_script(path, &interpreter) > 0) { + _cleanup_free_ char *comm = NULL; + + r = path_extract_filename(path, &comm); + if (r < 0) + return log_error_errno(r, "Failed to extract filename of '%s': %m", path); + + r = journal_add_match_pair(j, "_COMM", strshorten(comm, TASK_COMM_LEN-1)); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + + /* Append _EXE only if the interpreter is not a link. Otherwise, it might be outdated often. */ + path = is_symlink(interpreter) > 0 ? interpreter : NULL; + } + + if (path) { + r = journal_add_match_pair(j, "_EXE", path); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + } + + return 0; +} + static int add_matches_for_device(sd_journal *j, const char *devpath) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; - sd_device *d = NULL; - struct stat st; int r; assert(j); assert(devpath); - if (!path_startswith(devpath, "/dev/")) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Devpath does not start with /dev/"); - - if (stat(devpath, &st) < 0) - return log_error_errno(errno, "Couldn't stat file: %m"); - - r = sd_device_new_from_stat_rdev(&device, &st); + r = sd_device_new_from_devname(&device, devpath); if (r < 0) - return log_error_errno(r, "Failed to get device from devnum " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(st.st_rdev)); + return log_error_errno(r, "Failed to get device '%s': %m", devpath); - for (d = device; d; ) { - _cleanup_free_ char *match = NULL; - const char *subsys, *sysname, *devnode; - sd_device *parent; + for (sd_device *d = device; d; ) { + const char *subsys, *sysname; r = sd_device_get_subsystem(d, &subsys); if (r < 0) @@ -347,35 +367,22 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) { if (r < 0) goto get_parent; - match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname); - if (!match) - return log_oom(); - - r = sd_journal_add_match(j, match, 0); + r = journal_add_matchf(j, "_KERNEL_DEVICE=+%s:%s", subsys, sysname); if (r < 0) return log_error_errno(r, "Failed to add match: %m"); - if (sd_device_get_devname(d, &devnode) >= 0) { - _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" DEVNUM_FORMAT_STR, S_ISBLK(st.st_mode) ? 'b' : 'c', DEVNUM_FORMAT_VAL(st.st_rdev)); - if (r < 0) - return log_oom(); - - r = sd_journal_add_match(j, match1, 0); + dev_t devnum; + if (sd_device_get_devnum(d, &devnum) >= 0) { + r = journal_add_matchf(j, "_KERNEL_DEVICE=%c" DEVNUM_FORMAT_STR, + streq(subsys, "block") ? 'b' : 'c', + DEVNUM_FORMAT_VAL(devnum)); if (r < 0) return log_error_errno(r, "Failed to add match: %m"); } get_parent: - if (sd_device_get_parent(d, &parent) < 0) + if (sd_device_get_parent(d, &d) < 0) break; - - d = parent; } r = add_match_this_boot(j, arg_machine); @@ -385,83 +392,66 @@ get_parent: return 0; } +static int add_matches_for_path(sd_journal *j, const char *path) { + _cleanup_free_ char *p = NULL; + struct stat st; + int r; + + assert(j); + assert(path); + + if (arg_root || arg_machine) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "An extra path in match filter is currently not supported with --root, --image, or -M/--machine."); + + r = chase_and_stat(path, NULL, 0, &p, &st); + if (r < 0) + return log_error_errno(r, "Couldn't canonicalize path '%s': %m", path); + + if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) + return add_matches_for_executable(j, p); + + if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) + return add_matches_for_device(j, p); + + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File is neither a device node nor executable: %s", p); +} + static int add_matches(sd_journal *j, char **args) { bool have_term = false; + int r; assert(j); - STRV_FOREACH(i, args) { - int r; + if (strv_isempty(args)) + return 0; + STRV_FOREACH(i, args) if (streq(*i, "+")) { if (!have_term) break; + r = sd_journal_add_disjunction(j); + if (r < 0) + return log_error_errno(r, "Failed to add disjunction: %m"); + have_term = false; } else if (path_is_absolute(*i)) { - _cleanup_free_ char *p = NULL, *t = NULL, *t2 = NULL, *interpreter = NULL; - struct stat st; - - r = chase(*i, NULL, CHASE_TRAIL_SLASH, &p, NULL); + r = add_matches_for_path(j, *i); if (r < 0) - return log_error_errno(r, "Couldn't canonicalize path: %m"); - - if (lstat(p, &st) < 0) - return log_error_errno(errno, "Couldn't stat file: %m"); - - if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) { - if (executable_is_script(p, &interpreter) > 0) { - _cleanup_free_ char *comm = NULL; - - r = path_extract_filename(p, &comm); - if (r < 0) - return log_error_errno(r, "Failed to extract filename of '%s': %m", p); - - t = strjoin("_COMM=", strshorten(comm, TASK_COMM_LEN-1)); - 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)) { - t2 = strjoin("_EXE=", interpreter); - if (!t2) - return log_oom(); - } - } else { - t = strjoin("_EXE=", p); - 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, p); - if (r < 0) - return r; - } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "File is neither a device node, nor regular file, nor executable: %s", - *i); - + return r; have_term = true; + } else { r = sd_journal_add_match(j, *i, 0); + if (r < 0) + return log_error_errno(r, "Failed to add match '%s': %m", *i); have_term = true; } - if (r < 0) - return log_error_errno(r, "Failed to add match '%s': %m", *i); - } - - if (!strv_isempty(args) && !have_term) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "\"+\" can only be used between terms"); + if (!have_term) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "\"+\" can only be used between terms."); return 0; } -- 2.47.3