From 9bd3f4297dd22dc2268fcdeaa6b3c1da0bbf27c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 11 May 2026 16:25:59 +0200 Subject: [PATCH 1/6] journalctl: reorder parse_argv() cases to match --help Pure reordering. ARG_SMART_RELINQUISH_VAR is kept immediately before ARG_RELINQUISH_VAR because of the existing _fallthrough_; that's the only deviation from strict --help order. Co-developed-by: Claude Opus 4.7 --- src/journal/journalctl.c | 580 +++++++++++++++++++-------------------- 1 file changed, 290 insertions(+), 290 deletions(-) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index b25827961f2..2aeeeb55314 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -525,124 +525,6 @@ static int parse_argv(int argc, char *argv[]) { switch (c) { - case 'h': - return help(); - - case ARG_VERSION: - return version(); - - case ARG_NO_PAGER: - arg_pager_flags |= PAGER_DISABLE; - break; - - case 'e': - arg_pager_flags |= PAGER_JUMP_TO_END; - break; - - case 'f': - arg_follow = true; - break; - - case 'o': - if (streq(optarg, "help")) - return DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX); - - arg_output = output_mode_from_string(optarg); - if (arg_output < 0) - return log_error_errno(arg_output, "Unknown output format '%s'.", optarg); - - if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT)) - arg_quiet = true; - - if (OUTPUT_MODE_IS_JSON(arg_output)) - arg_json_format_flags = output_mode_to_json_format_flags(arg_output) | SD_JSON_FORMAT_COLOR_AUTO; - else - arg_json_format_flags = SD_JSON_FORMAT_OFF; - - break; - - case 'l': - arg_full = true; - break; - - case ARG_NO_FULL: - arg_full = false; - break; - - case 'a': - arg_all = true; - break; - - case 'n': - r = parse_lines(optarg ?: argv[optind], !optarg); - if (r < 0) - return r; - if (r > 0 && !optarg) - optind++; - - break; - - case ARG_NO_TAIL: - arg_no_tail = true; - break; - - case ARG_TRUNCATE_NEWLINE: - arg_truncate_newline = true; - break; - - case ARG_NEW_ID128: - arg_action = ACTION_NEW_ID128; - break; - - case 'q': - arg_quiet = true; - break; - - case 'm': - arg_merge = true; - break; - - case ARG_THIS_BOOT: - arg_boot = true; - arg_boot_id = SD_ID128_NULL; - arg_boot_offset = 0; - break; - - case 'b': - arg_boot = true; - arg_boot_id = SD_ID128_NULL; - arg_boot_offset = 0; - - if (optarg) { - r = parse_id_descriptor(optarg, &arg_boot_id, &arg_boot_offset); - if (r < 0) - return log_error_errno(r, "Failed to parse boot descriptor '%s'", optarg); - - arg_boot = r; - - } else if (optind < argc) { - /* Hmm, no argument? Maybe the next word on the command line is supposed to be the - * argument? Let's see if there is one and is parsable as a boot descriptor... */ - r = parse_id_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset); - if (r >= 0) { - arg_boot = r; - optind++; - } - } - break; - - case ARG_LIST_BOOTS: - arg_action = ACTION_LIST_BOOTS; - break; - - case ARG_LIST_INVOCATIONS: - arg_action = ACTION_LIST_INVOCATIONS; - break; - - case 'k': - arg_dmesg = true; - break; - case ARG_SYSTEM: arg_journal_type |= SD_JOURNAL_SYSTEM; break; @@ -657,28 +539,8 @@ static int parse_argv(int argc, char *argv[]) { return r; break; - case ARG_NAMESPACE: - if (streq(optarg, "*")) { - arg_namespace_flags = SD_JOURNAL_ALL_NAMESPACES; - arg_namespace = mfree(arg_namespace); - } else if (startswith(optarg, "+")) { - arg_namespace_flags = SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE; - r = free_and_strdup_warn(&arg_namespace, optarg + 1); - if (r < 0) - return r; - } else if (isempty(optarg)) { - arg_namespace_flags = 0; - arg_namespace = mfree(arg_namespace); - } else { - arg_namespace_flags = 0; - r = free_and_strdup_warn(&arg_namespace, optarg); - if (r < 0) - return r; - } - break; - - case ARG_LIST_NAMESPACES: - arg_action = ACTION_LIST_NAMESPACES; + case 'm': + arg_merge = true; break; case 'D': @@ -719,14 +581,44 @@ static int parse_argv(int argc, char *argv[]) { return r; break; - case 'c': - r = free_and_strdup_warn(&arg_cursor, optarg); - if (r < 0) - return r; + case ARG_NAMESPACE: + if (streq(optarg, "*")) { + arg_namespace_flags = SD_JOURNAL_ALL_NAMESPACES; + arg_namespace = mfree(arg_namespace); + } else if (startswith(optarg, "+")) { + arg_namespace_flags = SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE; + r = free_and_strdup_warn(&arg_namespace, optarg + 1); + if (r < 0) + return r; + } else if (isempty(optarg)) { + arg_namespace_flags = 0; + arg_namespace = mfree(arg_namespace); + } else { + arg_namespace_flags = 0; + r = free_and_strdup_warn(&arg_namespace, optarg); + if (r < 0) + return r; + } break; - case ARG_CURSOR_FILE: - r = free_and_strdup_warn(&arg_cursor_file, optarg); + case 'S': + r = parse_timestamp(optarg, &arg_since); + if (r < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to parse timestamp: %s", optarg); + arg_since_set = true; + break; + + case 'U': + r = parse_timestamp(optarg, &arg_until); + if (r < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Failed to parse timestamp: %s", optarg); + arg_until_set = true; + break; + + case 'c': + r = free_and_strdup_warn(&arg_cursor, optarg); if (r < 0) return r; break; @@ -737,83 +629,78 @@ static int parse_argv(int argc, char *argv[]) { return r; break; - case ARG_SHOW_CURSOR: - arg_show_cursor = true; - break; - - case ARG_HEADER: - arg_action = ACTION_PRINT_HEADER; - break; - - case ARG_VERIFY: - arg_action = ACTION_VERIFY; - break; - - case ARG_DISK_USAGE: - arg_action = ACTION_DISK_USAGE; - break; - - case ARG_VACUUM_SIZE: - r = parse_size(optarg, 1024, &arg_vacuum_size); + case ARG_CURSOR_FILE: + r = free_and_strdup_warn(&arg_cursor_file, optarg); if (r < 0) - return log_error_errno(r, "Failed to parse vacuum size: %s", optarg); - - arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; + return r; break; - case ARG_VACUUM_FILES: - r = safe_atou64(optarg, &arg_vacuum_n_files); + case ARG_THIS_BOOT: + arg_boot = true; + arg_boot_id = SD_ID128_NULL; + arg_boot_offset = 0; + break; + + case 'b': + arg_boot = true; + arg_boot_id = SD_ID128_NULL; + arg_boot_offset = 0; + + if (optarg) { + r = parse_id_descriptor(optarg, &arg_boot_id, &arg_boot_offset); + if (r < 0) + return log_error_errno(r, "Failed to parse boot descriptor '%s'", optarg); + + arg_boot = r; + + } else if (optind < argc) { + /* Hmm, no argument? Maybe the next word on the command line is supposed to be the + * argument? Let's see if there is one and is parsable as a boot descriptor... */ + r = parse_id_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset); + if (r >= 0) { + arg_boot = r; + optind++; + } + } + break; + + case 'u': + r = strv_extend(&arg_system_units, optarg); if (r < 0) - return log_error_errno(r, "Failed to parse vacuum files: %s", optarg); - - arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; - break; - - case ARG_VACUUM_TIME: - r = parse_sec(optarg, &arg_vacuum_time); - if (r < 0) - return log_error_errno(r, "Failed to parse vacuum time: %s", optarg); - - arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; - break; - -#if HAVE_GCRYPT - case ARG_FORCE: - arg_force = true; - break; - - case ARG_SETUP_KEYS: - arg_action = ACTION_SETUP_KEYS; - break; - - case ARG_VERIFY_KEY: - erase_and_free(arg_verify_key); - arg_verify_key = strdup(optarg); - if (!arg_verify_key) return log_oom(); - - /* Use memset not explicit_bzero() or similar so this doesn't look confusing - * in ps or htop output. */ - memset(optarg, 'x', strlen(optarg)); - - arg_action = ACTION_VERIFY; - arg_merge = false; break; - case ARG_INTERVAL: - r = parse_sec(optarg, &arg_interval); - if (r < 0 || arg_interval <= 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse sealing key change interval: %s", optarg); + case ARG_USER_UNIT: + r = strv_extend(&arg_user_units, optarg); + if (r < 0) + return log_oom(); + break; + + case ARG_INVOCATION: + r = parse_id_descriptor(optarg, &arg_invocation_id, &arg_invocation_offset); + if (r < 0) + return log_error_errno(r, "Failed to parse invocation descriptor: %s", optarg); + arg_invocation = r; + break; + + case 'I': + /* Equivalent to --invocation=0 */ + arg_invocation = true; + arg_invocation_id = SD_ID128_NULL; + arg_invocation_offset = 0; + break; + + case 't': + r = strv_extend(&arg_syslog_identifier, optarg); + if (r < 0) + return log_oom(); + break; + + case 'T': + r = strv_extend(&arg_exclude_identifier, optarg); + if (r < 0) + return log_oom(); break; -#else - case ARG_SETUP_KEYS: - case ARG_VERIFY_KEY: - case ARG_INTERVAL: - case ARG_FORCE: - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "Compiled without forward-secure sealing support."); -#endif case 'p': { const char *dots; @@ -907,58 +794,160 @@ static int parse_argv(int argc, char *argv[]) { break; - case 'S': - r = parse_timestamp(optarg, &arg_since); + case 'k': + arg_dmesg = true; + break; + + case 'o': + if (streq(optarg, "help")) + return DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX); + + arg_output = output_mode_from_string(optarg); + if (arg_output < 0) + return log_error_errno(arg_output, "Unknown output format '%s'.", optarg); + + if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT)) + arg_quiet = true; + + if (OUTPUT_MODE_IS_JSON(arg_output)) + arg_json_format_flags = output_mode_to_json_format_flags(arg_output) | SD_JSON_FORMAT_COLOR_AUTO; + else + arg_json_format_flags = SD_JSON_FORMAT_OFF; + + break; + + case ARG_OUTPUT_FIELDS: { + _cleanup_strv_free_ char **v = NULL; + + v = strv_split(optarg, ","); + if (!v) + return log_oom(); + + r = set_put_strdupv(&arg_output_fields, v); if (r < 0) + return log_oom(); + + break; + } + + case 'n': + r = parse_lines(optarg ?: argv[optind], !optarg); + if (r < 0) + return r; + if (r > 0 && !optarg) + optind++; + + break; + + case 'r': + arg_reverse = true; + break; + + case ARG_SHOW_CURSOR: + arg_show_cursor = true; + break; + + case ARG_UTC: + arg_utc = true; + break; + + case 'x': + arg_catalog = true; + break; + + case 'W': + arg_no_hostname = true; + break; + + case 'l': + arg_full = true; + break; + + case ARG_NO_FULL: + arg_full = false; + break; + + case 'a': + arg_all = true; + break; + + case 'f': + arg_follow = true; + break; + + case ARG_NO_TAIL: + arg_no_tail = true; + break; + + case ARG_TRUNCATE_NEWLINE: + arg_truncate_newline = true; + break; + + case 'q': + arg_quiet = true; + break; + + case ARG_SYNCHRONIZE_ON_EXIT: + r = parse_boolean_argument("--synchronize-on-exit", optarg, &arg_synchronize_on_exit); + if (r < 0) + return r; + + break; + + case ARG_NO_PAGER: + arg_pager_flags |= PAGER_DISABLE; + break; + + case 'e': + arg_pager_flags |= PAGER_JUMP_TO_END; + break; + +#if HAVE_GCRYPT + case ARG_INTERVAL: + r = parse_sec(optarg, &arg_interval); + if (r < 0 || arg_interval <= 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse timestamp: %s", optarg); - arg_since_set = true; + "Failed to parse sealing key change interval: %s", optarg); break; - case 'U': - r = parse_timestamp(optarg, &arg_until); - if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse timestamp: %s", optarg); - arg_until_set = true; - break; - - case 't': - r = strv_extend(&arg_syslog_identifier, optarg); - if (r < 0) + case ARG_VERIFY_KEY: + erase_and_free(arg_verify_key); + arg_verify_key = strdup(optarg); + if (!arg_verify_key) return log_oom(); + + /* Use memset not explicit_bzero() or similar so this doesn't look confusing + * in ps or htop output. */ + memset(optarg, 'x', strlen(optarg)); + + arg_action = ACTION_VERIFY; + arg_merge = false; break; - case 'T': - r = strv_extend(&arg_exclude_identifier, optarg); - if (r < 0) - return log_oom(); + case ARG_FORCE: + arg_force = true; break; - case 'u': - r = strv_extend(&arg_system_units, optarg); - if (r < 0) - return log_oom(); + case ARG_SETUP_KEYS: + arg_action = ACTION_SETUP_KEYS; break; +#else + case ARG_INTERVAL: + case ARG_VERIFY_KEY: + case ARG_FORCE: + case ARG_SETUP_KEYS: + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Compiled without forward-secure sealing support."); +#endif - case ARG_USER_UNIT: - r = strv_extend(&arg_user_units, optarg); - if (r < 0) - return log_oom(); - break; + case 'h': + return help(); - case ARG_INVOCATION: - r = parse_id_descriptor(optarg, &arg_invocation_id, &arg_invocation_offset); - if (r < 0) - return log_error_errno(r, "Failed to parse invocation descriptor: %s", optarg); - arg_invocation = r; - break; + case ARG_VERSION: + return version(); - case 'I': - /* Equivalent to --invocation=0 */ - arg_invocation = true; - arg_invocation_id = SD_ID128_NULL; - arg_invocation_offset = 0; + case 'N': + arg_action = ACTION_LIST_FIELD_NAMES; break; case 'F': @@ -968,40 +957,52 @@ static int parse_argv(int argc, char *argv[]) { return r; break; - case 'N': - arg_action = ACTION_LIST_FIELD_NAMES; + case ARG_LIST_BOOTS: + arg_action = ACTION_LIST_BOOTS; break; - case 'W': - arg_no_hostname = true; + case ARG_LIST_INVOCATIONS: + arg_action = ACTION_LIST_INVOCATIONS; break; - case 'x': - arg_catalog = true; + case ARG_LIST_NAMESPACES: + arg_action = ACTION_LIST_NAMESPACES; break; - case ARG_LIST_CATALOG: - arg_action = ACTION_LIST_CATALOG; + case ARG_DISK_USAGE: + arg_action = ACTION_DISK_USAGE; break; - case ARG_DUMP_CATALOG: - arg_action = ACTION_DUMP_CATALOG; + case ARG_VACUUM_SIZE: + r = parse_size(optarg, 1024, &arg_vacuum_size); + if (r < 0) + return log_error_errno(r, "Failed to parse vacuum size: %s", optarg); + + arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; break; - case ARG_UPDATE_CATALOG: - arg_action = ACTION_UPDATE_CATALOG; + case ARG_VACUUM_FILES: + r = safe_atou64(optarg, &arg_vacuum_n_files); + if (r < 0) + return log_error_errno(r, "Failed to parse vacuum files: %s", optarg); + + arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; break; - case 'r': - arg_reverse = true; + case ARG_VACUUM_TIME: + r = parse_sec(optarg, &arg_vacuum_time); + if (r < 0) + return log_error_errno(r, "Failed to parse vacuum time: %s", optarg); + + arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; break; - case ARG_UTC: - arg_utc = true; + case ARG_VERIFY: + arg_action = ACTION_VERIFY; break; - case ARG_FLUSH: - arg_action = ACTION_FLUSH; + case ARG_SYNC: + arg_action = ACTION_SYNC; break; case ARG_SMART_RELINQUISH_VAR: { @@ -1033,33 +1034,32 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_RELINQUISH_VAR; break; + case ARG_FLUSH: + arg_action = ACTION_FLUSH; + break; + case ARG_ROTATE: arg_action = arg_action == ACTION_VACUUM ? ACTION_ROTATE_AND_VACUUM : ACTION_ROTATE; break; - case ARG_SYNC: - arg_action = ACTION_SYNC; + case ARG_HEADER: + arg_action = ACTION_PRINT_HEADER; break; - case ARG_OUTPUT_FIELDS: { - _cleanup_strv_free_ char **v = NULL; - - v = strv_split(optarg, ","); - if (!v) - return log_oom(); - - r = set_put_strdupv(&arg_output_fields, v); - if (r < 0) - return log_oom(); - + case ARG_LIST_CATALOG: + arg_action = ACTION_LIST_CATALOG; break; - } - case ARG_SYNCHRONIZE_ON_EXIT: - r = parse_boolean_argument("--synchronize-on-exit", optarg, &arg_synchronize_on_exit); - if (r < 0) - return r; + case ARG_DUMP_CATALOG: + arg_action = ACTION_DUMP_CATALOG; + break; + case ARG_UPDATE_CATALOG: + arg_action = ACTION_UPDATE_CATALOG; + break; + + case ARG_NEW_ID128: + arg_action = ACTION_NEW_ID128; break; case '?': From e7d07c20351cbce5ed179b0bf3ca29765d5d005d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 12 May 2026 13:58:47 +0200 Subject: [PATCH 2/6] shared/options: add OPTION_COMMON_{SYSTEM,USER} We have different help strings for --user/--system in different places, so this only covers a subset of --system/--user instances. But this particular help seems to be the most widely used. (In a few cases, the help string is fixed: it should be "system mode", not "per-system mode".) --- src/import/export.c | 4 ++-- src/import/import-fs.c | 4 ++-- src/import/import.c | 4 ++-- src/import/pull.c | 4 ++-- src/shared/options.h | 6 ++++++ src/storage/storage-fs.c | 4 ++-- src/storage/storagectl.c | 4 ++-- 7 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/import/export.c b/src/import/export.c index a77333643c6..8b64b9cad90 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -263,11 +263,11 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { return log_error_errno(arg_class, "Failed to parse --class= argument: %s", opts.arg); break; - OPTION_LONG("system", NULL, "Operate in per-system mode"): + OPTION_COMMON_SYSTEM: arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - OPTION_LONG("user", NULL, "Operate in per-user mode"): + OPTION_COMMON_USER: arg_runtime_scope = RUNTIME_SCOPE_USER; break; } diff --git a/src/import/import-fs.c b/src/import/import-fs.c index 513a2c62d39..cc6e14c995a 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -370,11 +370,11 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { return log_error_errno(arg_class, "Failed to parse --class= argument: %s", opts.arg); break; - OPTION_LONG("system", NULL, "Operate in per-system mode"): + OPTION_COMMON_SYSTEM: arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - OPTION_LONG("user", NULL, "Operate in per-user mode"): + OPTION_COMMON_USER: arg_runtime_scope = RUNTIME_SCOPE_USER; break; } diff --git a/src/import/import.c b/src/import/import.c index 798b6b743a2..9ddc4469c1f 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -410,11 +410,11 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { return log_error_errno(arg_class, "Failed to parse --class= argument: %s", opts.arg); break; - OPTION_LONG("system", NULL, "Operate in per-system mode"): + OPTION_COMMON_SYSTEM: arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - OPTION_LONG("user", NULL, "Operate in per-user mode"): + OPTION_COMMON_USER: arg_runtime_scope = RUNTIME_SCOPE_USER; break; } diff --git a/src/import/pull.c b/src/import/pull.c index 6a1f913ff8a..ac9492f1775 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -537,11 +537,11 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { auto_keep_download = false; break; - OPTION_LONG("system", NULL, "Operate in per-system mode"): + OPTION_COMMON_SYSTEM: arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - OPTION_LONG("user", NULL, "Operate in per-user mode"): + OPTION_COMMON_USER: arg_runtime_scope = RUNTIME_SCOPE_USER; break; } diff --git a/src/shared/options.h b/src/shared/options.h index 1f28dab8ad5..f88275821a6 100644 --- a/src/shared/options.h +++ b/src/shared/options.h @@ -124,6 +124,12 @@ typedef struct Option { #define OPTION_COMMON_MACHINE \ OPTION('M', "machine", "CONTAINER", "Operate on local container") +#define OPTION_COMMON_SYSTEM \ + OPTION_LONG("system", NULL, "Operate in system mode") + +#define OPTION_COMMON_USER \ + OPTION_LONG("user", NULL, "Operate in per-user mode") + #define OPTION_COMMON_JSON \ OPTION_LONG("json", "FORMAT", "Generate JSON output (pretty, short, or off)") diff --git a/src/storage/storage-fs.c b/src/storage/storage-fs.c index 167b10dd835..5b2bc415fb6 100644 --- a/src/storage/storage-fs.c +++ b/src/storage/storage-fs.c @@ -777,11 +777,11 @@ static int parse_argv(int argc, char *argv[]) { OPTION_COMMON_VERSION: return version(); - OPTION_LONG("system", NULL, "Operate in system mode"): + OPTION_COMMON_SYSTEM: arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - OPTION_LONG("user", NULL, "Operate in user mode"): + OPTION_COMMON_USER: arg_runtime_scope = RUNTIME_SCOPE_USER; break; } diff --git a/src/storage/storagectl.c b/src/storage/storagectl.c index bbe09e01b1d..d3ae3f91453 100644 --- a/src/storage/storagectl.c +++ b/src/storage/storagectl.c @@ -433,11 +433,11 @@ static int parse_argv(int argc, char *argv[], char ***args) { arg_ask_password = false; break; - OPTION_LONG("system", NULL, "Operate in system mode"): + OPTION_COMMON_SYSTEM: arg_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - OPTION_LONG("user", NULL, "Operate in user mode"): + OPTION_COMMON_USER: arg_runtime_scope = RUNTIME_SCOPE_USER; break; } From c3f4c1b8d6b9bad0d88255ce40956a8f513c098a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 12 May 2026 13:28:35 +0200 Subject: [PATCH 3/6] journalctl: convert to OPTION macros Two namespaces are used: "journalctl" and "journalctl-varlink". Help for --user/--system in the latter is added, even though it is not used yet. I think it'll be good to have this for introspection. The four FSS-related options (--interval, --verify-key, --force, --setup-keys) unfortunately each gain an inline #if HAVE_GCRYPT / #else; the EOPNOTSUPP fallback is duplicated four times. The metavar for --identifier/--exclude-identifier is changed to "ID" to make the layout nicer. (And because that seems to make more sense.) Co-developed-by: Claude Opus 4.7 --- src/journal/journalctl.c | 668 +++++++++++++++------------------------ 1 file changed, 259 insertions(+), 409 deletions(-) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 2aeeeb55314..2b4995714f5 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include #include #include "sd-journal.h" @@ -9,7 +8,9 @@ #include "build.h" #include "dissect-image.h" #include "extract-word.h" +#include "format-table.h" #include "glob-util.h" +#include "help-util.h" #include "id128-print.h" #include "image-policy.h" #include "journalctl.h" @@ -24,12 +25,12 @@ #include "main-func.h" #include "mount-util.h" #include "mountpoint-util.h" +#include "options.h" #include "output-mode.h" #include "pager.h" #include "parse-argument.h" #include "parse-util.h" #include "pcre2-util.h" -#include "pretty-print.h" #include "runtime-scope.h" #include "set.h" #include "static-destruct.h" @@ -229,106 +230,42 @@ static int help_facilities(void) { } static int help(void) { - _cleanup_free_ char *link = NULL; + static const char *const groups[] = { + "Source Options", + "Filtering Options", + "Output Control Options", + "Pager Control Options", + "Forward Secure Sealing (FSS) Options", + "Commands", + }; + + Table *tables[ELEMENTSOF(groups)] = {}; + CLEANUP_ELEMENTS(tables, table_unref_array_clear); int r; pager_open(arg_pager_flags); - r = terminal_urlify_man("journalctl", "1", &link); - if (r < 0) - return log_oom(); + for (size_t i = 0; i < ELEMENTSOF(groups); i++) { + r = option_parser_get_help_table_full("journalctl", groups[i], &tables[i]); + if (r < 0) + return r; + } - printf("%1$s [OPTIONS...] [MATCHES...]\n\n" - "%5$sQuery the journal.%6$s\n\n" - "%3$sSource Options:%4$s\n" - " --system Show the system journal\n" - " --user Show the user journal for the current user\n" - " -M --machine=CONTAINER Operate on local container\n" - " -m --merge Show entries from all available journals\n" - " -D --directory=PATH Show journal files from directory\n" - " -i --file=PATH Show journal file\n" - " --root=PATH Operate on an alternate filesystem root\n" - " --image=PATH Operate on disk image as filesystem root\n" - " --image-policy=POLICY Specify disk image dissection policy\n" - " --namespace=NAMESPACE Show journal data from specified journal namespace\n" - "\n%3$sFiltering Options:%4$s\n" - " -S --since=DATE Show entries not older than the specified date\n" - " -U --until=DATE Show entries not newer than the specified date\n" - " -c --cursor=CURSOR Show entries starting at the specified cursor\n" - " --after-cursor=CURSOR Show entries after the specified cursor\n" - " --cursor-file=FILE Show entries after cursor in FILE and update FILE\n" - " -b --boot[=ID] Show current boot or the specified boot\n" - " -u --unit=UNIT Show logs from the specified unit\n" - " --user-unit=UNIT Show logs from the specified user unit\n" - " --invocation=ID Show logs from the matching invocation ID\n" - " -I Show logs from the latest invocation of unit\n" - " -t --identifier=STRING Show entries with the specified syslog identifier\n" - " -T --exclude-identifier=STRING\n" - " Hide entries with the specified syslog identifier\n" - " -p --priority=RANGE Show entries within the specified priority range\n" - " --facility=FACILITY... Show entries with the specified facilities\n" - " -g --grep=PATTERN Show entries with MESSAGE matching PATTERN\n" - " --case-sensitive[=BOOL] Force case sensitive or insensitive matching\n" - " -k --dmesg Show kernel message log from the current boot\n" - "\n%3$sOutput Control Options:%4$s\n" - " -o --output=STRING Change journal output mode (short, short-precise,\n" - " short-iso, short-iso-precise, short-full,\n" - " short-monotonic, short-unix, verbose, export,\n" - " json, json-pretty, json-sse, json-seq, cat,\n" - " with-unit)\n" - " --output-fields=LIST Select fields to print in verbose/export/json modes\n" - " -n --lines[=[+]INTEGER] Number of journal entries to show\n" - " -r --reverse Show the newest entries first\n" - " --show-cursor Print the cursor after all the entries\n" - " --utc Express time in Coordinated Universal Time (UTC)\n" - " -x --catalog Add message explanations where available\n" - " -W --no-hostname Suppress output of hostname field\n" - " --no-full Ellipsize fields\n" - " -a --all Show all fields, including long and unprintable\n" - " -f --follow Follow the journal\n" - " --no-tail Show all lines, even in follow mode\n" - " --truncate-newline Truncate entries by first newline character\n" - " -q --quiet Do not show info messages and privilege warning\n" - " --synchronize-on-exit=BOOL\n" - " Wait for Journal synchronization before exiting\n" - "\n%3$sPager Control Options:%4$s\n" - " --no-pager Do not pipe output into a pager\n" - " -e --pager-end Immediately jump to the end in the pager\n" - "\n%3$sForward Secure Sealing (FSS) Options:%4$s\n" - " --interval=TIME Time interval for changing the FSS sealing key\n" - " --verify-key=KEY Specify FSS verification key\n" - " --force Override of the FSS key pair with --setup-keys\n" - "\n%3$sCommands:%4$s\n" - " -h --help Show this help text\n" - " --version Show package version\n" - " -N --fields List all field names currently used\n" - " -F --field=FIELD List all values that a specified field takes\n" - " --list-boots Show terse information about recorded boots\n" - " --list-invocations Show invocation IDs of specified unit\n" - " --list-namespaces Show list of journal namespaces\n" - " --disk-usage Show total disk usage of all journal files\n" - " --vacuum-size=BYTES Reduce disk usage below specified size\n" - " --vacuum-files=INT Leave only the specified number of journal files\n" - " --vacuum-time=TIME Remove journal files older than specified time\n" - " --verify Verify journal file consistency\n" - " --sync Synchronize unwritten journal messages to disk\n" - " --relinquish-var Stop logging to disk, log to temporary file system\n" - " --smart-relinquish-var Similar, but NOP if log directory is on root mount\n" - " --flush Flush all journal data from /run into /var\n" - " --rotate Request immediate rotation of the journal files\n" - " --header Show journal header information\n" - " --list-catalog Show all message IDs in the catalog\n" - " --dump-catalog Show entries in the message catalog\n" - " --update-catalog Update the message catalog database\n" - " --setup-keys Generate a new FSS key pair\n" - "\nSee the %2$s for details.\n", - program_invocation_short_name, - link, - ansi_underline(), - ansi_normal(), - ansi_highlight(), - ansi_normal()); + assert_se(ELEMENTSOF(tables) == 6); + (void) table_sync_column_widths(0, tables[0], tables[1], tables[2], + tables[3], tables[4], tables[5]); + help_cmdline("[OPTIONS…] [MATCHES…]"); + help_abstract("Query the journal."); + + for (size_t i = 0; i < ELEMENTSOF(groups); i++) { + help_section(groups[i]); + r = table_print_or_warn(tables[i]); + if (r < 0) + return r; + } + + help_man_page_reference("journalctl", "1"); return 0; } @@ -355,134 +292,12 @@ static int vl_server(void) { return 0; } -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_NO_PAGER, - ARG_NO_FULL, - ARG_NO_TAIL, - ARG_NEW_ID128, - ARG_THIS_BOOT, - ARG_LIST_BOOTS, - ARG_LIST_INVOCATIONS, - ARG_USER, - ARG_SYSTEM, - ARG_ROOT, - ARG_IMAGE, - ARG_IMAGE_POLICY, - ARG_HEADER, - ARG_FACILITY, - ARG_SETUP_KEYS, - ARG_INTERVAL, - ARG_VERIFY, - ARG_VERIFY_KEY, - ARG_DISK_USAGE, - ARG_AFTER_CURSOR, - ARG_CURSOR_FILE, - ARG_SHOW_CURSOR, - ARG_USER_UNIT, - ARG_INVOCATION, - ARG_LIST_CATALOG, - ARG_DUMP_CATALOG, - ARG_UPDATE_CATALOG, - ARG_FORCE, - ARG_CASE_SENSITIVE, - ARG_UTC, - ARG_SYNC, - ARG_FLUSH, - ARG_RELINQUISH_VAR, - ARG_SMART_RELINQUISH_VAR, - ARG_ROTATE, - ARG_TRUNCATE_NEWLINE, - ARG_VACUUM_SIZE, - ARG_VACUUM_FILES, - ARG_VACUUM_TIME, - ARG_OUTPUT_FIELDS, - ARG_NAMESPACE, - ARG_LIST_NAMESPACES, - ARG_SYNCHRONIZE_ON_EXIT, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version" , no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "pager-end", no_argument, NULL, 'e' }, - { "follow", no_argument, NULL, 'f' }, - { "force", no_argument, NULL, ARG_FORCE }, - { "output", required_argument, NULL, 'o' }, - { "all", no_argument, NULL, 'a' }, - { "full", no_argument, NULL, 'l' }, - { "no-full", no_argument, NULL, ARG_NO_FULL }, - { "lines", optional_argument, NULL, 'n' }, - { "truncate-newline", no_argument, NULL, ARG_TRUNCATE_NEWLINE }, - { "no-tail", no_argument, NULL, ARG_NO_TAIL }, - { "new-id128", no_argument, NULL, ARG_NEW_ID128 }, /* deprecated */ - { "quiet", no_argument, NULL, 'q' }, - { "merge", no_argument, NULL, 'm' }, - { "this-boot", no_argument, NULL, ARG_THIS_BOOT }, /* deprecated */ - { "boot", optional_argument, NULL, 'b' }, - { "list-boots", no_argument, NULL, ARG_LIST_BOOTS }, - { "list-invocations", no_argument, NULL, ARG_LIST_INVOCATIONS }, - { "dmesg", no_argument, NULL, 'k' }, - { "system", no_argument, NULL, ARG_SYSTEM }, - { "user", no_argument, NULL, ARG_USER }, - { "directory", required_argument, NULL, 'D' }, - { "file", required_argument, NULL, 'i' }, - { "root", required_argument, NULL, ARG_ROOT }, - { "image", required_argument, NULL, ARG_IMAGE }, - { "image-policy", required_argument, NULL, ARG_IMAGE_POLICY }, - { "header", no_argument, NULL, ARG_HEADER }, - { "identifier", required_argument, NULL, 't' }, - { "exclude-identifier", required_argument, NULL, 'T' }, - { "priority", required_argument, NULL, 'p' }, - { "facility", required_argument, NULL, ARG_FACILITY }, - { "grep", required_argument, NULL, 'g' }, - { "case-sensitive", optional_argument, NULL, ARG_CASE_SENSITIVE }, - { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS }, - { "interval", required_argument, NULL, ARG_INTERVAL }, - { "verify", no_argument, NULL, ARG_VERIFY }, - { "verify-key", required_argument, NULL, ARG_VERIFY_KEY }, - { "disk-usage", no_argument, NULL, ARG_DISK_USAGE }, - { "cursor", required_argument, NULL, 'c' }, - { "cursor-file", required_argument, NULL, ARG_CURSOR_FILE }, - { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, - { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, - { "since", required_argument, NULL, 'S' }, - { "until", required_argument, NULL, 'U' }, - { "unit", required_argument, NULL, 'u' }, - { "user-unit", required_argument, NULL, ARG_USER_UNIT }, - { "invocation", required_argument, NULL, ARG_INVOCATION }, - { "field", required_argument, NULL, 'F' }, - { "fields", no_argument, NULL, 'N' }, - { "catalog", no_argument, NULL, 'x' }, - { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG }, - { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG }, - { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG }, - { "reverse", no_argument, NULL, 'r' }, - { "machine", required_argument, NULL, 'M' }, - { "utc", no_argument, NULL, ARG_UTC }, - { "flush", no_argument, NULL, ARG_FLUSH }, - { "relinquish-var", no_argument, NULL, ARG_RELINQUISH_VAR }, - { "smart-relinquish-var", no_argument, NULL, ARG_SMART_RELINQUISH_VAR }, - { "sync", no_argument, NULL, ARG_SYNC }, - { "rotate", no_argument, NULL, ARG_ROTATE }, - { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, - { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, - { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME }, - { "no-hostname", no_argument, NULL, 'W' }, - { "output-fields", required_argument, NULL, ARG_OUTPUT_FIELDS }, - { "namespace", required_argument, NULL, ARG_NAMESPACE }, - { "list-namespaces", no_argument, NULL, ARG_LIST_NAMESPACES }, - { "synchronize-on-exit", required_argument, NULL, ARG_SYNCHRONIZE_ON_EXIT }, - {} - }; - - int c, r; +static int parse_argv(int argc, char *argv[], char ***remaining_args) { + int r; assert(argc >= 0); assert(argv); + assert(remaining_args); r = sd_varlink_invocation(SD_VARLINK_ALLOW_ACCEPT); if (r < 0) @@ -490,228 +305,237 @@ static int parse_argv(int argc, char *argv[]) { if (r > 0) { arg_varlink = true; - static const struct option varlink_options[] = { - { "system", no_argument, NULL, ARG_SYSTEM }, - { "user", no_argument, NULL, ARG_USER }, - {} - }; - - while ((c = getopt_long(argc, argv, "", varlink_options, NULL)) >= 0) + OptionParser opts = { argc, argv, .namespace = "journalctl-varlink" }; + FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { - case ARG_SYSTEM: + OPTION_NAMESPACE("journalctl-varlink"): {} + + OPTION_COMMON_SYSTEM: arg_varlink_runtime_scope = RUNTIME_SCOPE_SYSTEM; break; - case ARG_USER: + OPTION_COMMON_USER: arg_varlink_runtime_scope = RUNTIME_SCOPE_USER; break; - - case '?': - return -EINVAL; - - default: - assert_not_reached(); } if (arg_varlink_runtime_scope < 0) return log_error_errno(arg_varlink_runtime_scope, "Cannot run in Varlink mode with no runtime scope specified."); + if (option_parser_get_n_args(&opts) > 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No arguments expected in Varlink mode."); + + *remaining_args = NULL; return 1; } - while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:g:c:S:U:t:T:u:INF:xrM:i:W", options, NULL)) >= 0) + OptionParser opts = { argc, argv, .namespace = "journalctl" }; + FOREACH_OPTION_OR_RETURN(c, &opts) switch (c) { - case ARG_SYSTEM: + OPTION_NAMESPACE("journalctl"): {} + + OPTION_GROUP("Source Options"): {} + + OPTION_LONG("system", NULL, "Show the system journal"): arg_journal_type |= SD_JOURNAL_SYSTEM; break; - case ARG_USER: + OPTION_LONG("user", NULL, "Show the user journal for the current user"): arg_journal_type |= SD_JOURNAL_CURRENT_USER; break; - case 'M': - r = free_and_strdup_warn(&arg_machine, optarg); + OPTION_COMMON_MACHINE: + r = free_and_strdup_warn(&arg_machine, opts.arg); if (r < 0) return r; break; - case 'm': + OPTION('m', "merge", NULL, "Show entries from all available journals"): arg_merge = true; break; - case 'D': - r = free_and_strdup_warn(&arg_directory, optarg); + OPTION('D', "directory", "PATH", "Show journal files from directory"): + r = free_and_strdup_warn(&arg_directory, opts.arg); if (r < 0) return r; break; - case 'i': - if (streq(optarg, "-")) + OPTION('i', "file", "PATH", "Show journal file"): + if (streq(opts.arg, "-")) /* An undocumented feature: we can read journal files from STDIN. We don't document * this though, since after all we only support this for mmap-able, seekable files, and * not for example pipes which are probably the primary use case for reading things from * STDIN. To avoid confusion we hence don't document this feature. */ arg_file_stdin = true; else { - r = glob_extend(&arg_file, optarg, GLOB_NOCHECK); + r = glob_extend(&arg_file, opts.arg, GLOB_NOCHECK); if (r < 0) return log_error_errno(r, "Failed to add paths: %m"); } break; - case ARG_ROOT: - r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root); + OPTION_LONG("root", "PATH", "Operate on an alternate filesystem root"): + r = parse_path_argument(opts.arg, /* suppress_root= */ true, &arg_root); if (r < 0) return r; break; - case ARG_IMAGE: - r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image); + OPTION_LONG("image", "PATH", "Operate on disk image as filesystem root"): + r = parse_path_argument(opts.arg, /* suppress_root= */ false, &arg_image); if (r < 0) return r; break; - case ARG_IMAGE_POLICY: - r = parse_image_policy_argument(optarg, &arg_image_policy); + OPTION_LONG("image-policy", "POLICY", "Specify disk image dissection policy"): + r = parse_image_policy_argument(opts.arg, &arg_image_policy); if (r < 0) return r; break; - case ARG_NAMESPACE: - if (streq(optarg, "*")) { + OPTION_LONG("namespace", "NAMESPACE", + "Show journal data from specified journal namespace"): + if (streq(opts.arg, "*")) { arg_namespace_flags = SD_JOURNAL_ALL_NAMESPACES; arg_namespace = mfree(arg_namespace); - } else if (startswith(optarg, "+")) { + } else if (startswith(opts.arg, "+")) { arg_namespace_flags = SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE; - r = free_and_strdup_warn(&arg_namespace, optarg + 1); + r = free_and_strdup_warn(&arg_namespace, opts.arg + 1); if (r < 0) return r; - } else if (isempty(optarg)) { + } else if (isempty(opts.arg)) { arg_namespace_flags = 0; arg_namespace = mfree(arg_namespace); } else { arg_namespace_flags = 0; - r = free_and_strdup_warn(&arg_namespace, optarg); + r = free_and_strdup_warn(&arg_namespace, opts.arg); if (r < 0) return r; } break; - case 'S': - r = parse_timestamp(optarg, &arg_since); + OPTION_GROUP("Filtering Options"): {} + + OPTION('S', "since", "DATE", "Show entries not older than the specified date"): + r = parse_timestamp(opts.arg, &arg_since); if (r < 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse timestamp: %s", optarg); + "Failed to parse timestamp: %s", opts.arg); arg_since_set = true; break; - case 'U': - r = parse_timestamp(optarg, &arg_until); + OPTION('U', "until", "DATE", "Show entries not newer than the specified date"): + r = parse_timestamp(opts.arg, &arg_until); if (r < 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse timestamp: %s", optarg); + "Failed to parse timestamp: %s", opts.arg); arg_until_set = true; break; - case 'c': - r = free_and_strdup_warn(&arg_cursor, optarg); + OPTION('c', "cursor", "CURSOR", "Show entries starting at the specified cursor"): + r = free_and_strdup_warn(&arg_cursor, opts.arg); if (r < 0) return r; break; - case ARG_AFTER_CURSOR: - r = free_and_strdup_warn(&arg_after_cursor, optarg); + OPTION_LONG("after-cursor", "CURSOR", "Show entries after the specified cursor"): + r = free_and_strdup_warn(&arg_after_cursor, opts.arg); if (r < 0) return r; break; - case ARG_CURSOR_FILE: - r = free_and_strdup_warn(&arg_cursor_file, optarg); + OPTION_LONG("cursor-file", "FILE", "Show entries after cursor in FILE and update FILE"): + r = free_and_strdup_warn(&arg_cursor_file, opts.arg); if (r < 0) return r; break; - case ARG_THIS_BOOT: + OPTION_LONG("this-boot", NULL, /* help= */ NULL): arg_boot = true; arg_boot_id = SD_ID128_NULL; arg_boot_offset = 0; break; - case 'b': + OPTION_FULL(OPTION_OPTIONAL_ARG, 'b', "boot", "ID", + "Show current boot or the specified boot"): arg_boot = true; arg_boot_id = SD_ID128_NULL; arg_boot_offset = 0; - if (optarg) { - r = parse_id_descriptor(optarg, &arg_boot_id, &arg_boot_offset); + if (opts.arg) { + r = parse_id_descriptor(opts.arg, &arg_boot_id, &arg_boot_offset); if (r < 0) - return log_error_errno(r, "Failed to parse boot descriptor '%s'", optarg); + return log_error_errno(r, "Failed to parse boot descriptor '%s'", opts.arg); arg_boot = r; - } else if (optind < argc) { - /* Hmm, no argument? Maybe the next word on the command line is supposed to be the - * argument? Let's see if there is one and is parsable as a boot descriptor... */ - r = parse_id_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset); - if (r >= 0) { - arg_boot = r; - optind++; + } else { + /* Hmm, no argument? Maybe the next word on the command line is supposed to + * be the argument? Let's see if there is one and is parsable as a boot + * descriptor… */ + char *peek = option_parser_peek_next_arg(&opts); + if (peek) { + r = parse_id_descriptor(peek, &arg_boot_id, &arg_boot_offset); + if (r >= 0) { + arg_boot = r; + (void) option_parser_consume_next_arg(&opts); + } } } break; - case 'u': - r = strv_extend(&arg_system_units, optarg); + OPTION('u', "unit", "UNIT", "Show logs from the specified unit"): + r = strv_extend(&arg_system_units, opts.arg); if (r < 0) return log_oom(); break; - case ARG_USER_UNIT: - r = strv_extend(&arg_user_units, optarg); + OPTION_LONG("user-unit", "UNIT", "Show logs from the specified user unit"): + r = strv_extend(&arg_user_units, opts.arg); if (r < 0) return log_oom(); break; - case ARG_INVOCATION: - r = parse_id_descriptor(optarg, &arg_invocation_id, &arg_invocation_offset); + OPTION_LONG("invocation", "ID", "Show logs from the matching invocation ID"): + r = parse_id_descriptor(opts.arg, &arg_invocation_id, &arg_invocation_offset); if (r < 0) - return log_error_errno(r, "Failed to parse invocation descriptor: %s", optarg); + return log_error_errno(r, "Failed to parse invocation descriptor: %s", opts.arg); arg_invocation = r; break; - case 'I': + OPTION_SHORT('I', NULL, "Show logs from the latest invocation of unit"): /* Equivalent to --invocation=0 */ arg_invocation = true; arg_invocation_id = SD_ID128_NULL; arg_invocation_offset = 0; break; - case 't': - r = strv_extend(&arg_syslog_identifier, optarg); + OPTION('t', "identifier", "ID", "Show entries with the specified syslog identifier"): + r = strv_extend(&arg_syslog_identifier, opts.arg); if (r < 0) return log_oom(); break; - case 'T': - r = strv_extend(&arg_exclude_identifier, optarg); + OPTION('T', "exclude-identifier", "ID", + "Hide entries with the specified syslog identifier"): + r = strv_extend(&arg_exclude_identifier, opts.arg); if (r < 0) return log_oom(); break; - case 'p': { + OPTION('p', "priority", "RANGE", "Show entries within the specified priority range"): { const char *dots; - dots = strstr(optarg, ".."); + dots = strstr(opts.arg, ".."); if (dots) { _cleanup_free_ char *a = NULL; int from, to, i; /* a range */ - a = strndup(optarg, dots - optarg); + a = strndup(opts.arg, dots - opts.arg); if (!a) return log_oom(); @@ -720,7 +544,7 @@ static int parse_argv(int argc, char *argv[]) { if (from < 0 || to < 0) return log_error_errno(from < 0 ? from : to, - "Failed to parse log level range %s", optarg); + "Failed to parse log level range %s", opts.arg); arg_priorities = 0; @@ -735,9 +559,9 @@ static int parse_argv(int argc, char *argv[]) { } else { int p, i; - p = log_level_from_string(optarg); + p = log_level_from_string(opts.arg); if (p < 0) - return log_error_errno(p, "Unknown log level %s", optarg); + return log_error_errno(p, "Unknown log level %s", opts.arg); arg_priorities = 0; @@ -748,16 +572,16 @@ static int parse_argv(int argc, char *argv[]) { break; } - case ARG_FACILITY: { + OPTION_LONG("facility", "FACILITY…", "Show entries with the specified facilities"): { const char *p; - for (p = optarg;;) { + for (p = opts.arg;;) { _cleanup_free_ char *fac = NULL; int num; r = extract_first_word(&p, &fac, ",", 0); if (r < 0) - return log_error_errno(r, "Failed to parse facilities: %s", optarg); + return log_error_errno(r, "Failed to parse facilities: %s", opts.arg); if (r == 0) break; @@ -777,34 +601,40 @@ static int parse_argv(int argc, char *argv[]) { break; } - case 'g': - r = free_and_strdup_warn(&arg_pattern, optarg); + OPTION('g', "grep", "PATTERN", "Show entries with MESSAGE matching PATTERN"): + r = free_and_strdup_warn(&arg_pattern, opts.arg); if (r < 0) return r; break; - case ARG_CASE_SENSITIVE: - if (optarg) { - r = parse_boolean(optarg); + OPTION_LONG_FLAGS(OPTION_OPTIONAL_ARG, "case-sensitive", "BOOL", + "Force case sensitive or insensitive matching"): + if (opts.arg) { + r = parse_boolean(opts.arg); if (r < 0) - return log_error_errno(r, "Bad --case-sensitive= argument \"%s\": %m", optarg); + return log_error_errno(r, "Bad --case-sensitive= argument \"%s\": %m", opts.arg); arg_case = r ? PATTERN_COMPILE_CASE_SENSITIVE : PATTERN_COMPILE_CASE_INSENSITIVE; } else arg_case = PATTERN_COMPILE_CASE_SENSITIVE; break; - case 'k': + OPTION('k', "dmesg", NULL, "Show kernel message log from the current boot"): arg_dmesg = true; break; - case 'o': - if (streq(optarg, "help")) + OPTION_GROUP("Output Control Options"): {} + + OPTION('o', "output", "STRING", + "Change journal output mode (short, short-precise, short-iso, short-iso-precise, " + "short-full, short-monotonic, short-unix, verbose, export, json, json-pretty, " + "json-sse, json-seq, cat, with-unit)"): + if (streq(opts.arg, "help")) return DUMP_STRING_TABLE(output_mode, OutputMode, _OUTPUT_MODE_MAX); - arg_output = output_mode_from_string(optarg); + arg_output = output_mode_from_string(opts.arg); if (arg_output < 0) - return log_error_errno(arg_output, "Unknown output format '%s'.", optarg); + return log_error_errno(arg_output, "Unknown output format '%s'.", opts.arg); if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT)) arg_quiet = true; @@ -816,10 +646,10 @@ static int parse_argv(int argc, char *argv[]) { break; - case ARG_OUTPUT_FIELDS: { + OPTION_LONG("output-fields", "LIST", "Select fields to print in verbose/export/json modes"): { _cleanup_strv_free_ char **v = NULL; - v = strv_split(optarg, ","); + v = strv_split(opts.arg, ","); if (!v) return log_oom(); @@ -830,182 +660,195 @@ static int parse_argv(int argc, char *argv[]) { break; } - case 'n': - r = parse_lines(optarg ?: argv[optind], !optarg); + OPTION_FULL(OPTION_OPTIONAL_ARG, 'n', "lines", "[+]INTEGER", + "Number of journal entries to show"): { + const char *p = opts.arg ?: option_parser_peek_next_arg(&opts); + + r = parse_lines(p, /* graceful= */ !opts.arg); if (r < 0) return r; - if (r > 0 && !optarg) - optind++; + if (r > 0 && !opts.arg) + (void) option_parser_consume_next_arg(&opts); break; + } - case 'r': + OPTION('r', "reverse", NULL, "Show the newest entries first"): arg_reverse = true; break; - case ARG_SHOW_CURSOR: + OPTION_LONG("show-cursor", NULL, "Print the cursor after all the entries"): arg_show_cursor = true; break; - case ARG_UTC: + OPTION_LONG("utc", NULL, "Express time in Coordinated Universal Time (UTC)"): arg_utc = true; break; - case 'x': + OPTION('x', "catalog", NULL, "Add message explanations where available"): arg_catalog = true; break; - case 'W': + OPTION('W', "no-hostname", NULL, "Suppress output of hostname field"): arg_no_hostname = true; break; - case 'l': + OPTION('l', "full", NULL, /* help= */ NULL): arg_full = true; break; - case ARG_NO_FULL: + OPTION_LONG("no-full", NULL, "Ellipsize fields"): arg_full = false; break; - case 'a': + OPTION('a', "all", NULL, "Show all fields, including long and unprintable"): arg_all = true; break; - case 'f': + OPTION('f', "follow", NULL, "Follow the journal"): arg_follow = true; break; - case ARG_NO_TAIL: + OPTION_LONG("no-tail", NULL, "Show all lines, even in follow mode"): arg_no_tail = true; break; - case ARG_TRUNCATE_NEWLINE: + OPTION_LONG("truncate-newline", NULL, "Truncate entries by first newline character"): arg_truncate_newline = true; break; - case 'q': + OPTION('q', "quiet", NULL, "Do not show info messages and privilege warning"): arg_quiet = true; break; - case ARG_SYNCHRONIZE_ON_EXIT: - r = parse_boolean_argument("--synchronize-on-exit", optarg, &arg_synchronize_on_exit); + OPTION_LONG("synchronize-on-exit", "BOOL", + "Wait for Journal synchronization before exiting"): + r = parse_boolean_argument("--synchronize-on-exit", opts.arg, &arg_synchronize_on_exit); if (r < 0) return r; - break; - case ARG_NO_PAGER: + OPTION_GROUP("Pager Control Options"): {} + + OPTION_COMMON_NO_PAGER: arg_pager_flags |= PAGER_DISABLE; break; - case 'e': + OPTION('e', "pager-end", NULL, "Immediately jump to the end in the pager"): arg_pager_flags |= PAGER_JUMP_TO_END; break; + OPTION_GROUP("Forward Secure Sealing (FSS) Options"): {} + + OPTION_LONG("interval", "TIME", "Time interval for changing the FSS sealing key"): #if HAVE_GCRYPT - case ARG_INTERVAL: - r = parse_sec(optarg, &arg_interval); + r = parse_sec(opts.arg, &arg_interval); if (r < 0 || arg_interval <= 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse sealing key change interval: %s", optarg); - break; - - case ARG_VERIFY_KEY: - erase_and_free(arg_verify_key); - arg_verify_key = strdup(optarg); - if (!arg_verify_key) - return log_oom(); - - /* Use memset not explicit_bzero() or similar so this doesn't look confusing - * in ps or htop output. */ - memset(optarg, 'x', strlen(optarg)); - - arg_action = ACTION_VERIFY; - arg_merge = false; - break; - - case ARG_FORCE: - arg_force = true; - break; - - case ARG_SETUP_KEYS: - arg_action = ACTION_SETUP_KEYS; + "Failed to parse sealing key change interval: %s", opts.arg); break; #else - case ARG_INTERVAL: - case ARG_VERIFY_KEY: - case ARG_FORCE: - case ARG_SETUP_KEYS: return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Compiled without forward-secure sealing support."); #endif - case 'h': + OPTION_LONG("verify-key", "KEY", "Specify FSS verification key"): +#if HAVE_GCRYPT + erase_and_free(arg_verify_key); + arg_verify_key = strdup(opts.arg); + if (!arg_verify_key) + return log_oom(); + + /* Use memset not explicit_bzero() or similar so this doesn't look confusing + * in ps or htop output. We need to cast away the const to do this. */ + memset((char*) opts.arg, 'x', strlen(opts.arg)); + + arg_action = ACTION_VERIFY; + arg_merge = false; + break; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Compiled without forward-secure sealing support."); +#endif + + OPTION_LONG("force", NULL, "Override of the FSS key pair with --setup-keys"): +#if HAVE_GCRYPT + arg_force = true; + break; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Compiled without forward-secure sealing support."); +#endif + + OPTION_GROUP("Commands"): {} + + OPTION_COMMON_HELP: return help(); - case ARG_VERSION: + OPTION_COMMON_VERSION: return version(); - case 'N': + OPTION('N', "fields", NULL, "List all field names currently used"): arg_action = ACTION_LIST_FIELD_NAMES; break; - case 'F': + OPTION('F', "field", "FIELD", "List all values that a specified field takes"): arg_action = ACTION_LIST_FIELDS; - r = free_and_strdup_warn(&arg_field, optarg); + r = free_and_strdup_warn(&arg_field, opts.arg); if (r < 0) return r; break; - case ARG_LIST_BOOTS: + OPTION_LONG("list-boots", NULL, "Show terse information about recorded boots"): arg_action = ACTION_LIST_BOOTS; break; - case ARG_LIST_INVOCATIONS: + OPTION_LONG("list-invocations", NULL, "Show invocation IDs of specified unit"): arg_action = ACTION_LIST_INVOCATIONS; break; - case ARG_LIST_NAMESPACES: + OPTION_LONG("list-namespaces", NULL, "Show list of journal namespaces"): arg_action = ACTION_LIST_NAMESPACES; break; - case ARG_DISK_USAGE: + OPTION_LONG("disk-usage", NULL, "Show total disk usage of all journal files"): arg_action = ACTION_DISK_USAGE; break; - case ARG_VACUUM_SIZE: - r = parse_size(optarg, 1024, &arg_vacuum_size); + OPTION_LONG("vacuum-size", "BYTES", "Reduce disk usage below specified size"): + r = parse_size(opts.arg, 1024, &arg_vacuum_size); if (r < 0) - return log_error_errno(r, "Failed to parse vacuum size: %s", optarg); + return log_error_errno(r, "Failed to parse vacuum size: %s", opts.arg); arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; break; - case ARG_VACUUM_FILES: - r = safe_atou64(optarg, &arg_vacuum_n_files); + OPTION_LONG("vacuum-files", "INT", "Leave only the specified number of journal files"): + r = safe_atou64(opts.arg, &arg_vacuum_n_files); if (r < 0) - return log_error_errno(r, "Failed to parse vacuum files: %s", optarg); + return log_error_errno(r, "Failed to parse vacuum files: %s", opts.arg); arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; break; - case ARG_VACUUM_TIME: - r = parse_sec(optarg, &arg_vacuum_time); + OPTION_LONG("vacuum-time", "TIME", "Remove journal files older than specified time"): + r = parse_sec(opts.arg, &arg_vacuum_time); if (r < 0) - return log_error_errno(r, "Failed to parse vacuum time: %s", optarg); + return log_error_errno(r, "Failed to parse vacuum time: %s", opts.arg); arg_action = arg_action == ACTION_ROTATE ? ACTION_ROTATE_AND_VACUUM : ACTION_VACUUM; break; - case ARG_VERIFY: + OPTION_LONG("verify", NULL, "Verify journal file consistency"): arg_action = ACTION_VERIFY; break; - case ARG_SYNC: + OPTION_LONG("sync", NULL, "Synchronize unwritten journal messages to disk"): arg_action = ACTION_SYNC; break; - case ARG_SMART_RELINQUISH_VAR: { + OPTION_LONG("smart-relinquish-var", NULL, + "Similar, but NOP if log directory is on root mount"): { int root_mnt_id, log_mnt_id; /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown: @@ -1030,45 +873,51 @@ static int parse_argv(int argc, char *argv[]) { _fallthrough_; } - case ARG_RELINQUISH_VAR: + OPTION_LONG("relinquish-var", NULL, "Stop logging to disk, log to temporary file system"): arg_action = ACTION_RELINQUISH_VAR; break; - case ARG_FLUSH: + OPTION_LONG("flush", NULL, "Flush all journal data from /run into /var"): arg_action = ACTION_FLUSH; break; - case ARG_ROTATE: + OPTION_LONG("rotate", NULL, "Request immediate rotation of the journal files"): arg_action = arg_action == ACTION_VACUUM ? ACTION_ROTATE_AND_VACUUM : ACTION_ROTATE; break; - case ARG_HEADER: + OPTION_LONG("header", NULL, "Show journal header information"): arg_action = ACTION_PRINT_HEADER; break; - case ARG_LIST_CATALOG: + OPTION_LONG("list-catalog", NULL, "Show all message IDs in the catalog"): arg_action = ACTION_LIST_CATALOG; break; - case ARG_DUMP_CATALOG: + OPTION_LONG("dump-catalog", NULL, "Show entries in the message catalog"): arg_action = ACTION_DUMP_CATALOG; break; - case ARG_UPDATE_CATALOG: + OPTION_LONG("update-catalog", NULL, "Update the message catalog database"): arg_action = ACTION_UPDATE_CATALOG; break; - case ARG_NEW_ID128: + OPTION_LONG("setup-keys", NULL, "Generate a new FSS key pair"): +#if HAVE_GCRYPT + arg_action = ACTION_SETUP_KEYS; + break; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Compiled without forward-secure sealing support."); +#endif + + OPTION_LONG("new-id128", NULL, /* help= */ NULL): arg_action = ACTION_NEW_ID128; break; - - case '?': - return -EINVAL; - - default: - assert_not_reached(); } + char **args = option_parser_get_args(&opts); + size_t n_args = option_parser_get_n_args(&opts); + if (arg_no_tail) arg_lines = ARG_LINES_ALL; @@ -1109,10 +958,10 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--lines=+N is unsupported when --reverse or --follow is specified."); - if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) + if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && n_args > 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Extraneous arguments starting with '%s'", - argv[optind]); + args[0]); if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && arg_merge) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -1146,6 +995,11 @@ static int parse_argv(int argc, char *argv[]) { if (!arg_follow) arg_journal_additional_open_flags = SD_JOURNAL_ASSUME_IMMUTABLE; + args = strv_copy(args); + if (!args) + return log_oom(); + + *remaining_args = args; return 1; } @@ -1158,17 +1012,13 @@ static int run(int argc, char *argv[]) { setlocale(LC_ALL, ""); log_setup(); - r = parse_argv(argc, argv); + r = parse_argv(argc, argv, &args); if (r <= 0) return r; if (arg_varlink) return vl_server(); - r = strv_copy_unless_empty(strv_skip(argv, optind), &args); - if (r < 0) - return log_oom(); - if (arg_image) { assert(!arg_root); From 1dbd734048b9424f5eacfffe51ce3b5da6334df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 12 May 2026 14:05:01 +0200 Subject: [PATCH 4/6] journalctl: drop some parentheses --- src/journal/journalctl.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 2b4995714f5..a48e28497d3 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -527,55 +527,44 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { break; OPTION('p', "priority", "RANGE", "Show entries within the specified priority range"): { - const char *dots; - dots = strstr(opts.arg, ".."); + const char *dots = strstr(opts.arg, ".."); if (dots) { - _cleanup_free_ char *a = NULL; - int from, to, i; - /* a range */ - a = strndup(opts.arg, dots - opts.arg); + _cleanup_free_ char *a = strndup(opts.arg, dots - opts.arg); if (!a) return log_oom(); - from = log_level_from_string(a); - to = log_level_from_string(dots + 2); + int from = log_level_from_string(a), + to = log_level_from_string(dots + 2); if (from < 0 || to < 0) return log_error_errno(from < 0 ? from : to, "Failed to parse log level range %s", opts.arg); arg_priorities = 0; - - if (from < to) { - for (i = from; i <= to; i++) + if (from < to) + for (int i = from; i <= to; i++) arg_priorities |= 1 << i; - } else { - for (i = to; i <= from; i++) + else + for (int i = to; i <= from; i++) arg_priorities |= 1 << i; - } } else { - int p, i; - - p = log_level_from_string(opts.arg); + int p = log_level_from_string(opts.arg); if (p < 0) return log_error_errno(p, "Unknown log level %s", opts.arg); arg_priorities = 0; - - for (i = 0; i <= p; i++) + for (int i = 0; i <= p; i++) arg_priorities |= 1 << i; } break; } - OPTION_LONG("facility", "FACILITY…", "Show entries with the specified facilities"): { - const char *p; - - for (p = opts.arg;;) { + OPTION_LONG("facility", "FACILITY…", "Show entries with the specified facilities"): + for (const char *p = opts.arg;;) { _cleanup_free_ char *fac = NULL; int num; @@ -599,7 +588,6 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { } break; - } OPTION('g', "grep", "PATTERN", "Show entries with MESSAGE matching PATTERN"): r = free_and_strdup_warn(&arg_pattern, opts.arg); From 1955c18a18b2822b35b3ab37bb868fff05f33fa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 12 May 2026 14:37:35 +0200 Subject: [PATCH 5/6] journalctl: move handling of --smart-relinquish-var to action logic The help string for --smart-relinquish-var and --relinquish-var were in reversed order because of the _fallthrough_. We would resolve the conditions for "smart relinquish" immediately in parse_argv() and call 'return 0' if the conditions were wrong, terminating option parsing and the program. It seems nicer to delay action until later. This makes the logic flow more standard. This also allows the option parsing cases to be exchanged, fixing the issue with --help. --- src/journal/journalctl-varlink.c | 2 +- src/journal/journalctl.c | 56 +++++++++++++++++--------------- src/journal/journalctl.h | 1 + 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/src/journal/journalctl-varlink.c b/src/journal/journalctl-varlink.c index c278bc33657..a38c320a4f8 100644 --- a/src/journal/journalctl-varlink.c +++ b/src/journal/journalctl-varlink.c @@ -65,7 +65,7 @@ int action_relinquish_var(void) { _cleanup_(sd_varlink_flush_close_unrefp) sd_varlink *link = NULL; int r; - assert(arg_action == ACTION_RELINQUISH_VAR); + assert(IN_SET(arg_action, ACTION_RELINQUISH_VAR, ACTION_SMART_RELINQUISH_VAR)); if (arg_machine || arg_namespace) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index a48e28497d3..c5009eb6f05 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -835,36 +835,15 @@ static int parse_argv(int argc, char *argv[], char ***remaining_args) { arg_action = ACTION_SYNC; break; - OPTION_LONG("smart-relinquish-var", NULL, - "Similar, but NOP if log directory is on root mount"): { - int root_mnt_id, log_mnt_id; - - /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown: - * if it's on the same mount as the root file system there's no point in - * relinquishing access and we can leave journald write to it until the very last - * moment. */ - - r = path_get_mnt_id("/", &root_mnt_id); - if (r < 0) - log_debug_errno(r, "Failed to get root mount ID, ignoring: %m"); - else { - r = path_get_mnt_id("/var/log/journal/", &log_mnt_id); - if (r < 0) - log_debug_errno(r, "Failed to get journal directory mount ID, ignoring: %m"); - else if (root_mnt_id == log_mnt_id) { - log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var."); - return 0; - } else - log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it."); - } - - _fallthrough_; - } - OPTION_LONG("relinquish-var", NULL, "Stop logging to disk, log to temporary file system"): arg_action = ACTION_RELINQUISH_VAR; break; + OPTION_LONG("smart-relinquish-var", NULL, + "Similar, but NOP if log directory is on root mount"): + arg_action = ACTION_SMART_RELINQUISH_VAR; + break; + OPTION_LONG("flush", NULL, "Flush all journal data from /run into /var"): arg_action = ACTION_FLUSH; break; @@ -1075,6 +1054,31 @@ static int run(int argc, char *argv[]) { case ACTION_FLUSH: return action_flush_to_var(); + case ACTION_SMART_RELINQUISH_VAR: { + int root_mnt_id, log_mnt_id; + + /* Try to be smart about relinquishing access to /var/log/journal/ during shutdown: + * if it's on the same mount as the root file system there's no point in + * relinquishing access and we can leave journald write to it until the very last + * moment. */ + + r = path_get_mnt_id("/", &root_mnt_id); + if (r < 0) + log_debug_errno(r, "Failed to get root mount ID, ignoring: %m"); + else { + r = path_get_mnt_id("/var/log/journal/", &log_mnt_id); + if (r < 0) + log_debug_errno(r, "Failed to get journal directory mount ID, ignoring: %m"); + else if (root_mnt_id == log_mnt_id) { + log_debug("/var/log/journal/ is on root file system, not relinquishing access to /var."); + return 0; + } else + log_debug("/var/log/journal/ is not on the root file system, relinquishing access to it."); + } + + _fallthrough_; + } + case ACTION_RELINQUISH_VAR: return action_relinquish_var(); diff --git a/src/journal/journalctl.h b/src/journal/journalctl.h index 090e3382496..406a16077be 100644 --- a/src/journal/journalctl.h +++ b/src/journal/journalctl.h @@ -21,6 +21,7 @@ typedef enum JournalctlAction { ACTION_LIST_NAMESPACES, ACTION_FLUSH, ACTION_RELINQUISH_VAR, + ACTION_SMART_RELINQUISH_VAR, ACTION_SYNC, ACTION_ROTATE, ACTION_VACUUM, From f2a4288412da482612220f78a2410a4a9dcd1176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 12 May 2026 16:22:18 +0200 Subject: [PATCH 6/6] storagectl: add assert for args MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit coccinelle-storage check started failing… --- src/storage/storagectl.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/storage/storagectl.c b/src/storage/storagectl.c index d3ae3f91453..1a10a097944 100644 --- a/src/storage/storagectl.c +++ b/src/storage/storagectl.c @@ -399,11 +399,12 @@ static int verb_providers(int argc, char *argv[], uintptr_t data, void *userdata return 0; } -static int parse_argv(int argc, char *argv[], char ***args) { +static int parse_argv(int argc, char *argv[], char ***remaining_args) { int r; assert(argc >= 0); assert(argv); + assert(remaining_args); OptionParser opts = { argc, argv }; FOREACH_OPTION_OR_RETURN(c, &opts) @@ -442,7 +443,7 @@ static int parse_argv(int argc, char *argv[], char ***args) { break; } - *args = option_parser_get_args(&opts); + *remaining_args = option_parser_get_args(&opts); return 1; }