about summary refs log tree commit diff
path: root/Completion/Linux/Command/_modutils
blob: 1205f2506209a36b95fbf4cf79c67820144395b9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#compdef lsmod modinfo modprobe rmmod insmod

_modules_caching_policy()
{
    # Rebuild if $modules_dir is newer than the cache, or every week.
    local -a oldp

    oldp=( "$1"(Nmw+0) )
    (( $#oldp )) || [[ $modules_dir -nt $1 ]]
}

_modutils() {
  local curcontext="$curcontext" expl state line modules modaliases ign args ret=1
  local -A opt_args
  local -a possible_modules_dirs=(
    # Mostly every other distro
    /lib/modules
    # NixOS & possibly Guix
    /run/booted-system/kernel-modules/lib/modules
  )
  local modules_dir tested_modules_dir
  for tested_modules_dir in "${possible_modules_dirs[@]}"; do
    if [[ -d "$tested_modules_dir" ]]; then
      modules_dir="$tested_modules_dir"
      break
    fi
  done

  local update_policy
  zstyle -s ":completion:*:*:$service:*" cache-policy update_policy
  if [[ -z "$update_policy" ]]; then
    zstyle ":completion:*:*:$service:*" cache-policy _modules_caching_policy
  fi

  args=(
    '(-)'{-V,--version}'[display version information]'
    '(-)'{-h,--help}'[display usage information]'
  )

  case "$service" in
    lsmod) _arguments -s "$args[@]" && return ;;

    modinfo)
      _arguments -s -C "$args[@]" \
	'(-)'{-k+,--set-version=}'[use modules from a different kernel version]:kernel_version:($(echo $modules_dir/*(/\:t)))' \
	{-b+,--basedir=}'[use specified directory as filesystem root]:path:_directories' \
	'1:module file:->all-modules' \
	+ '(field)' \
	{-a,--author}"[display the module's author]" \
	{-d,--description}"[display the module's description]" \
	{-l,--license}"[display the module's license]" \
	{-n,--filename}"[display the module's filename]" \
	{-p,--parameters}'[display the typed parameters that a module may support]' \
	{-F+,--field}"[display only selected module's information]:module_field:(alias author depends description filename intree license name parm sig_hashalgo sig_key signat signer srcversion vermagic)" \
	{-0,--null}'[use a null instead of newline in output]' && ret=0
    ;;

    modprobe)
      ign='-h --help -V --version -c --showconfig --show-config'
      _arguments -s -C "$args[@]" \
	"(-a --all $ign)"{-a,--all}'[load all matching modules]' \
	"(-n --show $ign)"{-n,--show}"[don't actually perform action]" \
	"(-q --quiet $ign)"{-q,--quiet}"[don't complain about insmod failures]" \
	"(-s --syslog $ign)"{-s,--syslog}'[report via syslog instead of stderr]' \
	"(-v --verbose $ign)"{-v,--verbose}'[print all commands as executed]' \
	'(-C --config)'{-C+,--config=}'[specify config file]:config file:_files' \
	"(-r --remove -a --all $ign)"{-r,--remove}'[remove module (stacks)]' \
	'--remove-dependencies[also remove modules depending on it]' \
	'(* -R --resolve-alias)'{-R,--resolve-alias}'[only lookup and print alias and exit]' \
	'--first-time[fail if module already inserted or removed]' \
	"(-a --all $ign)"{'-i[ignore install/remove commands in config file]','--ignore-install[ignore install commands in config file]','--ignore-remove[ignore remove commands in config file]'} \
	'(-b --use-blacklist)'{-b,--use-blacklist}'[apply blacklist to resolved alias]' \
	'(-f --force --force-modversions --force-vermagic)'{-f,--force}'[force module insertion or removal]' \
	"(-f --force)--force-modversion[ignore module's version]" \
	"(-f --force)--force-vermagic[ignore module's version magic]" \
	'(-D --show-depends)'{-D,--show-depends}'[only print module dependencies and exit]' \
	'(-)'{-c,--showconfig,--show-config}'[show current configuration]' \
	--{show,dump}'-modversions[dump module symbol version and exit]' \
	{-d+,--dirname=}'[use specified directory as filesystem root]:path:_directories' \
	{-S+,--set-version=}'[use modules from a different kernel version]:kernel_version:($(echo $modules_dir/*(/\:t)))' \
	'--show-exports[only print module exported symbol versions and exit]' \
	'(-n --dry-run --show)'{-n,--dry-run,--show}"[don't execute operations, just print]" \
	"(-c $ign)1:modules:->loadable-modules" \
	"(-c $ign)*:params:->params" && ret=0

      [[ -n $state && -n ${opt_args[(i)(-r|--remove)]} ]] && state=loaded-modules
    ;;

    rmmod)
      _arguments -s -C "$args[@]" \
	'(-f --force)'{-f,--force}'[allow modules that are in use to be removed]' \
	'(-s --syslog)'{-s,--syslog}'[send errors to syslog]' \
	'(-v --verbose)'{-v,--verbose}'[be verbose]' \
	'*:loaded module:->loaded-modules' && ret=0
      ;;

    insmod)
      _arguments "$args[@]" \
	  '1:module file:_files' \
	  '*:module parameters' && ret=0
    ;;
  esac

  case "$state" in
    loaded-modules|loadable-modules)
      if [[ -r /proc/modules ]]; then
	loaded_modules=(${${(f)"$(</proc/modules)"}%% *})
      # For compatibilty with old systems. Kernels nowadays provide
      # `/proc/modules` which is more reliable and faster for us.
      elif [[ -x /sbin/lsmod ]]; then
	loaded_modules=(${${(f)"$(_call_program loaded-modules /sbin/lsmod)"}[2,-1]%% *})
      else
	return 1
      fi

      if [[ $state = loaded-modules ]]; then
	_wanted modules expl 'loaded module' compadd -a loaded_modules && ret=0
	return ret
      fi
    ;&

    all-modules)
      local kver=${(v)opt_args[(i)(-S|-k|--set-version)]:-$(uname -r)}

      if [[ -z "$modules_dir" ]]; then
        return
      fi
      if _cache_invalid modules-$kver || ! _retrieve_cache modules-$kver;
      then
	modules=( $modules_dir/$kver/(*~(source|build))/**/*.(o|ko|ko.gz|ko.xz)(.:t:r:r) )
	modaliases=( ${${${(M)${(f)"$(<$modules_dir/$kver/modules.alias)"}:#alias*}#alias }%% *} )
	_store_cache modules-$kver modules modaliases
      fi

      if [[ -v opt_args[(i)(-R|--resolve-alias)] ]]; then
	_tags module-aliases
      else
	_tags files modules module-aliases
      fi
      if [[ $state = loadable-modules ]]; then
	modules=( ${modules:#(${(j:|:)~${=loaded_modules//_/-}})} )
      fi

      while _tags; do
	_requested modules expl module compadd -a modules && ret=0
	_requested module-aliases expl 'module alias' compadd -a modaliases && ret=0
	_requested files expl "module file"  _files -g '*.ko(-.)' && ret=0
	(( ret )) || break
      done
    ;;

    params)
      if compset -P 1 '*='; then
	_message -e value 'parameter value'
      else
	local params
	params=( ${${(M)${(f)"$(_call_program module-parameters modinfo "$words[2]" 2>/dev/null)"}:#parm:*}##parm:[[:space:]]##} )
	compset -S '=*'
	if (( $#params )); then
	  _values -S = -w 'module parameter' \
	      ${${${(M)params:#*(:bool|\(bool\))}/:/[}/(bool| \(bool\))/]} ${^${params:#*(:bool|\(bool\))}/:/[}"]:auto added argument: " && ret=0
	else
	  _message -e parameter "module doesn't take parameters"
	fi
      fi
    ;;
  esac

  return ret
}

_modutils "$@"