journalctl: reject field listing with filters
Reproducer: journalctl -F _SYSTEMD_UNIT -u test.service --no-pager journalctl -u test.service --no-pager -n 1 Before, the field listing ignored the unit filter and listed unrelated units, while the normal journal query applied the filter. sd_journal_query_unique() cannot represent journalctl filters such as unit, boot, time, cursor, or grep filters. Walking the journal line by line would make field listing linear in the number of entries and duplicate unique-value handling. Keep the scope-option predicate next to add_filters(), and reject field listings combined with options that actually limit the journal. Display-only options such as --pager-end are left alone.
This commit is contained in:
committed by
Yu Watanabe
parent
7cb8728d59
commit
cb7b533b92
@@ -23,6 +23,25 @@
|
||||
#include "strv.h"
|
||||
#include "unit-name.h"
|
||||
|
||||
bool field_list_has_scope_options(void) {
|
||||
return
|
||||
arg_boot_filter ||
|
||||
arg_invocation ||
|
||||
arg_dmesg ||
|
||||
arg_cursor ||
|
||||
arg_after_cursor ||
|
||||
arg_cursor_file ||
|
||||
!strv_isempty(arg_system_units) ||
|
||||
!strv_isempty(arg_user_units) ||
|
||||
!strv_isempty(arg_syslog_identifier) ||
|
||||
!strv_isempty(arg_exclude_identifier) ||
|
||||
arg_priorities != 0 ||
|
||||
!set_isempty(arg_facilities) ||
|
||||
arg_since_set ||
|
||||
arg_until_set ||
|
||||
arg_pattern;
|
||||
}
|
||||
|
||||
static int add_invocation(sd_journal *j) {
|
||||
int r;
|
||||
|
||||
|
||||
@@ -11,4 +11,5 @@ int journal_add_unit_matches(
|
||||
uid_t uid,
|
||||
char * const *user_units);
|
||||
|
||||
bool field_list_has_scope_options(void);
|
||||
int add_filters(sd_journal *j, char **matches);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "journalctl.h"
|
||||
#include "journalctl-authenticate.h"
|
||||
#include "journalctl-catalog.h"
|
||||
#include "journalctl-filter.h"
|
||||
#include "journalctl-metrics.h"
|
||||
#include "journalctl-misc.h"
|
||||
#include "journalctl-show.h"
|
||||
@@ -70,6 +71,7 @@ bool arg_merge = false;
|
||||
int arg_boot = -1; /* tristate */
|
||||
sd_id128_t arg_boot_id = {};
|
||||
int arg_boot_offset = 0;
|
||||
bool arg_boot_filter = false;
|
||||
bool arg_dmesg = false;
|
||||
bool arg_no_hostname = false;
|
||||
char *arg_cursor = NULL;
|
||||
@@ -532,6 +534,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
|
||||
|
||||
OPTION_LONG("this-boot", NULL, /* help= */ NULL):
|
||||
arg_boot = true;
|
||||
arg_boot_filter = true;
|
||||
arg_boot_id = SD_ID128_NULL;
|
||||
arg_boot_offset = 0;
|
||||
break;
|
||||
@@ -539,6 +542,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
|
||||
OPTION_FULL(OPTION_OPTIONAL_ARG, 'b', "boot", "ID",
|
||||
"Show current boot or the specified boot"):
|
||||
arg_boot = true;
|
||||
arg_boot_filter = true;
|
||||
arg_boot_id = SD_ID128_NULL;
|
||||
arg_boot_offset = 0;
|
||||
|
||||
@@ -548,6 +552,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
|
||||
return log_error_errno(r, "Failed to parse boot descriptor '%s'", opts.arg);
|
||||
|
||||
arg_boot = r;
|
||||
arg_boot_filter = r > 0;
|
||||
|
||||
} else {
|
||||
/* Hmm, no argument? Maybe the next word on the command line is supposed to
|
||||
@@ -558,6 +563,7 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
|
||||
r = parse_id_descriptor(peek, &arg_boot_id, &arg_boot_offset);
|
||||
if (r >= 0) {
|
||||
arg_boot = r;
|
||||
arg_boot_filter = r > 0;
|
||||
(void) option_parser_consume_next_arg(&opts);
|
||||
}
|
||||
}
|
||||
@@ -976,6 +982,10 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) {
|
||||
"Extraneous arguments starting with '%s'",
|
||||
args[0]);
|
||||
|
||||
if (IN_SET(arg_action, ACTION_LIST_FIELDS, ACTION_LIST_FIELD_NAMES) && field_list_has_scope_options())
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"-F/--field= and -N/--fields cannot be combined with options that limit the journal.");
|
||||
|
||||
if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Using --boot or --list-boots with --merge is not supported.");
|
||||
|
||||
@@ -45,6 +45,7 @@ extern bool arg_merge;
|
||||
extern int arg_boot;
|
||||
extern sd_id128_t arg_boot_id;
|
||||
extern int arg_boot_offset;
|
||||
extern bool arg_boot_filter;
|
||||
extern bool arg_dmesg;
|
||||
extern bool arg_no_hostname;
|
||||
extern char *arg_cursor;
|
||||
|
||||
@@ -158,6 +158,10 @@ journalctl --root / | grep . >/dev/null
|
||||
journalctl --cursor "t=0;t=-1;t=0;t=0x0" | grep . >/dev/null
|
||||
journalctl --header | grep system.journal
|
||||
journalctl --field _EXE | grep . >/dev/null
|
||||
journalctl --field _EXE --pager-end | grep . >/dev/null
|
||||
(! journalctl -q --field _SYSTEMD_UNIT --unit "test-no-such-unit-$RANDOM.service" --no-pager)
|
||||
(! journalctl -q --field _SYSTEMD_UNIT --since "9999-01-01" --no-pager)
|
||||
(! journalctl -q --fields --unit "test-no-such-unit-$RANDOM.service" --no-pager)
|
||||
journalctl --no-hostname --utc --catalog | grep . >/dev/null
|
||||
# Exercise executable_is_script() and the related code, e.g. `journalctl -b /path/to/a/script.sh` should turn
|
||||
# into ((_EXE=/usr/bin/bash AND _COMM=script.sh) AND _BOOT_ID=c002e3683ba14fa8b6c1e12878386514)
|
||||
|
||||
Reference in New Issue
Block a user