# fscrypt_bash_completion # # Copyright 2017 Google Inc. # Author: Henry-Joseph Audéoud (h.audeoud@gmail.com) # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. # Prefer completion script style COMPREPLY=($(...)) assignment. # shellcheck disable=SC2207 true # To apply shellcheck directive to all file # Output list of possible mount points _fscrypt_mountpoints() { # shellcheck disable=SC2016 fscrypt status 2>/dev/null | \ command awk 'substr($0, 1, 1) == "/" && $5 == "Yes" { print $1 }' } # Complete with all possible mountpoints _fscrypt_complete_mountpoint() { COMPREPLY=($(compgen -W "$(_fscrypt_mountpoints)" -- "${cur}")) } # Output list of possible policy or protector IDs # $1: the mount point on which policies are looked for. # $2: the section (policy or protector) to retrieve _fscrypt_status_section() { local section=${2^^} # shellcheck disable=SC2016 fscrypt status "$1" 2>/dev/null | \ command awk '/^[[:xdigit:]]{16}/ && section == "'"$section"'" { print $1; next; } { section = $1 }' } # Complete with policies or protectors _fscrypt_complete_policy_or_protector() { local status_section="$1" if [[ $cur = *:* ]]; then # Complete with IDs of the given mountpoint local mountpoint="${cur%:*}" id="${cur#*:}" COMPREPLY=($(compgen \ -W "$(_fscrypt_status_section "${mountpoint}" "${status_section}")" \ -- "${id}")) else # Complete with mountpoints, with colon and without ending space COMPREPLY=($(compgen -W "$(_fscrypt_mountpoints)" \ -- "${cur}" | sed s/\$/:/)) compopt -o nospace fi } # Complete with all arguments of that function _fscrypt_complete_word() { COMPREPLY=($(compgen -W "$*" -- "${cur}")) } # Complete with all arguments of that function, plus global options _fscrypt_complete_option() { local additional_opts=( "$@" ) # Add global options, always correct additional_opts+=( --verbose --quiet --help ) COMPREPLY=($(compgen -W "${additional_opts[*]}" -- "${cur}")) } _fscrypt() { # Initialize completion: compute some local variables to easily # detect what is written on the command line. -s is for splitting # long options on `=`, and -n is for splitting them also on `:` # (used in the protectors/policies `MOUNTPOINT:ID` forms). # # `split` is set by `_init_completion -s`, we must declare it local # even if we don't use it, not to modify the environment. # shellcheck disable=SC2034 local cur prev words cword split _init_completion -s -n : || return # Complete the options with argument here, if previous word were such # an option. It would be too difficult to check if they take place in # the correct command (such as `fscrypt status # --key ...`)—and that # is the command's job—so just complete them first. case $prev in --key) # Any file is accepted _filedir return ;; --name) # New value, nothing to complete return ;; --policy|--protector|--unlock-with) local p_or_p="${prev#--}" [[ $p_or_p = unlock-with ]] && p_or_p=protector _fscrypt_complete_policy_or_protector "${p_or_p}" return ;; --source) # Complete with keywords _fscrypt_complete_word \ pam_passphrase custom_passphrase raw_key return ;; --time) # It's a time, hard to complete a number… return ;; --user) # Complete with a user COMPREPLY=($(compgen -u -- "${cur}")) return ;; esac # Fetch positional arguments (i.e. subcommands) local positional positional=() local iword for ((iword = 1; iword < ${#words[@]} - 1; iword++)); do [[ ${words[iword - 1]} == --@(key|name|policy|protector|unlock-with|source|time|user) ]] \ && continue # Argument of previous option, skip [[ ${words[iword]} == -* ]] && continue # Option, skip positional+=("${words[iword]}") done # If completing the first positional, complete with all possible commands if [[ ${#positional[@]} == 0 ]]; then if [[ $cur == -* ]]; then _fscrypt_complete_option else _fscrypt_complete_word \ encrypt lock metadata purge setup status unlock fi return fi # Complete according to that provided case ${positional[0]-} in encrypt) # Directory or option if [[ $cur == -* ]]; then _fscrypt_complete_option \ --policy= --unlock-with= --protector= --source= \ --user= --name= --key= --skip-unlock --no-recovery else _filedir -d fi ;; lock) # Directory or option if [[ $cur == -* ]]; then _fscrypt_complete_option --user= --all-users else _filedir -d fi ;; purge) # Mountpoint or options if [[ $cur == -* ]]; then _fscrypt_complete_option --user= --force else _fscrypt_complete_mountpoint fi ;; setup) # Mountpoint or options if [[ $cur == -* ]]; then _fscrypt_complete_option --time= --force else _fscrypt_complete_mountpoint fi ;; status) # Directory (only global options for this command) if [[ $cur == -* ]]; then _fscrypt_complete_option else _filedir -d fi ;; unlock) # Directory or option if [[ $cur == -* ]]; then _fscrypt_complete_option --unlock-with= --user= --key= else _filedir -d fi ;; metadata) # This command has subcommands if [[ ${#positional[@]} = 1 ]]; then if [[ $cur = -* ]]; then _fscrypt_complete_option else # Still no subcommand, complete with them _fscrypt_complete_word \ add-protector-to-policy create change-passphrase \ destroy dump remove-protector-from-policy fi return fi # We have a subcommand, complete according to it case ${positional[1]-} in add-protector-to-policy) # Options only _fscrypt_complete_option \ --protector= --policy= --unlock-with= --key= ;; change-passphrase) # Options only _fscrypt_complete_option --protector= ;; destroy) # Mountpoint or option if [[ $cur == -* ]]; then _fscrypt_complete_option \ --protector= --policy= --force else _fscrypt_complete_mountpoint fi ;; dump) # Options only _fscrypt_complete_option --protector= --policy= ;; remove-protector-from-policy) # Options only _fscrypt_complete_option \ --protector= --policy= --force ;; create) # This subcommand has subsubcommands if [[ ${#positional[@]} = 2 ]]; then if [[ $cur = -* ]]; then _fscrypt_complete_option else # Still no subcommand, complete with them _fscrypt_complete_word protector policy fi return fi # We have a subsubcommand, complete according to it case ${positional[2]-} in policy) # Mountpoint or option if [[ $cur = -* ]]; then _fscrypt_complete_option --protector= --key= else _fscrypt_complete_mountpoint fi ;; protector) # Mountpoint or option if [[ $cur = -* ]]; then _fscrypt_complete_option \ --source= --name= --key= --user= else _fscrypt_complete_mountpoint fi ;; *) # Unrecognized subsubcommand… Suppose a new # unknown subsubcommand and complete with # global options only _fscrypt_complete_option ;; esac ;; *) # Unrecognized subcommand… Suppose a new unknown # subcommand and complete with global options only _fscrypt_complete_option ;; esac ;; *) # Unrecognized command… Suppose a new unknown command and # complete with global options only _fscrypt_complete_option ;; esac # When the sole offered completion is --*=, do not put a space after # the equal sign as we wait for the argument value. [[ ${#COMPREPLY[@]} == 1 ]] && [[ ${COMPREPLY[0]} == "--"*"=" ]] \ && compopt -o nospace } && complete -F _fscrypt fscrypt # ex: filetype=bash