#compdef setpriv

__setpriv_prctl_securebits_set_elements() {
  local -a expl
  local -a bits

  bits=(
    noroot noroot_locked
    no_setuid_fixup no_setuid_fixup_locked
    keep_caps_locked
  )

  if ! compset -P '[+-]'; then
    _description minus-or-plus expl "-/+"
    compadd "${(@)expl}" -qS '' {+,-}
    return
  fi

  _description minus-plus-securebits expl "prctl securebit"
  compadd "${(@)expl}" "$@" -a - bits
}

__setpriv_numbered_caps() {
  # The cap_ prefix.
  # We override the suffix from _sequence with -S '' to stay adjacent
  # to the following number.
  if ! compset -P cap_; then
    compadd -S '' "$@" -n - cap_
    return
  fi
  # A capability number; i.e. a non-negative integer.
  # We can't complete integers, so no matches.
  if ! compset -P '[0-9]##'; then
    local -a expl
    _description -x numbers expl "capability number"
    compadd -S '' "${(@)expl}" -n -
    return
  fi
  # The numbered cap expression is complete.
  compadd "$@" -n - ''
}

__setpriv_cap_set_elements() {
  # '-' or '+', followed by one of the following:
  # - a capability name
  # - the word 'all'
  # - 'cap_[0-9]+' (to specify unknown capabilities).
  if ! compset -P '[+-]'; then
    local -a expl
    _description minus-or-plus expl "-/+"
    compadd "${(@)expl}" -qS '' + -
    return
  fi

  # We pass through compadd options generated by _sequence.
  local -a sequence_argv=( "$@" )

  _alternative -O sequence_argv \
    'special-words:drop/obtain all caps:(all)' \
    'capabilities: :_capabilities' \
    'numbered-capabilities:cap_N:__setpriv_numbered_caps' \
    #
}

__setpriv_death_signals() {
  _alternative \
    'special-words:keep or clear:(keep clear)' \
    'signals:UNIX signal:_signals' \
    #
}

local curcontext="$curcontext" state state_descr line
typeset -A opt_args

_arguments -C -S -s \
  '(- : *)'{-h,--help}'[print help and exit]' \
  '(- : *)'{-V,--version}'[print version information and exit]' \
  '(- : *)'{-d,--dump}'[display the current privilege state]:*: :->option-dump' \
  '(--groups --init-groups --keep-groups)--clear-groups[clear supplementary groups]' \
  '(--clear-groups --init-groups --keep-groups)--groups[set supplementary groups]: : _sequence _groups' \
  '(--clear-groups --groups --init-groups)--keep-groups[preserve supplementary groups]' \
  '(--clear-groups --groups --keep-groups)--init-groups[initialize supplementary groups]' \
  '--inh-caps[set inheritable caps]: : _sequence __setpriv_cap_set_elements' \
  '--ambient-caps[set ambient caps]: : _sequence __setpriv_cap_set_elements' \
  '--bounding-set[set the cap bounding set]: : _sequence __setpriv_cap_set_elements' \
  '(- : *)--list-caps[list all known capabilities]' \
  '--no-new-privs[set NO_NEW_PRIVS]' \
  '--rgid[set real UNIX group id]:UNIX group:_groups' \
  '--egid[set effective UNIX group id]:UNIX group:_groups' \
  '--regid[set real and effective UNIX group id]:UNIX group:_groups' \
  '--ruid[set real UNIX user id]:UNIX user:_users' \
  '--euid[set effective UNIX user id]:UNIX user:_users' \
  '--reuid[set real and effective UNIX user id]:UNIX user:_users' \
  '--securebits[set "process securebits"]: : _sequence __setpriv_prctl_securebits_set_elements' \
  '--pdeathsig[keep, clear, or set parent death signal]: : __setpriv_death_signals' \
  '--selinux-label[request a selinux label]:SELinux label:_selinux_contexts' \
  '--apparmor-profile[request an apparmor profile]:AppArmor profiles: ' \
  '--reset-env[set environment as for a classic login shell]' \
  '*:::command: _normal -p $service' \
  && return 0

case $state in
  option-dump)
    _arguments -S '*'{-d,--dump}'[display the current privilege state]'
  ;;
  *) ;;
esac
