1# resolvectl(1) completion                                  -*- shell-script -*-
2# SPDX-License-Identifier: LGPL-2.1-or-later
3#
4# This file is part of systemd.
5#
6# systemd is free software; you can redistribute it and/or modify it
7# under the terms of the GNU Lesser General Public License as published by
8# the Free Software Foundation; either version 2.1 of the License, or
9# (at your option) any later version.
10#
11# systemd is distributed in the hope that it will be useful, but
12# WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14# General Public License for more details.
15#
16# You should have received a copy of the GNU Lesser General Public License
17# along with systemd; If not, see <http://www.gnu.org/licenses/>.
18
19__contains_word () {
20    local w word=$1; shift
21    for w in "$@"; do
22        [[ $w = "$word" ]] && return
23    done
24}
25
26__get_interfaces(){
27    local name
28    for name in $(cd /sys/class/net && command ls); do
29        [[ "$name" != "lo" ]] && echo "$name"
30    done
31}
32
33_resolvectl() {
34    local i comps verb name
35    local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
36    local -A OPTS=(
37        [STANDALONE]='-h --help --version -4 -6 --legend=no --cname=no
38                      --validate=no --synthesize=no --cache=no --zone=no
39                      --trust-anchor=no --network=no --service-address=no
40                      --service-txt=no --search=no --no-pager'
41        [ARG]='-t --type -c --class -i --interface -p --protocol --raw'
42    )
43    local -A VERBS=(
44        [DOMAIN]='query service openpgp'
45        [FAMILY]='tlsa'
46        [STATUS]='status'
47        [LINK]='revert dns domain nta'
48        [BOOLEAN]='default-route'
49        [RESOLVE]='llmnr mdns'
50        [DNSSEC]='dnssec'
51        [DNSOVERTLS]='dnsovertls'
52        [STANDALONE]='statistics reset-statistics flush-caches reset-server-features'
53        [LOG_LEVEL]='log-level'
54    )
55    local -A ARGS=(
56        [FAMILY]='tcp udp sctp'
57        [BOOLEAN]='yes no'
58        [RESOLVE]='yes no resolve'
59        [DNSSEC]='yes no allow-downgrade'
60        [DNSOVERTLS]='yes no opportunistic'
61    )
62    local interfaces=$( __get_interfaces )
63
64    if __contains_word "$prev" ${OPTS[ARG]}; then
65        case $prev in
66            --interface|-i)
67                comps="$interfaces"
68                ;;
69            --protocol|-p|--type|-t|--class|-c)
70                comps=$( resolvectl --legend=no "$prev" help; echo help )
71                ;;
72            --raw)
73                comps="payload packet"
74                ;;
75        esac
76        COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
77        return 0
78    fi
79
80    if [[ "$cur" = -* ]]; then
81        COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
82        return 0
83    fi
84
85    for ((i=0; i < COMP_CWORD; i++)); do
86        if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
87                ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
88            verb=${COMP_WORDS[i]}
89            break
90        fi
91    done
92
93    if [[ -z ${verb-} ]]; then
94        comps="${VERBS[*]}"
95
96    elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[DOMAIN]}; then
97        comps=''
98
99    elif __contains_word "$verb" ${VERBS[STATUS]}; then
100        comps="$interfaces"
101
102    elif __contains_word "$verb" ${VERBS[LOG_LEVEL]}; then
103        comps='debug info notice warning err crit alert emerg'
104
105    elif __contains_word "$verb" ${VERBS[FAMILY]}; then
106        for ((i++; i < COMP_CWORD; i++)); do
107            if __contains_word "${COMP_WORDS[i]}" ${ARGS[FAMILY]} &&
108                    ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
109                name=${COMP_WORDS[i]}
110                break;
111            fi
112        done
113        if [[ -z $name ]]; then
114            comps=${ARGS[FAMILY]}
115        else
116            comps=""
117        fi
118
119    elif __contains_word "$verb" ${VERBS[LINK]} ${VERBS[BOOLEAN]} ${VERBS[RESOLVE]} ${VERBS[DNSSEC]} ${VERBS[DNSOVERTLS]}; then
120        for ((i++; i < COMP_CWORD; i++)); do
121            if __contains_word "${COMP_WORDS[i]}" $interfaces &&
122                    ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
123                name=${COMP_WORDS[i]}
124                break;
125            fi
126        done
127
128        if [[ -z $name ]]; then
129            comps="$interfaces"
130
131        elif __contains_word "$verb" ${VERBS[RESOLVE]}; then
132            name=
133            for ((i++; i < COMP_CWORD; i++)); do
134                if __contains_word "${COMP_WORDS[i]}" ${ARGS[RESOLVE]} &&
135                        ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
136                    name=${COMP_WORDS[i]}
137                    break;
138                fi
139            done
140
141            if [[ -z $name ]]; then
142                comps=${ARGS[RESOLVE]}
143            else
144                comps=''
145            fi
146
147        elif __contains_word "$verb" ${VERBS[BOOLEAN]}; then
148            name=
149            for ((i++; i < COMP_CWORD; i++)); do
150                if __contains_word "${COMP_WORDS[i]}" ${ARGS[BOOLEAN]} &&
151                        ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
152                    name=${COMP_WORDS[i]}
153                    break;
154                fi
155            done
156
157            if [[ -z $name ]]; then
158                comps=${ARGS[BOOLEAN]}
159            else
160                comps=''
161            fi
162
163        elif __contains_word "$verb" ${VERBS[DNSSEC]}; then
164            name=
165            for ((i++; i < COMP_CWORD; i++)); do
166                if __contains_word "${COMP_WORDS[i]}" ${ARGS[DNSSEC]} &&
167                        ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
168                    name=${COMP_WORDS[i]}
169                    break;
170                fi
171            done
172
173            if [[ -z $name ]]; then
174                comps=${ARGS[DNSSEC]}
175            else
176                comps=''
177            fi
178
179        elif __contains_word "$verb" ${VERBS[DNSOVERTLS]}; then
180            name=
181            for ((i++; i < COMP_CWORD; i++)); do
182                if __contains_word "${COMP_WORDS[i]}" ${ARGS[DNSOVERTLS]} &&
183                        ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
184                    name=${COMP_WORDS[i]}
185                    break;
186                fi
187            done
188
189            if [[ -z $name ]]; then
190                comps=${ARGS[DNSOVERTLS]}
191            else
192                comps=''
193            fi
194
195        else
196            comps=''
197        fi
198    fi
199
200    COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
201    return 0
202}
203
204complete -F _resolvectl resolvectl
205