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.
This commit is contained in:
Yu Watanabe
2024-03-26 23:51:47 +09:00
parent bb59f34c21
commit 96a7f3fc75
+82 -92
View File
@@ -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;
}