if ENABLE_BASH_COMPLETION
bashcompletiondir = $(BASH_COMPLETION_DIR)
-dist_bashcompletion_DATA = bash-completion/lctl
+dist_bashcompletion_DATA = bash-completion/lustre bash-completion/lctl \
+ bash-completion/lfs
endif
EXTRA_DIST = license-status lustre_rmmod ldev lc_mon lhbadm \
$(addsuffix .in,$(genscripts)) lfs_migrate lustre_req_history \
lustre lsvcgss lc_common haconfig Lustre.ha_v2 dkms.mkconf \
zfsobj2fid ko2iblnd-probe statechange-lustre.sh \
- bash-completion/lctl
+ bash-completion/lustre bash-completion/lctl bash-completion/lfs
CLEANFILES = $(genscripts)
+++ /dev/null
-_lctl()
-{
- local cur prev words cword
-
- _init_completion || return
- COMPREPLY=()
-
- if [[ "$cword" == "1" ]]; then
- COMPREPLY=( $( compgen -W '$(lctl --list-commands |
- grep -v '^=')' -- "$cur" ) )
- return 0
- fi
-
- case "${words[1]}" in
- set_param|list_param|get_param)
- local filter="s/=$//"
- [[ "${words[1]}" == "set_param" ]] && filter="/[^=/]$/d"
- mapfile -t COMPREPLY < <(
- lctl list_param -F "${cur#[\"\']}*" 2>/dev/null |
- sed -e "$filter" -e 's#/$#.#' \
- -e "s#^${cur//\*/[^.]*}#$cur#"
- )
- compopt -o nospace
-
- return 0
- ;;
- esac
-} &&
-complete -F _lctl lctl
--- /dev/null
+lustre
\ No newline at end of file
--- /dev/null
+lustre
\ No newline at end of file
--- /dev/null
+_lustre_cmds()
+{
+ local cmd="$1"
+ local sub="$2"
+
+ # "--list-command" prints commands in columns and truncates long ones
+ "$cmd" "$sub" --non-existent-option |
+ sed -e 1d -e '$d' -e 's/"//g' -e /=/d -e /exit/d -e /quit/d
+}
+
+_lustre_long_opts()
+{
+ local cmd="$1"
+ local sub="$2"
+ local subsub="$3"
+
+ # strip off usage message decoration and leave long opts
+ if [[ -n "$subsub" ]]; then
+ "$cmd" "$sub" help "$subsub" |& grep -owE -- '--[-a-zA-Z0]*'
+ else
+ "$cmd" help "$sub" |& sed -e 1d | grep -owE -- '--[-a-zA-Z0]*'
+ fi
+ # several commands take the same options as setstripe, except --delete
+ case "$sub$subsub" in
+ migrate|mirrorcreate|mirrorextend)
+ _lustre_long_opts "$cmd" setstripe | grep -v -- --delete
+ esac
+}
+
+_lustre_short_opts()
+{
+ local cmd="$1"
+ local sub="$2"
+ local subsub="$3"
+
+ # strip off usage message decoration and leave short opts
+ if [[ -n "$subsub" ]]; then
+ "$cmd" "$sub" help "$subsub" |& grep -owE -- '-[-a-zA-Z0]'
+ else
+ "$cmd" help "$sub" |& grep -owE -- '-[-a-zA-Z0]'
+ fi
+ # several commands take the same options as setstripe, except -d
+ case "$sub$subsub" in
+ migrate|mirrorextend|mirrorextend)
+ _lustre_short_opts "$cmd" setstripe | grep -v -- -d
+ esac
+}
+
+_lustre_comp_flags()
+{
+ local cmd=$1
+ local flags
+
+ flags=$("$cmd" help find |& tr "<>[],}" " " |
+ grep -- '--component-flags {' | cut -d\{ -f2)
+ if [[ -z "$flags" ]]; then
+ local version=($("$cmd" --version))
+
+ case "${version[1]}" in
+ 2.13*) flags="init stale prefer offline nosync extension";;
+ 2.12*|2.11*) flags="init stale prefer offline nosync";;
+ *) flags="init";;
+ esac
+ fi
+ echo $flags
+}
+
+_lustre_mountpoints()
+{
+ findmnt --list -t lustre -n -o TARGET
+}
+
+_lustre_mount_fsnames()
+{
+ local mountpoint
+
+ # FIXME: will fail if newlines in $mountpoint, why would anyone do that?
+ _lustre_mountpoints | while read mountpoint; do
+ lfs getname -n "$mountpoint" 2> /dev/null
+ done
+}
+
+_lustre_devices()
+{
+ lctl device_list | awk '{ print $4 }'
+}
+
+_lustre_fsnames()
+{
+ local mountpoint="${1:-'.'}"
+
+ local fsname=$(lfs getname -n "$mountpoint" 2>/dev/null)
+
+ [[ -n "$fsname" ]] && echo "$fsname" || _lustre_mount_fsnames
+}
+
+_lustre_layouts()
+{
+ "$cmd" help find |& tr "[]," " " | grep -- --layout | sed "s/.*-L //"
+}
+
+_lustre_mdts()
+{
+ lfs mdts $1 | grep _UUID | sed -e "s/[0-9]*: //" -e "s/_UUID.*//"
+}
+
+_lustre_osts()
+{
+ lfs osts $1 | grep _UUID | sed -e "s/[0-9]*: //" -e "s/_UUID.*//"
+}
+
+_lustre_pools()
+{
+ if [[ -d "$1" ]]; then
+ "$cmd" pool_list $1 2> /dev/null | grep -v "[Pp]ools from" |
+ cut -d. -f2
+ return 0
+ fi
+
+ for fsname in $(_lustre_fsnames $1); do
+ "$cmd" pool_list $fsname 2> /dev/null | grep -v "[Pp]ools from"
+ done
+}
+
+_lfs()
+{
+ local cur prev words cword
+ local mountpoint cmd sub find_opts
+
+ COMPREPLY=()
+ # allow different versions of bash_completion to work
+ if declare -F _init_completion > /dev/null; then
+ # this provides more functionality, but is only in v2.x
+ _init_completion || return
+ else
+ # this is compatible with both v1.3 and v2.x
+ _get_comp_words_by_ref cur prev words cword
+ fi
+
+ cmd="${words[0]}"
+ sub="${words[1]}"
+ [[ "$sub" == "mirror" || "$sub" == "pcc" ]] && subsub="${words[2]}"
+ if [[ "$cword" == "1" || "$prev" == "help" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_cmds "$cmd")' -- "$cur"))
+ return 0
+ fi
+
+ case "$cur" in
+ --*)
+ COMPREPLY+=($(compgen -W '$(_lustre_long_opts "$cmd" "$sub" "$subsub")' -- "$cur"))
+ return 0
+ ;;
+ -*)
+ # lfs find allows "-longopt" for compatibility with find(1)
+ [[ "$sub" == "find" ]] && find_opts=$(_lustre_long_opts "$cmd" find)
+ COMPREPLY+=($(compgen -W '$(_lustre_short_opts "$cmd" "$sub" "$subsub") ${find_opts//--/-}' -- "$cur"))
+ return 0
+ ;;
+ esac
+
+ case "$sub" in
+ check)
+ [[ -n "$cur" ]] && return 0
+ COMPREPLY+=($(compgen -W '$("$cmd" help check |& grep usage |
+ sed -e "s/[<>|]/ /g" \
+ -e "s/.*check //")' -- "$cur"))
+ return 0
+ ;;
+ df)
+ mapfile -t COMPREPLY < <(
+ _lustre_mountpoints | grep -- "^$cur" | sed 's/ /\\ /g'
+ )
+ return 0
+ ;;
+ find)
+ [[ -d "${words[2]}" ]] && mountpoint="${words[2]}"
+ case "${prev/--/-}" in
+ -component-flags|-comp-flags)
+ # FIXME: this should allow a comma-separated list
+ COMPREPLY+=($(compgen -W '$(_lustre_comp_flags)' -- "$cur"))
+ return 0
+ ;;
+ -g|-group)
+ COMPREPLY+=($(compgen -g -- "$cur"))
+ return 0
+ ;;
+ -L|-layout)
+ COMPREPLY+=($(compgen -W '$(_lustre_layouts)' -- "$cur"))
+ return 0
+ ;;
+ -m|-mdt)
+ # FIXME: this should allow a comma-separated list
+ COMPREPLY+=($(compgen -W '$(_lustre_mdts "$mountpoint")' -- "$cur"))
+ return 0
+ ;;
+ -O|-ost)
+ # FIXME: this should allow a comma-separated list
+ COMPREPLY+=($(compgen -W '$(_lustre_osts "$mountpoint")' -- "$cur"))
+ return 0
+ ;;
+ -pool)
+ COMPREPLY+=($(compgen -W '$(_lustre_pools "$mountpoint")' -- "$cur"))
+ return 0
+ ;;
+ -t|-type)
+ COMPREPLY+=($(compgen -W 'b c d f l p s' -- "$cur"))
+ return 0
+ ;;
+ -u|-user)
+ COMPREPLY+=($(compgen -u -- "$cur"))
+ return 0
+ ;;
+ esac
+ if [ -z "$mountpoint" ]; then
+ mapfile -t COMPREPLY < <(
+ _lustre_mountpoints | grep -- "^$cur" |
+ sed -e 's/ /\\ /g'
+ )
+ return 0
+ fi
+ ;;
+ mirror)
+ if [[ "$prev" == "$sub" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_cmds "$cmd" "$sub")' -- "$cur"))
+ return 0
+ fi
+ ;;
+ pcc)
+ if [[ "$prev" == "$sub" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_cmds "$cmd" "$sub")' -- "$cur"))
+ return 0
+ fi
+ ;;
+ pool_list)
+ COMPREPLY+=($(compgen -W '$(_lustre_fsnames
+ _lustre_pools)' -- "$cur"))
+ return 0
+ ;;
+ setstripe)
+ case "$prev" in
+ --component-flags|--comp-flags)
+ # only subset allowed, easier to list than exclude for now
+ # COMPREPLY+=($(compgen -W '$(_lustre_comp_flags)' -- "$cur"))
+ # FIXME: this should allow a comma-separated list
+ COMPREPLY+=($(compgen -W 'nosync prefer' -- "$cur"))
+ return 0
+ ;;
+ -p|--pool)
+ COMPREPLY+=($(compgen -W '$(_lustre_pools)' -- "$cur"))
+ return 0
+ ;;
+ esac
+ ;;
+ esac
+
+ _filedir
+ return 0
+} &&
+complete -F _lfs lfs
+
+_lctl()
+{
+ local cur prev words cword
+
+ COMPREPLY=()
+ # allow different versions of bash_completion to work
+ if declare -F _init_completion > /dev/null; then
+ # this provides more functionality, but is only in v2.x
+ _init_completion || return
+ else
+ # this is compatible with both v1.3 and v2.x
+ _get_comp_words_by_ref cur prev words cword
+ fi
+
+ cmd="${words[0]}"
+ sub="${words[1]}"
+ [[ "$sub" == "--device" && $cword -ge 4 ]] && sub="${words[3]}"
+
+ if [[ "$cword" == "1" || "$prev" == "help" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_cmds "$cmd")' -- "$cur"))
+ return 0
+ fi
+
+ case "$cur" in
+ --*)
+ COMPREPLY+=($(compgen -W '$(_lustre_long_opts "$cmd" "$sub")' -- "$cur"))
+ return 0
+ ;;
+ -*)
+ COMPREPLY+=($(compgen -W '$(_lustre_short_opts "$cmd" "$sub")' -- "$cur"))
+ return 0
+ ;;
+ esac
+
+ case "$sub" in
+ --device)
+ if [[ "$cword" == "2" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_devices)' -- "$cur"))
+ elif [[ "$cword" == "3" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_cmds "$cmd")' -- "$cur"))
+ fi
+ return 0
+ ;;
+ get_param|list_param|set_param)
+ local filter="s/=$//"
+ [[ "$sub" == "set_param" ]] && filter="/[^=/]$/d"
+ mapfile -t COMPREPLY < <(
+ "$cmd" list_param -F "${cur#[\"\']}*" 2>/dev/null |
+ sed -e "$filter" -e 's#/$#.#' \
+ -e "s#^${cur//\*/[^.]*}#$cur#"
+ )
+ compopt -o nospace
+
+ return 0
+ ;;
+ pcc)
+ if [[ "$prev" == "$sub" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_cmds "$cmd" "$sub")' -- "$cur"))
+ return 0
+ fi
+ ;;
+ pool_list)
+ if [[ "$cword" == "2" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_mountpoints
+ _lustre_fsnames
+ _lustre_pools)' -- "$cur"))
+ return 0
+ fi
+ ;;
+ pool_destroy)
+ if [[ "$cword" == "2" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_pools)' -- "$cur"))
+ return 0
+ fi
+ return 0
+ ;;
+ pool_add|pool_remove)
+ if [[ "$cword" == "2" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_pools)' -- "$cur"))
+ return 0
+ elif [[ "$cword" == "3" ]]; then
+ COMPREPLY+=($(compgen -W '$(_lustre_osts)' -- "$cur"))
+ return 0
+ fi
+ return 0
+ ;;
+ esac
+} &&
+complete -F _lctl lctl
/* LFSCK commands */
{"==== LFSCK ====", NULL, 0, "LFSCK"},
{"lfsck_start", jt_lfsck_start, 0, "start LFSCK\n"
- "usage: lfsck_start [-M | --device [MDT,OST]_device]\n"
- " [-A | --all] [-c | --create-ostobj [on | off]]\n"
- " [-C | --create-mdtobj [on | off]]\n"
- " [-d | --delay-create-ostobj [on | off]]\n"
- " [-e | --error {continue | abort}] [-h | --help]\n"
- " [-n | --dryrun [on | off]] [-o | --orphan]\n"
- " [-r | --reset] [-s | --speed speed_limit]\n"
- " [-t | --type lfsck_type[,lfsck_type...]]\n"
- " [-w | --window-size size]"},
+ "usage: lfsck_start [--device|-M [MDT,OST]_device]\n"
+ " [--all|-A] [--create-ostobj|-c [on | off]]\n"
+ " [--create-mdtobj|-C [on | off]]\n"
+ " [--delay-create-ostobj|-d [on | off]]\n"
+ " [--error|-e {continue | abort}] [--help|-h]\n"
+ " [--dryrun|-n [on | off]] [-o | --orphan]\n"
+ " [--reset|-r] [--speed|-s speed_limit]\n"
+ " [--type|-t lfsck_type[,lfsck_type...]]\n"
+ " [--window-size|-w size]"},
{"lfsck_stop", jt_lfsck_stop, 0, "stop lfsck(s)\n"
- "usage: lfsck_stop [-M | --device [MDT,OST]_device]\n"
- " [-A | --all] [-h | --help]"},
+ "usage: lfsck_stop [--device|-M [MDT,OST]_device]\n"
+ " [--all|-a] [--help|-h]"},
{"lfsck_query", jt_lfsck_query, 0, "check lfsck(s) status\n"
- "usage: lfsck_query [-M | --device MDT_device] [-h | --help]\n"
- " [-t | --type lfsck_type[,lfsck_type...]]\n"
- " [-w | --wait]"},
+ "usage: lfsck_query [--device|-M MDT_device] [--help|-h]\n"
+ " [--type|-t lfsck_type[,lfsck_type...]]\n"
+ " [--wait|-w]"},
#endif /* HAVE_SERVER_SUPPORT */
{"==== obsolete (DANGEROUS) ====", NULL, 0, "obsolete (DANGEROUS)"},
/* some test scripts still use these */
"\t -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n" \
"\t Or:\n" \
"\t -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n" \
- "\t If --pool is set with --ost, then the OSTs\n" \
+ "\t If --pool is set with --ost then the OSTs\n" \
"\t must be the members of the pool.\n" \
"\tcomp_end: Extent end of component, start after previous end.\n"\
"\t Can be specified with K, M or G (for KB, MB, GB\n" \
"\t it must follow the option without a space.\n" \
"\t The option can also be repeated multiple times to\n" \
"\t separate mirrors that have different layouts.\n" \
- "\tsetstripe options: Mirror layout\n" \
+ "\tSETSTRIPE_OPTIONS: Mirror layout\n" \
"\t It can be a plain layout or a composite layout.\n" \
"\t If not specified, the stripe options inherited\n" \
"\t from the previous component will be used.\n" \
"\t file.\n"
#define MIRROR_EXTEND_USAGE \
- " <--mirror-count|-N[mirror_count]>\n" \
- " [setstripe options|-f <victim_file>]\n" \
+ " {--mirror-count|-N}[mirror_count]\n" \
+ " [SETSTRIPE_OPTIONS|-f|--file <victim_file>]\n" \
" [--no-verify]\n"
#define SETSTRIPE_USAGE \
{ .pc_name = "create", .pc_func = lfs_mirror_create,
.pc_help = "Create a mirrored file.\n"
"usage: lfs mirror create "
- "<--mirror-count|-N[mirror_count]> "
- "[setstripe options] ... <filename|directory>\n"
+ "{--mirror-count|-N}[mirror_count] "
+ "[SETSTRIPE_OPTIONS] ... <filename|directory>\n"
MIRROR_CREATE_HELP },
{ .pc_name = "extend", .pc_func = lfs_mirror_extend,
.pc_help = "Extend a mirrored file.\n"
"usage: lfs mirror extend "
- "<--mirror-count|-N[mirror_count]> [--no-verify] "
- "[setstripe options|-f <victim_file>] ... <filename>\n"
+ "{--mirror-count|-N}[mirror_count] [--no-verify] "
+ "[SETSTRIPE_OPTIONS|-f <victim_file>] ... <filename>\n"
MIRROR_EXTEND_HELP },
{ .pc_name = "split", .pc_func = lfs_mirror_split,
.pc_help = "Split a mirrored file.\n"
SSM_CMD_COMMON("setstripe --component-add")
SSM_HELP_COMMON
"To totally delete the default striping from an existing directory:\n"
- "usage: setstripe -d <directory>\n"
+ "usage: setstripe [--delete|-d] <directory>\n"
" or\n"
"To create a mirrored file or set s default mirror layout on a directory:\n"
- "usage: setstripe -N[mirror_count] [STRIPE_OPTIONS] <directory|filename>\n"
+ "usage: setstripe {--mirror-count|-N}[mirror_count] [STRIPE_OPTIONS] <directory|filename>\n"
" or\n"
"To delete the last component(s) from an existing composite file\n"
"(note that this will also delete any data in those components):\n"
" [--mdt-index|-m] [--recursive|-r] [--raw|-R]\n"
" [--layout|-L] [--generation|-g] [--yaml|-y]\n"
" [--component-id[=comp_id]|-I[comp_id]]\n"
- " [--component-flags[=comp_flags]]\n"
+ " [--component-flags {init,stale,prefer,offline,nosync}]\n"
" [--component-count]\n"
- " [--component-start[=[+-]comp_start]]\n"
- " [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
+ " [--component-start [+-]N[kMGTPE]]\n"
+ " [--component-end|-E [+-]N[kMGTPE]]\n"
" [[!] --mirror-index=[+-]<index> |\n"
" [!] --mirror-id=[+-]<id>]\n"
" <directory|filename> ..."},
{"df", lfs_df, 0,
"report filesystem disk space usage or inodes usage"
"of each MDS and all OSDs or a batch belonging to a specific pool .\n"
- "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
+ "Usage: df [--inodes|-i] [--human-readable|-h] [--lazy|-l]\n"
+ " [--pool|-p <fsname>[.<pool>]] [path]"},
{"getname", lfs_getname, 0, "list instances and specified mount points "
"[for specified path only]\n"
"Usage: getname [-h]|[path ...] "},
{"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
"usage: rmfid <fsname|rootpath> <fid> ..."},
{"data_version", lfs_data_version, 0, "Display file data version for "
- "a given path.\n" "usage: data_version -[n|r|w] <path>"},
+ "a given path.\n" "usage: data_version [-n|-r|-w] <path>"},
{"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
"undergoing actions) for given files.\n usage: hsm_state <file> ..."},
{"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"