diff --git a/man/udevadm.xml b/man/udevadm.xml index bafd5af0fb9..503ec810918 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -769,6 +769,11 @@ parsed. When set to never, names will never be resolved. + + + When looking for udev rules files located in udev/rules.d directories, + operate on files underneath the specified root path PATH. + diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index b6e14e1d36e..3c3c403153b 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -64,7 +64,7 @@ _udevadm() { [MONITOR_ARG]='-s --subsystem-match -t --tag-match' [TEST]='-a --action -N --resolve-names' [TEST_BUILTIN]='-a --action' - [VERIFY]='-N --resolve-names' + [VERIFY]='-N --resolve-names --root' [WAIT]='-t --timeout --initialized=no --removed --settle' [LOCK]='-t --timeout -d --device -b --backing -p --print' ) @@ -254,6 +254,10 @@ _udevadm() { -N|--resolve-names) comps='early never' ;; + --root) + comps=$(compgen -A directory -- "$cur" ) + compopt -o dirnames + ;; *) comps='' ;; diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index 074d367a9de..e8414eef679 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -108,6 +108,7 @@ _udevadm_test-builtin(){ _udevadm_verify(){ _arguments \ {-N+,--resolve-names=}'[When to resolve names.]:resolve:(early never)' \ + '--root=[Operate on catalog hierarchy under specified directory]:directories:_directories' \ {-h,--help}'[Print help text.]' \ '*::files:_files' } diff --git a/src/udev/udevadm-verify.c b/src/udev/udevadm-verify.c index f4728927312..26f317711e9 100644 --- a/src/udev/udevadm-verify.c +++ b/src/udev/udevadm-verify.c @@ -10,12 +10,17 @@ #include "conf-files.h" #include "constants.h" #include "log.h" +#include "parse-argument.h" #include "pretty-print.h" +#include "static-destruct.h" #include "strv.h" #include "udev-rules.h" #include "udevadm.h" static ResolveNameTiming arg_resolve_name_timing = RESOLVE_NAME_EARLY; +static char *arg_root = NULL; + +STATIC_DESTRUCTOR_REGISTER(arg_root, freep); static int help(void) { _cleanup_free_ char *link = NULL; @@ -30,6 +35,7 @@ static int help(void) { " -h --help Show this help\n" " -V --version Show package version\n" " -N --resolve-names=early|never When to resolve names\n" + " --root=PATH Operate on an alternate filesystem root\n" "\nSee the %s for details.\n", program_invocation_short_name, ansi_highlight(), @@ -40,14 +46,18 @@ static int help(void) { } static int parse_argv(int argc, char *argv[]) { + enum { + ARG_ROOT = 0x100, + }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - { "resolve-names", required_argument, NULL, 'N' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "resolve-names", required_argument, NULL, 'N' }, + { "root", required_argument, NULL, ARG_ROOT }, {} }; - int c; + int r, c; assert(argc >= 0); assert(argv); @@ -71,12 +81,22 @@ static int parse_argv(int argc, char *argv[]) { if (arg_resolve_name_timing == RESOLVE_NAME_NEVER) arg_resolve_name_timing = RESOLVE_NAME_LATE; break; + case ARG_ROOT: + r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root); + if (r < 0) + return r; + break; + case '?': return -EINVAL; default: assert_not_reached(); } + if (arg_root && optind < argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Combination of --root= and FILEs is not supported."); + return 1; } @@ -124,9 +144,12 @@ int verify_main(int argc, char *argv[], void *userdata) { const char* const* rules_dirs = STRV_MAKE_CONST(CONF_PATHS("udev/rules.d")); _cleanup_strv_free_ char **files = NULL; - r = conf_files_list_strv(&files, ".rules", NULL, 0, rules_dirs); + r = conf_files_list_strv(&files, ".rules", arg_root, 0, rules_dirs); if (r < 0) return log_error_errno(r, "Failed to enumerate rules files: %m"); + if (arg_root && strv_isempty(files)) + return log_error_errno(SYNTHETIC_ERRNO(ENOENT), + "No rules files found in %s", arg_root); return verify_rules(rules, files); }