#compdef firejail _all_firejails() { local -a _all_firejails_list for jail in ${(f)"$(_call_program modules_tag "firejail --list 2> /dev/null | cut -d: -f1")"}; do _all_firejails_list+=${jail%% *} done _describe 'firejails list' _all_firejails_list } _all_cpus() { _cpu_count=$(getconf _NPROCESSORS_ONLN) for i in {0..$((_cpu_count-1))} ; do print $i done } _profiles() { print $1/*.profile | sed -E "s;^$1/;;g;s;\.profile$;;g;" } _profiles_with_ext() { print $1/*.profile } _all_profiles() { _values 'profiles' $(_profiles _SYSCONFDIR_/firejail) $(_profiles $HOME/.config/firejail) $(_profiles_with_ext .) } _firejail_args=( '*::arguments:_normal' '(--profile)'{--profile=,--profile=}'[use a custom profile]: :_all_profiles' '--caps[enable default Linux capabilities filter]' '(--caps.drop)'{--caps.drop=,--caps.drop=}'[drop capabilities: all|cap1,cap2,...]: :->caps_drop' '(--caps.keep)'{--caps.keep=,--caps.keep=}'[keep capabilities: cap1,cap2,...]: :->caps_keep' '(--caps.print)'{--caps.print=,--caps.print=}'[print the caps filter name|pid]:firejail:_all_firejails' '--allow-debuggers[allow tools such as strace and gdb inside the sandbox]' '(--debug)'{--debug,--debug}'[print sandbox debug messages]' '--debug-blacklists[debug blacklisting]' '--debug-caps[print all recognized capabilities]' '--debug-errnos[print all recognized error numbers]' '--debug-private-lib[debug for --private-lib option]' '--debug-protocols[print all recognized protocols]' '--debug-syscalls[print all recognized system calls]' '--debug-syscalls32[print all recognized 32 bit system calls]' '--debug-whitelists[debug whitelisting]' # Ignore that you can do -? too as it's the only short option '(--help)'{--help,--help}'[this help screen]' '--allusers[all user home directories are visible inside the sandbox]' '--appimage[sandbox an AppImage application]' '--private[temporary home directory]' '(--private)'{--private=,--private=}'[use directory as user home]: : _files -/' '--seccomp[enable seccomp filter and apply the default blacklist]' '(--seccomp=)'{--seccomp=,--seccomp=}'[enable seccomp filter, blacklist the default syscall list and the syscalls specified by the command]:' '(--seccomp.print)'{--seccomp.print=,--seccomp.print=}'[print the seccomp filter for the sandbox identified by name|pid]: : _all_firejails' '--seccomp.block-secondary[build only the native architecture filters]' '(--seccomp.drop)'{--seccomp.drop=,--seccomp.drop=}'[enable seccomp filter, and blacklist the syscalls specified by the command]: :' '(--seccomp.keep)'{--seccomp.keep=,--seccomp.keep=}'[enable seccomp filter, and whitelist the syscalls specified by the command]: :' '(--seccomp.32.drop)'{--seccomp.32.drop=,--seccomp.32.drop=}'[enable seccomp filter, and blacklist the 32 bit syscalls specified by the command]: :' '(--seccomp.32.keep)'{--seccomp.32.keep=,--seccomp.32.keep=}'[enable seccomp filter, and whitelist the 32 bit syscalls specified by the command]: :' '(--seccomp-error-action)'{--seccomp-error-action=,--seccomp-error-action=}'[change error code, kill process or log the attempt]: :(ERRNO kill log)' '--memory-deny-write-execute[seccomp filter to block attempts to create memory mappings that are both writable and executable]' '*'{--blacklist=,--blacklist=}'[blacklist directory or file]: : _files' '--writable-etc[/etc directory is mounted read-write]' '--writable-run-user[allow access to /run/user/$UID/systemd and /run/user/$UID/gnupg]' '--writable-var[/var directory is mounted read-write]' '--writable-var-log[use the real /var/log directory, not a clone]' '--build[build a whitelisted profile for the application and print it on stdout]' '(--build)'{--build=,--build=}'[build a whitelisted profile for the application and save it]: : _files' '(--fs.print)'{--fs.print=,--fs.print=}'[print the filesystem log name|pid]: : _all_firejails' '(--join)'{--join=,--join=}'[join the sandbox name|pid]: : _all_firejails' '(--join-filesystem)'{--join-filesystem=,--join-filesystem=}'[join the mount namespace name|pid]: : _all_firejails' '(--profile.print)'{--profile.print=,--profile.print=}'[print the name of profile file name|pid]: : _all_firejails' '(--protocol.print)'{--protocol.print=,--protocol.print=}'[print the protocol filter name|pid]: : _all_firejails' '(--shutdown)'{--shutdown=,--shutdown=}'[shutdown the sandbox identified by name|pid]: : _all_firejails' '(--cat)'{--cat=,--cat=}'[print content of file from sandbox container name|pid]: : _all_firejails' '(--cpu.print)'{--cpu.print=,--cpu.print=}'[print the cpus in use name|pid]: : _all_firejails' '--list[list all sandboxes]' '(--dns)'{--dns=,--dns=}'[set DNS server]: :' '(--protocol)'{--protocol=,--protocol=}'[enable protocol filter]: :' '(--join-or-start)'{--join-or-start=,--join-or-start=}'[join the sandbox or start a new one name|pid]: : _all_firejails' '(--hosts-file)'{--hosts-file=,--hosts-file=}'[use file as /etc/hosts]: : _files' '--shell=none[run the program directly without a user shell]' '(--shell)'{--shell=,--shell=}'[set default user shell]: : _files -g "*(*)"' '(--output)'{--output=,--output=}'[stdout logging and log rotation]: : _files' '(--output-stderr)'{--output-stderr=,--output-stderr=}'[stdout and stderr logging and log rotation]: : _files' '--no3d[disable 3D hardware acceleration]' '--nodvd[disable DVD and audio CD devices]' '--nogroups[disable supplementary groups]' '--nonewprivs[sets the NO_NEW_PRIVS prctl]' '--noprofile[do not use a security profile]' '(--noexec)'{--noexec=,--noexec=}'[remount the file or directory noexec nosuid and nodev]: : _files' '--ipc-namespace[enable a new IPC namespace]' '--keep-dev-shm[/dev/shm directory is untouched (even with --private-dev)]' '--keep-var-tmp[/var/tmp directory is untouched]' '--top[monitor the most CPU-intensive sandboxes]' '--trace[trace open, access and connect system calls]' '--tracelog[add a syslog message for every access to files or directories blacklisted by the security profile]' '--tree[print a tree of all sandboxed processes]' '(--cpu)'{--cpu=,--cpu=}'[set cpu affinity]: :->cpus' '--private-dev[create a new /dev directory with a small number of common device files]' '--private-tmp[mount a tmpfs on top of /tmp directory]' '--private-cwd[do not inherit working directory inside jail]' '(--private-cwd)'{--private-cwd=,--private-cwd=}'[set working directory inside jail]: : _files -/' '*'{--read-only=,--read-only=}'[set directory or file read-only]: : _files' '*'{--read-write=,--read-write=}'[set directory or file read-write]: : _files' '(--tmpfs)'{--tmpfs=,--tmpfs=}'[mount a tmpfs filesystem on directory dirname]: : _files -/' '(--private-etc)'{--private-etc=,--private-etc=}'[build a new /etc in a temporary filesystem, and copy the files and directories in the list]: : _files' "--deterministic-exit-code[always exit with first child's status code]" '--machine-id[preserve /etc/machine-id]' # Sample values as I don't think # many would enjoy getting a list from -20..20 '(--nice)'{--nice=,--nice=}'[set nice value]: :(1 10 15 20)' # Should be _files, a comma and files or files -/ '*'{--bind=,--bind=}'[mount-bind dirname1/filename1 on top of dirname2/filename2]: :(file1,file2 dir1,dir2)' '--audit[audit the sandbox]' '(--audit)'{--audit=,--audit=}'[audit the sandbox with a test-program]: :' '(--cgroup)'{--cgroup=,--cgroup=}'[place the sandbox in the specified control group]: :' '*'{--env=,--env=}'[set environment variable]: :' '(--hostname)'{--hostname=,--hostname=}'[set sandbox hostname]: :' '(--ignore)'{--ignore=,--ignore=}'[ignore command in profile files]: :' '(--name)'{--name=,--name=}'[set sandbox name]: :' '(--rlimit-as)'{--rlimit-as=,--rlimit-as=}"[set the maximum size of the process's virtual memory (address space) in bytes]: :" '(--rlimit-cpu)'{--rlimit-cpu=,--rlimit-cpu=}'[set the maximum CPU time in seconds]: :' '(--rlimit-fsize)'{--rlimit-fsize=,--rlimit-fsize=}'[set the maximum file size that can be created by a process]: :' '(--rlimit-nofile)'{--rlimit-nofile=,--rlimit-nofile=}'[set the maximum number of files that can be opened by a process]: :' '(--rlimit-nproc)'{--rlimit-nproc=,--rlimit-nproc=}'[set the maximum number of processes that can be created for the real user ID of the calling process]: :' '(--rlimit-sigpending)'{--rlimit-sigpending=,--rlimit-sigpending=}'[set the maximum number of pending signals for a process]: :' '*'{--rmenv=,--rmenv=}'[remove environment variable in the new sandbox]: :' '(--timeout)'{--timeout=,--timeout=}'[kill the sandbox automatically after the time has elapsed]: :(hh\:mm\:ss)' "--quiet[turn off Firejail's output.]" '--version[print program version and exit]' #ifdef HAVE_APPARMOR '--apparmor[enable AppArmor confinement]' '(--apparmor.print=)'{--apparmor.print=,--apparmor.print=}'[print apparmor status name|pid]:firejail:_all_firejails' #endif #ifdef HAVE_CHROOT '(--chroot)'{--chroot=,--chroot=}'[chroot into directory]: : _files -/' #endif #ifdef HAVE_FILE_TRANSFER '(--get)'{--get=,--get=}'[get a file from sandbox container name|pid]: : _all_firejails' # --put=name|pid src-filename dest-filename - put a file in sandbox container. '(--put)'{--put=,--put=}'[put a file in sandbox container]: :' '(--ls)'{--ls=,--ls=}'[list files in sandbox container name|pid]: : _all_firejails' #endif #ifdef HAVE_NETWORK # '--net=none[enable a new, unconnected network namespace]' '(--net)'{--net=,--net=}'[enable network namespaces and connect to this bridge or Ethernet interface (or none to disable)]: :->net_or_none' '(--net.print)'{--net.print=,--net.print=}'[print network interface configuration name|pid]: : _all_firejails' '(--netfilter.print)'{--netfilter.print=,--netfilter.print=}'[print the firewall name|pid]: : _all_firejails' '(--netfilter6.print)'{--netfilter6.print=,--netfilter6.print=}'[print the IPv6 firewall name|pid]: : _all_firejails' '--netstats[monitor network statistics]' '(--netmask)'{--netmask=,--netmask=}'[define a network mask when dealing with unconfigured parrent interfaces]: :' '(--netns)'{--netns=,--netns=}'[Run the program in a named, persistent network namespace]: :' '(--netfilter)'{--netfilter=,--netfilter=}'[enable firewall]: :' '(--netfilter6)'{--netfilter6=,--netfilter6=}'[enable IPv6 firewall]: :' '(--veth-name)'{--veth-name=,--veth-name=}'[use this name for the interface connected to the bridge]: :' '(--join-network)'{--join-network=,--join-network=}'[join the network namespace name|pid]: : _all_firejails' '(--defaultgw)'{--defaultgw=,--defaultgw=}'[configure default gateway]: :' '(--ip)'{--ip=,--ip=}'[set interface IP address none|dhcp|ADDRESS]: :(none dhcp)' '(--dns.print)'{--dns.print=,--dns.print=}'[print DNS configuration name|pid]: : _all_firejails' '(--interface)'{--interface=,--interface=}'[move interface in sandbox]: :' '(--ip6)'{--ip6=,--ip6=}'[set interface IPv6 address or use dhcp via dhclient]: :(dhcp)' '(--iprange)'{--iprange=,--iprange=}'[configure an IP address in this range]: :' '(--mac)'{--mac=,--mac=}'[set interface MAC address]: :(xx\:xx\:xx\:xx\:xx\:xx)' '(--mtu)'{--mtu=,--mtu=}'[set interface MTU]: :' '--scan[ARP-scan all the networks from inside a network namespace]' '(--bandwidth)'{--bandwidth=,--bandwidth=}'[set bandwidth limits name|pid]: : _all_firejails' #endif #ifdef HAVE_X11 '--x11[enable X11 sandboxing. The software checks first if Xpra is installed, then it checks if Xephyr is installed. If all fails, it will attempt to use X11 security extension]' '(--x11)'{--x11=,--x11=}'[disable or enable specific X11 server]: :(none xephyr xorg xpra xvfb)' '(--xephyr-screen)'{--xephyr-screen=,--xephyr-screen=}'[set screen size for --x11=xephyr]: :(WIDTHxHEIGHT)' #endif #ifdef HAVE_USERNS '--noroot[install a user namespace with only the current user]' #endif '--nosound[disable sound system]' '--noautopulse[disable automatic ~/.config/pulse init]' '--novideo[disable video devices]' '--nou2f[disable U2F devices]' #ifdef HAVE_OVERLAYFS '--overlay[mount a filesystem overlay on top of the current filesystem]' '(--overlay-named)'{--overlay-named=,--overlay-named=}'[mount a filesystem overlay on top of the current filesystem, and store it in name directory]: : _files -/' '--overlay-tmpfs[mount a temporary filesystem overlay on top of the current filesystem]' '--overlay-clean[clean all overlays stored in $HOME/.firejail directory]' #endif #ifdef HAVE_WHITELIST '(--nowhitelist)'{--nowhitelist=,--nowhitelist=}'[disable whitelist for file or directory]: : _files' '*'{--whitelist=,--whitelist=}'[whitelist directory or file]: : _files' #endif '(--noblacklist)'{--noblacklist=,--noblacklist=}'[disable blacklist for file or directory]: : _files' #ifdef HAVE_DBUSPROXY '(--dbus-system)'{--dbus-system=,--dbus-system=}'[set system DBus access policy or none]: :' '(--dbus-system.broadcast)'{--dbus-system.broadcast=,--dbus-system.broadcast=}'[allow signals on the system DBus according to rule]: :' '(--dbus-system.call)'{--dbus-system.call=,--dbus-system.call=}'[allow calls on the system DBus according to rule]: :' '(--dbus-system.own)'{--dbus-system.own=,--dbus-system.own=}'[allow ownership of name on the system DBus]: :' '(--dbus-system.see)'{--dbus-system.see=,--dbus-system.see=}'[allow seeing name on the system DBus]: :' '(--dbus-system.talk)'{--dbus-system.talk=,--dbus-system.talk=}'[allow talking to name on the system DBus]: :' '(--dbus-user)'{--dbus-user=,--dbus-user=}'[set session DBus access policy or none]: :' '(--dbus-user.broadcast)'{--dbus-user.broadcast=,--dbus-user.broadcast=}'[allow signals on the session DBus according to rule]: :' '(--dbus-user.call)'{--dbus-user.call=,--dbus-user.call=}'[allow calls on the session DBus according to rule]: :' '(--dbus-user.see)'{--dbus-user.see=,--dbus-user.see=}'[allow seeing name on the session DBus]: :' '(--dbus-user.talk)'{--dbus-user.talk=,--dbus-user.talk=}'[allow talking to name on the session DBus]: :' '(--dbus-log)'{--dbus-log=,--dbus-log=}'[set DBus log file location]: : _files' '(--dbus-system)'{--dbus-system=,--dbus-system=}'[set system DBus access policy]: :(filter none)' '--dbus-user.log[turn on logging for the user DBus]' '(--dbus-user.own)'{--dbus-user.own=,--dbus-user.own=}'[allow ownership of name on the session DBus]: :' '--dbus-system.log[turn on logging for the system DBus]' '--nodbus[disable D-Bus access]' #endif #ifdef HAVE_PRIVATE_HOME '(--private-home)'{--private-home=,--private-home=}'[build a new user home in a temporary filesystem, and copy the files and directories in the list in the new home]: :' #endif '(--private-bin)'{--private-bin=,--private-bin=}'[build a new /bin in a temporary filesystem, and copy the programs in the list]: :' '(--private-opt)'{--private-opt=,--private-opt=}'[build a new /opt in a temporary filesystem]: :' '(--private-srv)'{--private-srv=,--private-srv=}'[build a new /srv in a temporary filesystem]: :' #ifdef HAVE_USERTMPFS '--private-cache[temporary ~/.cache directory]' #endif #ifdef HAVE_FIRETUNNEL '(--tunnel)'{--tunnel=,--tunnel=}'[connect the sandbox to a tunnel created by firetunnel utility]: :' #endif ) _firejail() { _arguments -S $_firejail_args case "$state" in caps_drop) local caps_and_all=(all $(firejail --debug-caps | awk '/[0-9]+\s*- /{print $3}')) _values -s "," 'caps_drop' $caps_and_all ;; caps_keep) local caps=($(firejail --debug-caps | awk '/[0-9]+\s*- /{print $3}')) _values -s "," 'caps_keep' $caps ;; cpus) _values -s "," 'cpus' $(_all_cpus) ;; net_or_none) local netdevs=($(ip link | awk '{print $2}' | grep '^.*:$' | tr -d ':')) local net_and_none=(none $netdevs) _values 'net' $net_and_none ;; esac }