mirror of
https://github.com/Dasharo/systemd.git
synced 2026-03-06 15:02:31 -08:00
We seem to have no tool to verify udev rule files. There is a simple udev rules syntax checker in the tree, test/rule-syntax-check.py, but it is too simple to detect less trivial issues not detected by udev, e.g. redundant comparisons (#26593) or labels without references. Such a tool would be beneficial not only for maintaining udev rules distributed along with udev, but also and even more so for maintaining third party udev rules that are more likely to have issues with syntax and semantic correctness. Implement a udev rules syntax and semantics checker in the form of 'udevadm verify [OPTIONS] FILE...' command that is based on udev_rules_parse_file() interface and would apply further checks on top of it in subsequent commits. Resolves: #26606
319 lines
10 KiB
Bash
319 lines
10 KiB
Bash
# udevadm(8) completion -*- shell-script -*-
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
#
|
|
# This file is part of systemd.
|
|
#
|
|
# Copyright © 2010 Ran Benita
|
|
#
|
|
# systemd is free software; you can redistribute it and/or modify it
|
|
# under the terms of the GNU Lesser General Public License as published by
|
|
# the Free Software Foundation; either version 2.1 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# systemd is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public License
|
|
# along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
__contains_word () {
|
|
local w word=$1; shift
|
|
for w in "$@"; do
|
|
[[ $w = "$word" ]] && return
|
|
done
|
|
}
|
|
|
|
__get_all_sysdevs() {
|
|
local -a devs=(/sys/bus/*/devices/*/ /sys/class/*/*/)
|
|
printf '%s\n' "${devs[@]%/}"
|
|
}
|
|
|
|
__get_all_devs() {
|
|
local i
|
|
for i in /dev/* /dev/*/* /dev/*/*/*; do
|
|
echo $i
|
|
done
|
|
}
|
|
|
|
__get_all_device_units() {
|
|
systemctl list-units -t device --full --no-legend --no-pager --plain 2>/dev/null | \
|
|
{ while read -r a b; do echo "$a"; done; }
|
|
}
|
|
|
|
_udevadm() {
|
|
local i verb comps builtin
|
|
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
|
|
local -A OPTS=(
|
|
[COMMON]='-h --help -V --version'
|
|
[DEBUG]='-d --debug'
|
|
[INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db
|
|
-w --wait-for-initialization --value'
|
|
[INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file --property'
|
|
[TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid
|
|
--initialized-match --initialized-nomatch'
|
|
[TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
|
|
-a --attr-match -A --attr-nomatch -p --property-match
|
|
-g --tag-match -y --sysname-match --name-match -b --parent-match
|
|
--prioritized-subsystem'
|
|
[SETTLE]='-t --timeout -E --exit-if-exists'
|
|
[CONTROL_STANDALONE]='-e --exit -s --stop-exec-queue -S --start-exec-queue -R --reload --ping'
|
|
[CONTROL_ARG]='-l --log-priority -p --property -m --children-max -t --timeout'
|
|
[MONITOR_STANDALONE]='-k --kernel -u --udev -p --property'
|
|
[MONITOR_ARG]='-s --subsystem-match -t --tag-match'
|
|
[TEST]='-a --action -N --resolve-names'
|
|
[TEST_BUILTIN]='-a --action'
|
|
[VERIFY]='-N --resolve-names'
|
|
[WAIT]='-t --timeout --initialized=no --removed --settle'
|
|
[LOCK]='-t --timeout -d --device -b --backing -p --print'
|
|
)
|
|
|
|
local verbs=(info trigger settle control monitor test-builtin test verify wait lock)
|
|
local builtins=(blkid btrfs hwdb input_id keyboard kmod net_id net_setup_link path_id usb_id uaccess)
|
|
|
|
for ((i=0; i < COMP_CWORD; i++)); do
|
|
if __contains_word "${COMP_WORDS[i]}" "${verbs[@]}"; then
|
|
verb=${COMP_WORDS[i]}
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ -z ${verb-} ]]; then
|
|
if [[ "$cur" = -* ]]; then
|
|
COMPREPLY=( $(compgen -W '${OPTS[COMMON]} ${OPTS[DEBUG]}' -- "$cur") )
|
|
else
|
|
COMPREPLY=( $(compgen -W '${verbs[*]}' -- "$cur") )
|
|
fi
|
|
return 0
|
|
fi
|
|
|
|
case $verb in
|
|
'info')
|
|
if __contains_word "$prev" ${OPTS[INFO_ARG]}; then
|
|
case $prev in
|
|
-q|--query)
|
|
comps='name symlink path property all'
|
|
;;
|
|
-p|--path)
|
|
comps=$( __get_all_sysdevs )
|
|
local IFS=$'\n'
|
|
;;
|
|
-n|--name)
|
|
comps=$( __get_all_devs )
|
|
;;
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ $cur = -* ]]; then
|
|
comps="${OPTS[COMMON]} ${OPTS[INFO_STANDALONE]} ${OPTS[INFO_ARG]}"
|
|
else
|
|
comps=$( __get_all_sysdevs; __get_all_device_units )
|
|
local IFS=$'\n'
|
|
fi
|
|
;;
|
|
|
|
'trigger')
|
|
if __contains_word "$prev" ${OPTS[TRIGGER_ARG]}; then
|
|
case $prev in
|
|
-t|--type)
|
|
comps='all devices subsystems'
|
|
;;
|
|
-c|--action)
|
|
comps=$( udevadm trigger --action help )
|
|
;;
|
|
-y|--sysname-match|-b|--parent-match)
|
|
comps=$( __get_all_sysdevs )
|
|
local IFS=$'\n'
|
|
;;
|
|
--name-match)
|
|
comps=$( __get_all_devs )
|
|
;;
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ $cur = -* ]]; then
|
|
comps="${OPTS[COMMON]} ${OPTS[TRIGGER_STANDALONE]} ${OPTS[TRIGGER_ARG]}"
|
|
else
|
|
comps=$( __get_all_sysdevs; __get_all_device_units )
|
|
local IFS=$'\n'
|
|
fi
|
|
;;
|
|
|
|
'settle')
|
|
if __contains_word "$prev" ${OPTS[SETTLE]}; then
|
|
case $prev in
|
|
-E|--exit-if-exists)
|
|
comps=$( compgen -A file -- "$cur" )
|
|
;;
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
comps="${OPTS[COMMON]} ${OPTS[SETTLE]}"
|
|
;;
|
|
|
|
'control')
|
|
if __contains_word "$prev" ${OPTS[CONTROL_ARG]}; then
|
|
case $prev in
|
|
-l|--log-priority)
|
|
comps='alert crit debug emerg err info notice warning'
|
|
;;
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
comps="${OPTS[COMMON]} ${OPTS[CONTROL_STANDALONE]} ${OPTS[CONTROL_ARG]}"
|
|
;;
|
|
|
|
'monitor')
|
|
if __contains_word "$prev" ${OPTS[MONITOR_ARG]}; then
|
|
case $prev in
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
comps="${OPTS[COMMON]} ${OPTS[MONITOR_STANDALONE]} ${OPTS[MONITOR_ARG]}"
|
|
;;
|
|
|
|
'test')
|
|
if __contains_word "$prev" ${OPTS[TEST]}; then
|
|
case $prev in
|
|
-a|--action)
|
|
comps=$( udevadm test --action help )
|
|
;;
|
|
-N|--resolve-names)
|
|
comps='early late never'
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ $cur = -* ]]; then
|
|
comps="${OPTS[COMMON]} ${OPTS[TEST]}"
|
|
else
|
|
comps=$( __get_all_sysdevs )
|
|
local IFS=$'\n'
|
|
fi
|
|
;;
|
|
|
|
'test-builtin')
|
|
if __contains_word "$prev" ${OPTS[TEST_BUILTIN]}; then
|
|
case $prev in
|
|
-a|--action)
|
|
comps=$( udevadm test-builtin --action help )
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
for ((i=0; i < COMP_CWORD; i++)); do
|
|
if __contains_word "${COMP_WORDS[i]}" "${builtins[@]}"; then
|
|
builtin=${COMP_WORDS[i]}
|
|
break
|
|
fi
|
|
done
|
|
|
|
if [[ -z $builtin ]]; then
|
|
comps="${builtins[@]}"
|
|
elif [[ $cur = -* ]]; then
|
|
comps="${OPTS[COMMON]} ${OPTS[TEST_BUILTIN]}"
|
|
else
|
|
comps=$( __get_all_sysdevs )
|
|
local IFS=$'\n'
|
|
fi
|
|
;;
|
|
|
|
'verify')
|
|
if __contains_word "$prev" ${OPTS[VERIFY]}; then
|
|
case $prev in
|
|
-N|--resolve-names)
|
|
comps='early never'
|
|
;;
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ $cur = -* ]]; then
|
|
comps="${OPTS[COMMON]} ${OPTS[VERIFY]}"
|
|
else
|
|
comps=$( compgen -A file -- "$cur" )
|
|
fi
|
|
;;
|
|
|
|
'wait')
|
|
if __contains_word "$prev" ${OPTS[WAIT]}; then
|
|
case $prev in
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ $cur = -* ]]; then
|
|
comps="${OPTS[COMMON]} ${OPTS[WAIT]}"
|
|
else
|
|
comps=$( __get_all_devs )
|
|
local IFS=$'\n'
|
|
fi
|
|
;;
|
|
|
|
'lock')
|
|
if __contains_word "$prev" ${OPTS[LOCK]}; then
|
|
case $prev in
|
|
*)
|
|
comps=''
|
|
;;
|
|
esac
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
fi
|
|
|
|
if [[ $cur = -* ]]; then
|
|
comps="${OPTS[COMMON]} ${OPTS[LOCK]}"
|
|
else
|
|
comps=''
|
|
fi
|
|
;;
|
|
|
|
*)
|
|
comps=${VERBS[*]}
|
|
;;
|
|
esac
|
|
|
|
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
|
|
return 0
|
|
}
|
|
|
|
complete -F _udevadm udevadm
|