4 # The contents of this file are subject to the terms of the
5 # Common Development and Distribution License (the "License").
6 # You may not use this file except in compliance with the License.
8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 # or http://www.opensolaris.org/os/licensing.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
13 # When distributing Covered Code, include this CDDL HEADER in each
14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 # If applicable, add the following below this CDDL HEADER, with the
16 # fields enclosed by brackets "[]" replaced with your own identifying
17 # information: Portions Copyright [yyyy] [name of copyright owner]
21 # Copyright 2007 Sun Microsystems, Inc. All rights reserved.
22 # Use is subject to license terms.
24 #----------------------------------------------------------------------
27 # bash command line completion for zfs and zpool
29 # There are a few restrictions to bash's ability to complete command
30 # lines, and there is at least one bug.
32 # * Command line arguments:
33 # Most of zfs's commands take various arguments. I decided
34 # against writing a full command line parser for each command,
35 # the completion code will complete some things that are not
39 # Some of the option arguments are in the form of lists (e.g.
40 # option,option or even option=val,option=val). There doesn't
41 # seem to be a facility in base to handle this properly, so
42 # this still has to be done manually.
45 # ZFS uses the '@' character for snapshot names. This apparently
46 # confuses the completion code. To reproduce the bug, create
47 # a snapshot of a filesystem, e.g. tank/foo@snap, and then
48 # perform the following steps:
49 # # zfs send tank/foo<TAB><BACKSPACE><TAB>
50 # The first <TAB> will cause the snapshot's name to be expanded
51 # properly. The <BACKSPACE> will put the cursor at the end of the
52 # name, and the second <TAB> will cause the completion code to
53 # replace 'tank/foo@snap' with 'tank/footank/foo@snap'. I suspect
54 # the built-in hostname completion code is interfering with the
58 # Some arguments, such as the <dev> 'zpool create <pool> <dev>'
59 # work better without trailing spaces, whereas they are expected
60 # in others, such as the 'create' in that very same command. There
61 # does not seem to be a way in bash to specify which arguments
62 # get spaces and which don't. This can be frustrating for the user.
68 # discover all inheritable properties
69 zfs get 2>&1 | grep YES | awk '{ if ($3 == "YES") print $1 }'
75 local cur prev cmds iprops base cmd
78 cur="${COMP_WORDS[COMP_CWORD]}"
79 prev="${COMP_WORDS[COMP_CWORD-1]}"
80 base="${COMP_WORDS[1]}"
83 cmds="create destroy snapshot rollback clone promote rename \
84 list set get inherit mount unmount share unshare \
87 if [ "${prev##*/}" = "zfs" ]
89 COMPREPLY=($(compgen -W "$cmds" -- "$cur"))
98 # To create a filesystem, we need at least a pool name. We
99 # use the "-S /" option to add trailing /'s to the names. It
100 # would be nice to selectively turn on '-o nospace' here, but
101 # it doesn't appear possible. It would also be nice to be
102 # able to restrict the command line to a single filesystem or
103 # volume, but that would require extensive command line
106 results=$(/sbin/zfs list -H -o name -t filesystem,volume)
107 COMPREPLY=($(compgen -S / -W "$results" -- "$cur"))
110 destroy|list|set|get)
112 # Destroy differs from create in that we don't need to
113 # restrict options to filesystems & volumes. The list, set,
114 # and get commands kinda fall into this category too. As
115 # these three commands can take multiple datasets, we don't
116 # try to restrict them to one.
118 results=$(/sbin/zfs list -H -o name)
122 # We can only snapshot filesystems and volumes, and we
123 # *dont* want to add trailing /'s.
125 results=$(/sbin/zfs list -H -o name -t filesystem,volume)
129 # Rollback only works with snapshots.
131 results=$(/sbin/zfs list -H -o name -t snapshot)
135 # Clone takes no options, so this is easier to handle. The
136 # first argument (where $prev == $base) has to be a snapshot,
137 # whereas the second argument has to be a filesystem in
140 if [ "x$prev" = "x$base" ]
142 results=$(/sbin/zfs list -H -o name -t snapshot)
144 results=$(/sbin/zfs list -H -ro name \
145 -t filesystem ${prev%%/*} 2>/dev/null)
150 # Promotions can only be done of cloned filesystems. We
151 # check the 'origin' property to see if the filesystem is
154 if [ "x$prev" = "x$base" ]
156 results=$(/sbin/zfs get -rH -o name,value origin |
157 grep -v -- '-$' | awk '{print $1}')
164 # The first argument to rename, besides the -r, can be
165 # of any type. The second argument has to be of the same
166 # type as the first. If -r is specified, then the first
167 # and second type must be snapshots
169 if [ "x$prev" = "x-r" ]
171 results=$(/sbin/zfs list -H -o name -t snapshot)
173 results=$(/sbin/zfs list -H -o name)
178 # Inherit takes a property and one or more filesystems or
181 if [ "x$prev" = "x-r" ] || [ "x$prev" = "x$base" ]
183 results=$(__zfs_get_iprops)
185 results=$(/sbin/zfs list -H -o name \
186 -t filesystem,volume)
191 # Mount and share can be -a, or a filesystem
193 results=$(/sbin/zfs list -H -o name -t filesystem)
197 # Unmount and unshare can take a dataset filesystem, or a
198 # mountpoint. Happily, the output from 'zfs mount' lists
199 # all of these without any cruft to strip off.
201 results=$(/sbin/zfs mount)
205 # Send can only send snapshots
207 results=$(/sbin/zfs list -H -o name -t snapshot)
211 # Receive can take any dataset type
213 results=$(/sbin/zfs list -H -o name)
221 # A quick filter until CR 6540584 is fixed
223 if [ "$results" = "no datasets available" ]
228 COMPREPLY=($(compgen -W "$results" -- "$cur"))
237 /sbin/zpool status -v $1 | while read line
240 if [ "${line}" = "NAME" ]
244 elif [ ! -z "$found" ] && [ "${line}" = "" ]
250 if [ "${line}" = "$1" ] || [ "${line}" = "mirror" ] ||
251 [ "${line}" = "raidz" ] ||
252 [ "${line}" = "raidz2" ] || [ "${line}" = "spares" ]
264 /sbin/zpool list -H -o name | while read pname
276 local cur prev cmds iprops base cmd
279 cur="${COMP_WORDS[COMP_CWORD]}"
280 prev="${COMP_WORDS[COMP_CWORD-1]}"
281 base="${COMP_WORDS[1]}"
284 cmds="create destroy add remove list iostat status online offline \
285 clear attach detach replace scrub import export upgrade \
288 if [ "${prev##*/}" = "zpool" ]
290 COMPREPLY=($(compgen -W "$cmds" -- "$cur"))
301 # Pool creation can be a bit tricky to complete, so we just
302 # go with the built-in options ('mirror', 'raidz', 'raidz2',
303 # and 'spare') and filename completion (which unfortunately is
306 if [ "${cur%%/*}" = "" ]
308 results=$(compgen -f "${cur}")
310 results="mirror raidz raidz2 spare"
313 destroy|history|set|upgrade)
315 # Pool names are only allowed here, plus the -f force option
318 if [ "x$prev" = "x$base" ] || [ "x$prev" = "x-f" ]
320 results=$(/sbin/zpool list -H -o name)
327 # We can add vdevs to existing pools.
331 if [ "x$prev" = "x$base" ] || [ "x$isopt" != "x$prev" ]
333 results=$(/sbin/zpool list -H -o name)
335 results=$(compgen -f "${cur}")
338 remove|online|offline|clear|detach)
340 # Removing a device from a pool gives us a little more room
341 # for cleverness: once we know the pool name, we can
342 # provide a list of devices. Online, offline, clear, and
343 # detach work similarly, except that offline takes a -t option
346 if [ "x$prev" = "x$base" ]
348 results=$(/sbin/zpool list -H -o name)
349 elif [ "$base" = "offline" ] && [ "x$prev" = "x-t" ]
351 results=$(/sbin/zpool list -H -o name)
353 results=$(__zpool_devices $prev)
357 list|scrub|export|get|iostat|status)
359 # These commands can take any number of pools.
361 results=$(/sbin/zpool list -H -o name)
366 # Attach takes a pool, an existing pool's device, and a
367 # new device. Optional -f adds complexity, of course.
368 # Replace looks nearly the same.
370 if [ "x$prev" = "x$base" ] || [ "x$prev" = "x-f" ]
372 results=$(/sbin/zpool list -H -o name)
373 elif [ "$(__zpool_is_pool ${prev})" = "yes" ]
375 results=$(__zpool_devices $prev)
377 results=$(compgen -f "${cur}")
386 # A quick filter until CR 6540584 is fixed
388 if [ "$results" = "no pools available" ]
393 COMPREPLY=($(compgen $xtra -W "$results" -- "$cur"))
397 complete -F __zfs_comp zfs
398 complete -F __zpool_comp zpool