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 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
|
#compdef btrfs
local curcontext="$curcontext" curstate state line expl grp cmd cont shift ret=1
local -a cmds_1 cmds_2 cmds_3 cmds_4 cmds_5 cmds_6 cmds_7 cmds_8 cmds_9 cmds_10
local -a groups args
groups=( subvolume filesystem device scrub balance inspect-internal property
quota qgroup replace rescue check restore send receive
help version )
cmds_1=( create delete list snapshot get-default set-default find-new show sync help )
cmds_2=( df du show sync defragment resize label usage help )
cmds_3=( add delete remove ready scan stats usage help )
cmds_4=( start cancel resume status help )
cmds_5=( start pause cancel resume status )
cmds_6=( dump-{super,tree} {inode,logical,subvolid}-resolve min-dev-size rootid tree-stats help )
cmds_7=( get set list )
cmds_8=( enable disable rescan help )
cmds_9=( assign remove create destroy show limit help )
cmds_10=( start status cancel help )
cmds_11=( chunk-recover fix-device-size super-recover zero-log create-control-device )
_arguments -C -A "-*" "$args[@]" \
'(- *)--help[print help information]' \
'(- *)--version[print version information]' \
'(-v --verbose -q --quiet --help --version)'{-v,--verbose}'[verbose output of operation]' \
'(-v --verbose -q --quiet --help --version)'{-q,--quiet}'[suppress all messages except errors]' \
'(--help --version)--format=[specify output format]:format:(text json)' \
'(--version)1: :->groups' \
'2: :->cmds' \
'*:: :->args' && ret=0
while (( $#state )); do
curstate=$state
shift state
case $curstate in
groups)
_wanted command-groups expl 'btrfs command group' compadd -a groups && ret=0
;;
cmds)
grp=${groups[(i)$words[2]*]}
(( grp && grp <= 16 )) || return 1
cont=${groups[grp]}
curcontext="${curcontext%:*:*}:$service-${cont}:"
if (( grp <= 11 )); then
_wanted commands expl command compadd -a cmds_$grp && ret=0
continue
fi
;&
args)
if [[ $curstate != cmds ]]; then
grp=${groups[(i)$words[1]*]}
(( grp && grp <= 16 )) || return 1
cont=${groups[grp]}
if (( grp <= 11 )); then
local group=cmds_$grp
local cmd=${${(P)group}[(i)$words[2]*]}
(( cmd )) || return 1
cont+=:${${(P)group}[cmd]}
else
shift=1
fi
curcontext="${curcontext%:*:*}:$service-${cont/:/-}:"
fi
args=( '(-)--help[print help information]' )
case ${cont} in
(balance|replace):start|device:(add|delete|remove)|filesystem:resize)
args+=(
"--enqueue[wait if there's another exclusive operation running, otherwise continue]"
)
;|
subvolume:create)
args+=(
'*-i[add the newly created subvolume to a qgroup]:qgroup'
'1:destination:->mounts'
)
;;
subvolume:delete)
args+=( '!-v' '!--verbose'
'(-c --commit-after -C --commit-each)'{-c,--commit-after}'[wait for transaction commit at the end of the operation]'
'(-c --commit-after -C --commit-each)'{-C,--commit-each}'[wait for transaction commit after deleting each subvolume]'
'(-i --subvolid)'{-i+,--subvolid=}'[specify id of subvolume to be removed]:subvolume id'
'1:subvolume:_files -/'
)
;;
subvolume:snapshot)
args+=(
'-r[readonly snapshot]'
'*-i[assign to qgroup]:qgroup: _message "qgroup"'
'1:source directory:_files -/'
'2:snapshot name or destination:_files -/'
)
;;
subvolume:list)
args+=(
'-p[include parent ID in output]'
'-a[include all subvolumes]'
'-c[include ogeneration of the subvolume]'
'-g[include generation of the subvolume]'
'-o[include only subvolumes below the path]'
'-u[include UUID of subvolume]'
'-q[include parent UUID of subvolume]'
'-R[include the uuid of the received snapshots]'
'-t[print results as a table]'
'-s[list only snapshot subvolumes]'
'-r[list only readonly subvolumes]'
'-d[list deleted subvolumes that are not yet cleaned]'
'-G[subvolume generation is more or less than]:gen: _guard "(|+|-)[0-9]#"'
'-C[subvolume ogeneration is more or less than]:ogen: _guard "(|+|-)[0-9]#"'
'--sort=-[list in order]:order:_sequence compadd - rootid gen ogen path'
'1:path:->mounts'
)
;;
subvolume:set-default) args+=( '1:id:_guard "[0-9]#" id' '2:path:->mounts' );;
subvolume:show)
args+=(
'(-r --rootid)'{-r,--rootid}'[rootid of the subvolume]'
'(-u --uuid)'{-u,--uuid}'[uuid of the subvolume]'
'1:subvolume path:_directories'
)
;|
subvolume:sync) args+=( '-s[sleep between checks]:delay (seconds) [1]' );;
subvolume:find-new) args+=( '1:subvol:_files -/' '2:lastgen: _message "last gen"' );;
(device|filesystem|qgroup|subvolume):(df|du|show|usage)|scrub:status)
args+=(
'--iec[use 1024 as a base]'
'--si[use 1000 as a base]'
)
;|
(device|filesystem):(df|usage)|subvolume:show)
args+=(
'(-b --raw)'{-b,--raw}'[output raw numbers in bytes]'
'(-h --human-readable -H)'{-h,--human-readable}'[output human friendly numbers, base 1024]'
'(-h --human-readable -H)-H[output human friendly numbers, base 1000]'
'(-k --kbytes)'{-k,--kbytes}'[show sizes in KiB, or kB with --si]'
'(-m --mbytes)'{-m,--mbytes}'[show sizes in MiB, or MB with --si]'
'(-g --gbytes)'{-g,--gbytes}'[show sizes in GiB, or GB with --si]'
'(-t --tbytes)'{-t,--tbytes}'[show sizes in TiB, or TB with --si]'
)
;|
(filesystem|qgroup|scrub):(du|show|status))
args+=(
'--raw[output raw numbers in bytes]'
'--human-readable[output human friendly numbers, base 1024]'
'--kbytes[show sizes in KiB, or kB with --si]'
'--mbytes[show sizes in MiB, or MB with --si]'
'--gbytes[show sizes in GiB, or GB with --si]'
'--tbytes[show sizes in TiB, or TB with --si]'
)
;|
filesystem:resize) args+=( '1: :_numbers -u bytes -N size K M G T P E' '2:path:->mounts' );;
filesystem:defragment)
args+=( '!-v'
'-r[defragment files recursively]'
'-c+[compress files while defragmenting]::compression algorithm:(zlib lzo zstd)'
'-r[defragment files recursively]'
'-f[flush after defragmenting]'
'-s[start position]: :_numbers -u bytes -d "beginning of file" offset K M G T P E'
'-l[defragment limited number of bytes]: :_numbers -u bytes length K M G T P E'
'-t[defragment only extents up to a certain size]: :_numbers -u bytes -d 32M "maximum extent size" K M G T P E'
'*:file:_files'
)
;;
filesystem:du) args+=( '(-s --summarize)'{-s,--summarize}'[display only a total for each argument]' );;
filesystem:label) args+=( '1:device:_files -g "*(-%)"' '2:new label' );;
filesystem:show)
args+=(
'(1 -)'{-d,--all-devices}'[scan all devices in /dev]'
'(1 -)'{-m,--mounted}'[show only mounted filesystems]'
'--raw[output raw numbers in bytes]'
'--human-readable[output human friendly numbers, base 1024]'
'1: :_guard "^-*" uuid or label'
)
;;
filesystem:usage) args+=( '-T[show data in tabular format]' );;
device:(add|delete|ready|remove))
args+=(
'1:device:_files -g "*(-%)"'
'2:path:->mounts'
)
[[ ${${(P)group}[cmd]} == add ]] &&
args+=(
{-K,--nodiscard}"[don't perform whole device TRIM]"
{-f,--force}'[force overwrite of existing filesystem]'
)
;;
device:scan)
args+=(
'(-)'{-u,--forget}'[unregister all stale devices or a given device]'
'(1 -)'{-d,--all-devices}'[enumerate and register all devices]'
'1:device:_files -g "*(-%)"'
)
;;
device:stats)
args+=(
'(-c --check)'{-c,--check}'[return non-zero if any stat counter is not zero]'
'(-z --reset)'{-z,--reset}'[reset stats when done]'
"1:device or mountpoint:_files -g '*(-%,/)'"
)
;;
device:ready) args+=( '1:device: _files -g "*(-%)"' );;
scrub:(start|resume))
args+=( '!-q'
"-B[don't background and print statistics at end]"
'-d[print separate statistics for each device]'
'-r[read only mode]'
'-R[raw print mode]'
'-c[set ioprio class]:class:(( 0\:none 1\:realtime 2\:best-effort 3\:idle))'
'-n[set ioprio classdata]:classdata:(0 1 2 3 4 5 6 7)'
'1:path or device:_files'
)
[[ ${${(P)group}[cmd]} == start ]] && args+=(
'-f[force starting new scrub even if a scrub is already running]'
)
;;
scrub:cancel) args+=( '1: : _guard "^-*" "path or device"' );;
scrub:status)
args+=(
'-d[separate statistics for each device]'
'-R[print raw stats]'
'1:path or device:_files'
)
;;
balance:start)
args+=( '!-v' '!--verbose'
'(-m -s)-d+[act on data chunks]:filter:->filters'
'(-d -s)-m+[act on metadata chunks]:filter:->filters'
'(-d -m)-s+[act on system chunks (only under -f)]:filters:->filters'
'-f[force a reduction of metadata integrity]'
"--full-balance[don't print warning and don't delay start]"
'(--background --bg)'{--background,--bg}'[run balance operation asynchronously in the background]'
'1:path:_files -/'
)
;;
balance:status) args+=( '!-v' '!--verbose' '1:path:_files -/' );;
balance:(pause|cancel|resume)) args+=( '1:path:_files -/' );;
property:set) args+=( '3:value' );&
property:get) args+=( '2:property:(ro label compression)' );&
property:list)
args+=(
'-t[specify object type]:object type:(subvol filesystem inode device)'
'1: : _guard "^-*" object'
)
;;
quota:(enable|disable)) args+=( '1:path:_files -/' );;
quota:rescan)
args+=(
'-s[show status of currently running rescan]'
'-w[wait for rescan to finish]'
'1:path:_files -/'
)
;;
qgroup:(assign|remove))
args+=(
\!--rescan
"--no-rescan[don't do a rescan, even if the quotas may become inconsistent]"
'1:source path:_files -/'
'2:destination path:_files -/'
'3:path:_files -/'
)
;;
qgroup:(create|destroy)) args+=( '1:qgroupid:' '2:path:_files -/' );;
qgroup:show)
args+=(
'-p[print parent qgroup id]'
'-c[print child qgroup id]'
'-r[print max referenced size of qgroup]'
'-e[print max exclusive size of qgroup]'
'-F[list impacted qgroups \(include ancestral qgroups\)]'
'-f[list impacted qgroups \(exclude ancestral qgroups\)]'
'--sort=-[sort qgroups]:sort:_values -s , sort \
qgroupid rfer excl max_rfer max_excl'
'--sync[do filesystem sync before getting information]'
'1:path:_files -/'
)
;;
qgroup:limit)
args+=(
'-c[limit amount of data after compression]'
'-e[limit space exclusively to qgroup]'
': :_guard "^-*" "size or none"'
':qgroup id or path:_files -/'
':path:_files -/'
)
;;
replace:start)
args+=(
'-r[read from specified source device only]:srcdev:_files'
'-f[force overwriting of target]'
"-B[don't background]"
':srcdev or devid:_files'
':target:_files'
':path:->mounts'
)
;;
replace:status) args+=( '-1[print once rather than continuously]' ':path:->mounts' );;
replace:cancel) args+=( ':path:->mounts' );;
inspect*:dump-tree)
args+=(
'(-e --extents)'{-e,--extents}'[print only extent info: extent and device trees]'
'(-d --device)'{-d,--device}'[print only device info: tree root, chunk and device trees]'
'(-r --roots)'{-r,--roots}'[print only short root node info]'
'(-R --backups)'{-R,--backups}'[same as --roots plus print backup root info]'
'(-u --uuid)'{-u,--uuid}'[print only the uuid tree]'
\*{-b,--block}'[print info from the specified block only]:block number'
'(-t --tree)'{-t,--tree}'[print only tree with the given id (string or number)]:tree id'
'--follow[use with -b, to show all children tree blocks of the block]'
"--noscan[don't scan devices from the filesystem, use only the listed ones]"
'!(--dfs)--bfs'
'--dfs[depth-first traversal of the trees]'
'--hide-names[hide filenames/subvolume/xattrs and other name references]'
'--csum-headers[print node checksums stored in headers (metadata)]'
'--csum-items[print checksums stored in checksum items (data)]'
)
;;
inspect*:dump-super)
args+=( \!-s:byte\ number '!-i:super:(0 1 2)'
'(-f --full)'{-f,--full}'[print full superblock information, backup roots etc.]'
'(-a --all)'{-a,--all}'[print information about all superblocks]'
'(-s --super)'{-s,--super}'[specify which copy to print out]:super:(0 1 2)'
'(-F --force)'{-F,--force}'[attempt to dump superblocks with bad magic]'
'--bytenr[specify alternate superblock offset]:offset'
)
;;
inspect*:inode*) args+=( '!-v' '1:inode:_files' '2:path:_files -/' );;
inspect*:subvol*) args+=( '!-v' '1:subvolid:_guard "[0-9]#" subvolume id' '2:path:_files -/' );;
inspect*:logical*)
args+=( '!-v'
'-P[skip the path resolving and print the inodes instead]'
'-o[ignore offsets when matching references]'
'-s[specify buffer size]:buffer size [4096]'
'1:logical address:_files'
'2:filesystem path:_files -/'
)
;;
inspect*:min*) args+=( '--id[specify the device id to query]:device id [1]' );;
inspect*:rootid) args+=( '1:path:_files -/' );;
inspect*:tree*) args+=( '-b[print raw numbers in bytes]' );;
rescue:(chunk|super)-recover)
args+=( '!-v'
'-y[assume yes to every question]'
'1:device:_files'
)
[[ ${${(P)group}[cmd]} == chunk-recover ]] && args+=('(-)-h[display help]')
;;
subvolume:get-default) ;&
*:sync) ;&
*:df) args+=( '1:path:->mounts' );;
check)
args+=( \!--readonly
'(-s --super)'{-s,--super}'[specify superblock]:superblock'
'(-b --backup)'{-b,--backup}'[use the backup root copy]'
'(-r --tree-root)'{-r,--tree-root}'[use specified byte number for the tree root]:byte number'
'--chunk-root[ use the given offset for the chunk tree root]:byte offset'
'--repair[try to repair the filesystem]'
'--force[skip mount checks, repair is not possible]'
'--mode[select memory/IO trade-off]:mode:(original lowmem)'
'--init-csum-tree[create a new CRC tree]'
'--init-extent-tree[create a new extent tree]'
'--clear-space-cache[clear space cache for v1 or v2]:version:(v1 v2)'
'--check-data-csum[verify checksums of data blocks]'
'(-Q --qgroup-report)'{-Q,--qgroup-report}'[verify qgroup accounting and compare against filesystem accounting]'
'(-E --subvol-extents)'{-E,--subvol-extents}'[show extent state for the given subvolume]:subvolume id'
'(-p --progress)'{-p,--progress}'[indicate progress at various checking phases]'
'1:path:_files -/'
)
;;
restore)
args+=( '!-v' '!--verbose'
'(-s --snapshots)'{-s,--snapshots}'[get snapshots]'
'(-x --xattr)'{-x,--xattr}'[restore extended attributes]'
'(-m --metadata)'{-m,--metadata}'[restore owner, mode and times]'
'(-S --symlink)'{-S,--symlink}'[restore symbolic links]'
'(-i --ignore-errors)'{-i,--ignore-errors}'[ignore errors]'
'(-o --overwrite)'{-o,--overwrite}'[overwrite directories and files]'
'-t[specify tree location]:tree root'
'-f[specify filesystem location]:byte offset'
'(-u --super)'{-u,--super}'[use specified superblock mirror]:mirror:(0 1 2)'
'(-r --root)'{-r,--root}'[specify root objectid]:root id'
'-d[find directory]'
'(-l --list-roots)'{-l,--list-roots}'[list tree roots]'
'(-D --dry-run)'{-D,--dry-run}'[dry run (only list files that would be recovered)]'
'--path-regex[restore only filenames matching regex]:regex'
'-c[ignore case (--path-regex only)]'
'1:device:_files -/'
'2:path:_files -/'
)
;;
send|receive)
args+=( '!-q' '!--quiet' )
;|
send)
args+=( '!-v'
'-e[if sending multiple subvolumes at once, use the new format]'
'-p[send incremental stream]:parent:_files -/'
'*-c[use snapshot as clone source]:clone:_files -/'
'-f[specify output file]:file:_files'
'--no-data[send in NO_FILE_DATA mode]'
'1:subvolume:_files -/'
)
;;
receive)
args+=( '!-v'
'-f[input file]:file: _files'
'-e[terminate after <end cmd>]'
'(-C --chroot)'{-C,--chroot}'[confine the process to destination path using chroot(1)]'
'(-E --max-errors)'{-E,--max-errors}'[terminate as soon as specified number of errors occur]:errors [1]'
'(--dump)-m[specify root mount point of the destination filesystem]:mount point:_directories'
'(-m)--dump[dump stream metadata, one line per operation]'
'1:mount:->mounts'
)
;;
h(|e(|l(|p)))) args+=(
'--full[display detailed help on every command]'
'--box[show list of built-in tools (busybox style)]'
)
;;
*) args+=( '*: :_default' );; # fallback for unknown subcommands
esac
if ! (( shift )); then
shift words
(( CURRENT-- ))
fi
_arguments -C "$args[@]" && ret=0
;;
mounts)
_wanted mount-points expl 'mount point' compadd \
${${${(M)${(f)"$(</etc/mtab)"}:#*btrfs*}#* }%% *} && ret=0
;;
filters)
state=()
_values -s , filter \
'profiles[balance only block groups in given replication profiles]:profile:->profiles' \
'usage[balance block groups with usage below percentage]:percentage' \
'devid[limit by device ID]:device ID' \
'drange[balance block groups overlapping byte range]:range' \
'vrange[balance block groups overlapping byte range in virtual address space]:range' \
'convert[convert block groups to given profile]:profile:->profiles' \
'soft[leave chunks that already have target profile]' && ret=0
state=( $state )
;;
profiles)
compset -P '*\|'
_values -s ',' profile raid0 raid1 raid5 raid6 raid10 dup single && ret=0
;;
esac
done
return ret
|