From 8de7929de5b70c4a130a0477c2f9baeecb86c905 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 23 Aug 2021 16:44:58 +0100 Subject: [PATCH] mkosi: Add zsh to Arch packages Useful for testing zsh completion changes. --- .mkosi/mkosi.arch | 3 ++ man/systemd-analyze.xml | 14 +++++++++ shell-completion/bash/systemd-analyze | 15 ++++++++- src/analyze/analyze-condition.c | 45 ++++++++++++++++++++++----- src/analyze/analyze-condition.h | 2 +- src/analyze/analyze.c | 32 ++++++++++++++++--- 6 files changed, 96 insertions(+), 15 deletions(-) diff --git a/.mkosi/mkosi.arch b/.mkosi/mkosi.arch index cb8fb01ef27..f584d2d1267 100644 --- a/.mkosi/mkosi.arch +++ b/.mkosi/mkosi.arch @@ -56,3 +56,6 @@ Packages= man-db # For testing systemd's bash completion scripts. bash-completion + # For testing systemd's zsh completion scripts + # Run `autoload -Uz compinit; compinit` from a zsh shell in the booted image to enable completions. + zsh diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 932218d80e0..fb2a1caa9e5 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -1123,6 +1123,20 @@ Service b@0.service not loaded, b.socket cannot be started. to the specified point in time. If not specified defaults to the current time. + + + + When used with the condition command, evaluate all the + Condition*=... and Assert*=... + assignments in the specified unit file. The full unit search path is formed by combining the + directories for the specified unit with the usual unit load paths. The variable + $SYSTEMD_UNIT_PATH is supported, and may be used to replace or augment the + compiled in set of unit load paths; see + systemd.unit5. All + units files present in the directory containing the specified unit will be used in preference to the + other paths. + + diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze index 07d069a6d71..6bed5e73e8b 100644 --- a/shell-completion/bash/systemd-analyze +++ b/shell-completion/bash/systemd-analyze @@ -55,13 +55,14 @@ _systemd_analyze() { ) local -A VERBS=( - [STANDALONE]='time blame plot dump unit-paths exit-status condition calendar timestamp timespan' + [STANDALONE]='time blame plot dump unit-paths exit-status calendar timestamp timespan' [CRITICAL_CHAIN]='critical-chain' [DOT]='dot' [VERIFY]='verify' [SECCOMP_FILTER]='syscall-filter' [CAT_CONFIG]='cat-config' [SECURITY]='security' + [CONDITION]='condition' ) local CONFIGS='systemd/bootchart.conf systemd/coredump.conf systemd/journald.conf @@ -153,6 +154,18 @@ _systemd_analyze() { fi comps=$( __get_services $mode ) fi + + elif __contains_word "$verb" ${VERBS[CONDITION]}; then + if [[ $cur = -* ]]; then + comps='--help --version --system --user --global --no-pager --root --image' + elif [[ $prev = "-u" ]] || [[ $prev = "--unit" ]]; then + if __contains_word "--user" ${COMP_WORDS[*]}; then + mode=--user + else + mode=--system + fi + comps=$( __get_services $mode ) + fi fi COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) diff --git a/src/analyze/analyze-condition.c b/src/analyze/analyze-condition.c index 09870b95ec4..f57bb27b9a8 100644 --- a/src/analyze/analyze-condition.c +++ b/src/analyze/analyze-condition.c @@ -3,6 +3,7 @@ #include #include "analyze-condition.h" +#include "analyze-verify.h" #include "condition.h" #include "conf-parser.h" #include "load-fragment.h" @@ -72,29 +73,57 @@ static int log_helper(void *userdata, int level, int error, const char *file, in return r; } -int verify_conditions(char **lines, UnitFileScope scope) { +int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const char *root) { _cleanup_(manager_freep) Manager *m = NULL; Unit *u; - char **line; int r, q = 1; + if (unit) { + _cleanup_strv_free_ char **filenames = NULL; + _cleanup_free_ char *var = NULL; + + filenames = strv_new(unit); + if (!filenames) + return log_oom(); + + r = verify_generate_path(&var, filenames); + if (r < 0) + return log_error_errno(r, "Failed to generate unit load path: %m"); + + assert_se(set_unit_path(var) >= 0); + } + r = manager_new(scope, MANAGER_TEST_RUN_MINIMAL, &m); if (r < 0) return log_error_errno(r, "Failed to initialize manager: %m"); log_debug("Starting manager..."); - r = manager_startup(m, /* serialization= */ NULL, /* fds= */ NULL, /* root= */ NULL); + r = manager_startup(m, /* serialization= */ NULL, /* fds= */ NULL, root); if (r < 0) return r; - r = unit_new_for_name(m, sizeof(Service), "test.service", &u); - if (r < 0) - return log_error_errno(r, "Failed to create test.service: %m"); + if (unit) { + _cleanup_free_ char *prepared = NULL; - STRV_FOREACH(line, lines) { - r = parse_condition(u, *line); + r = verify_prepare_filename(unit, &prepared); + if (r < 0) + return log_error_errno(r, "Failed to prepare filename %s: %m", unit); + + r = manager_load_startable_unit_or_warn(m, NULL, prepared, &u); if (r < 0) return r; + } else { + char **line; + + r = unit_new_for_name(m, sizeof(Service), "test.service", &u); + if (r < 0) + return log_error_errno(r, "Failed to create test.service: %m"); + + STRV_FOREACH(line, lines) { + r = parse_condition(u, *line); + if (r < 0) + return r; + } } r = condition_test_list(u->asserts, environ, assert_type_to_string, log_helper, u); diff --git a/src/analyze/analyze-condition.h b/src/analyze/analyze-condition.h index 7b52669d05e..9ebd205b6d6 100644 --- a/src/analyze/analyze-condition.h +++ b/src/analyze/analyze-condition.h @@ -3,4 +3,4 @@ #include "install.h" -int verify_conditions(char **lines, UnitFileScope scope); +int verify_conditions(char **lines, UnitFileScope scope, const char *unit, const char *root); diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 816532f69e0..68b9941afe5 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -96,12 +96,14 @@ static bool arg_offline = false; static unsigned arg_threshold = 100; static unsigned arg_iterations = 1; static usec_t arg_base_time = USEC_INFINITY; +static char *arg_unit = NULL; STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_security_policy, freep); +STATIC_DESTRUCTOR_REGISTER(arg_unit, freep); typedef struct BootTimes { usec_t firmware_time; @@ -2147,7 +2149,7 @@ static int service_watchdogs(int argc, char *argv[], void *userdata) { } static int do_condition(int argc, char *argv[], void *userdata) { - return verify_conditions(strv_skip(argv, 1), arg_scope); + return verify_conditions(strv_skip(argv, 1), arg_scope, arg_unit, arg_root); } static int do_verify(int argc, char *argv[], void *userdata) { @@ -2327,6 +2329,7 @@ static int parse_argv(int argc, char *argv[]) { { "machine", required_argument, NULL, 'M' }, { "iterations", required_argument, NULL, ARG_ITERATIONS }, { "base-time", required_argument, NULL, ARG_BASE_TIME }, + { "unit", required_argument, NULL, 'U' }, {} }; @@ -2335,7 +2338,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hH:M:U:", options, NULL)) >= 0) switch (c) { case 'h': @@ -2465,6 +2468,16 @@ static int parse_argv(int argc, char *argv[]) { break; + case 'U': { + _cleanup_free_ char *mangled = NULL; + + r = unit_name_mangle(optarg, UNIT_NAME_MANGLE_WARN, &mangled); + if (r < 0) + return log_error_errno(r, "Failed to mangle unit name %s: %m", optarg); + + free_and_replace(arg_unit, mangled); + break; + } case '?': return -EINVAL; @@ -2493,15 +2506,24 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --security-policy= is only supported for security."); - if ((arg_root || arg_image) && (!STRPTR_IN_SET(argv[optind], "cat-config", "verify")) && + if ((arg_root || arg_image) && (!STRPTR_IN_SET(argv[optind], "cat-config", "verify", "condition")) && (!(streq_ptr(argv[optind], "security") && arg_offline))) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Options --root= and --image= are only supported for cat-config, verify and security when used with --offline= right now."); + "Options --root= and --image= are only supported for cat-config, verify, condition and security when used with --offline= right now."); /* Having both an image and a root is not supported by the code */ if (arg_root && arg_image) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported."); + if (arg_unit && !streq_ptr(argv[optind], "condition")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --unit= is only supported for condition"); + + if (streq_ptr(argv[optind], "condition") && !arg_unit && optind >= argc - 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too few arguments for condition"); + + if (streq_ptr(argv[optind], "condition") && arg_unit && optind < argc - 1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No conditions can be passed if --unit= is used."); + return 1; /* work to do */ } @@ -2532,7 +2554,7 @@ static int run(int argc, char *argv[]) { { "exit-status", VERB_ANY, VERB_ANY, 0, dump_exit_status }, { "syscall-filter", VERB_ANY, VERB_ANY, 0, dump_syscall_filters }, { "capability", VERB_ANY, VERB_ANY, 0, dump_capabilities }, - { "condition", 2, VERB_ANY, 0, do_condition }, + { "condition", VERB_ANY, VERB_ANY, 0, do_condition }, { "verify", 2, VERB_ANY, 0, do_verify }, { "calendar", 2, VERB_ANY, 0, test_calendar }, { "timestamp", 2, VERB_ANY, 0, test_timestamp }, -- 2.39.2