diff options
Diffstat (limited to 'usr.sbin/bsdconfig/share/geom.subr')
-rw-r--r-- | usr.sbin/bsdconfig/share/geom.subr | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/usr.sbin/bsdconfig/share/geom.subr b/usr.sbin/bsdconfig/share/geom.subr new file mode 100644 index 0000000..912a5c7 --- /dev/null +++ b/usr.sbin/bsdconfig/share/geom.subr @@ -0,0 +1,430 @@ +if [ ! "$_GEOM_SUBR" ]; then _GEOM_SUBR=1 +# +# Copyright (c) 2012-2014 Devin Teske +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# +############################################################ INCLUDES + +BSDCFG_SHARE="/usr/share/bsdconfig" +. $BSDCFG_SHARE/common.subr || exit 1 +f_dprintf "%s: loading includes..." geom.subr +f_include $BSDCFG_SHARE/strings.subr +f_include $BSDCFG_SHARE/struct.subr + +############################################################ GLOBALS + +NGEOM_CLASSES=0 # Set by f_geom_get_all()/f_geom_reset() + +# +# GEOM classes for use with f_geom_find() +# +# NB: Since $GEOM_CLASS_ANY is the NULL string, make sure you quote it whenever +# you put arguments after it. +# +setvar GEOM_CLASS_ANY "any" +setvar GEOM_CLASS_DEV "DEV" +setvar GEOM_CLASS_DISK "DISK" +setvar GEOM_CLASS_ELI "ELI" +setvar GEOM_CLASS_FD "FD" +setvar GEOM_CLASS_LABEL "LABEL" +setvar GEOM_CLASS_MD "MD" +setvar GEOM_CLASS_NOP "NOP" +setvar GEOM_CLASS_PART "PART" +setvar GEOM_CLASS_RAID "RAID" +setvar GEOM_CLASS_SWAP "SWAP" +setvar GEOM_CLASS_VFS "VFS" +setvar GEOM_CLASS_ZFS_VDEV "ZFS::VDEV" +setvar GEOM_CLASS_ZFS_ZVOL "ZFS::ZVOL" + +# +# GEOM structure definitions +# +f_struct_define GEOM_CLASS \ + id name ngeoms +f_struct_define GEOM_GEOM \ + id class_ref config name nconsumers nproviders rank + # Also consumerN where N is 1 through nconsumers + # Also providerN where N is 1 through nproviders +f_struct_define GEOM_CONSUMER \ + id geom_ref config mode provider_ref +f_struct_define GEOM_PROVIDER \ + id geom_ref config mode name mediasize + +# The config property of GEOM_GEOM struct is defined as this +f_struct_define GEOM_GEOM_CONFIG \ + entries first fwheads fwsectors last modified scheme state + +# The config property of GEOM_PROVIDER struct is defined as this +f_struct_define GEOM_PROVIDER_CONFIG \ + descr file fwheads fwsectors ident length type unit + +# +# Default behavior is to call f_geom_get_all() automatically when loaded. +# +: ${GEOM_SELF_SCAN_ALL=1} + +############################################################ FUNCTIONS + +# f_geom_get_all +# +# Parse sysctl(8) `kern.geom.confxml' data into a series of structs. GEOM +# classes are at the top of the heirarchy and are stored as numbered structs +# from 1 to $NGEOM_CLASSES (set by this function) named `geom_class_C'. GEOM +# objects within each class are stored as numbered structs from 1 to `ngeoms' +# (a property of the GEOM class struct) named `geom_class_C_geom_N' (where C +# is the class number and N is the geom number). +# +# Use the function f_geom_find() to get a list of geoms (execute without +# arguments) or find specific geoms by class or name. +# +f_geom_get_all() +{ + eval "$( sysctl -n kern.geom.confxml | awk ' + BEGIN { + struct_count["class"] = 0 + struct_count["geom"] = 0 + struct_count["consumer"] = 0 + struct_count["provider"] = 0 + } + ############################################### FUNCTIONS + function set_value(prop, value) + { + if (!struct_stack[cur_struct]) return + printf "%s set %s \"%s\"\n", + struct_stack[cur_struct], prop, value + } + function create(type, id) + { + if (struct = created[type "_" id]) + print "f_struct_free", struct + else { + struct = struct_stack[cur_struct] + struct = struct ( struct ? "" : "geom" ) + struct = struct "_" type "_" ++struct_count[type] + created[type "_" id] = struct + } + print "debug= f_struct_new GEOM_" toupper(type), struct + cur_struct++ + struct_stack[cur_struct] = struct + type_stack[cur_struct] = type + set_value("id", id) + } + function create_config() + { + struct = struct_stack[cur_struct] + struct = struct ( struct ? "" : "geom" ) + struct = struct "_config" + set_value("config", struct) + type = type_stack[cur_struct] + print "debug= f_struct_new GEOM_" toupper(type) "_CONFIG", \ + struct + cur_struct++ + struct_stack[cur_struct] = struct + type_stack[cur_struct] = type "_config" + } + function extract_attr(field, attr) + { + if (match(field, attr "=\"0x[[:xdigit:]]+\"")) { + len = length(attr) + return substr($2, len + 3, RLENGTH - len - 3) + } + } + function extract_data(type) + { + data = $0 + sub("^[[:space:]]*<" type ">", "", data) + sub("</" type ">.*$", "", data) + return data + } + ############################################### OPENING PATTERNS + $1 == "<mesh>" { mesh = 1 } + $1 ~ /^<(class|geom)$/ && mesh { + prop = substr($1, 2) + if ((ref = extract_attr($2, "ref")) != "") + set_value(prop "_ref", ref) + else if ((id = extract_attr($2, "id")) != "") + create(prop, id) + } + $1 ~ /^<(consumer|provider)$/ && mesh { + prop = substr($1, 2) + if ((ref = extract_attr($2, "ref")) != "") + set_value(prop "_ref", ref) + else if ((id = extract_attr($2, "id")) != "") { + create(prop, id) + cur_struct-- + propn = struct_count[prop] + set_value(prop propn, struct_stack[cur_struct+1]) + cur_struct++ + } + } + $1 == "<config>" && mesh { create_config() } + ############################################### PROPERTIES + $1 ~ /^<[[:alnum:]]+>/ { + prop = $1 + sub(/^</, "", prop); sub(/>.*/, "", prop) + set_value(prop, extract_data(prop)) + } + ############################################### CLOSING PATTERNS + $1 ~ "^</(consumer|provider|config)>$" { cur_struct-- } + $1 == "</geom>" { + set_value("nconsumers", struct_count["consumer"]) + set_value("nproviders", struct_count["provider"]) + cur_struct-- + struct_count["consumer"] = 0 + struct_count["provider"] = 0 + } + $1 == "</class>" { + set_value("ngeoms", struct_count["geom"]) + cur_struct-- + struct_count["consumer"] = 0 + struct_count["provider"] = 0 + struct_count["geom"] = 0 + } + $1 == "</mesh>" { + printf "NGEOM_CLASSES=%u\n", struct_count["class"] + delete struct_count + mesh = 0 + }' )" +} + +# f_geom_reset +# +# Reset the registered GEOM chain. +# +f_geom_reset() +{ + local classn=1 class ngeoms geomn geom + while [ $classn -le ${NGEOM_CLASSES:-0} ]; do + class=geom_class_$classn + $class get ngeoms ngeoms + geomn=1 + while [ $geomn -le $ngeoms ]; do + f_struct_free ${class}_geom_$geomn + geomn=$(( $geomn + 1 )) + done + classn=$(( $classn + 1 )) + done + NGEOM_CLASSES=0 +} + +# f_geom_rescan +# +# Rescan all GEOMs - convenience function. +# +f_geom_rescan() +{ + f_geom_reset + f_geom_get_all +} + +# f_geom_find $name [$type [$var_to_set]] +# +# Find one or more registered GEOMs by name, type, or both. Returns a space- +# separated list of GEOMs matching the search criterion. The $type argument +# should be the GEOM class (see $GEOM_CLASS_* variables in GLOBALS above). +# +# If $var_to_set is missing or NULL, the GEOM name(s) are printed to standard +# out for capturing in a sub-shell (which is less-recommended because of +# performance degredation; for example, when called in a loop). +# +f_geom_find() +{ + local __name="$1" __type="${2:-$GEOM_CLASS_ANY}" __var_to_set="$3" + local __classn=1 __class __class_name __ngeoms + local __geomn __geom __geom_name __found= + while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do + __class=geom_class_$__classn + $__class get name __class_name + if [ "$__type" != "$GEOM_CLASS_ANY" -a \ + "$__type" != "$__class_name" ] + then + __classn=$(( $__classn + 1 )) + continue + fi + + __geomn=1 + $__class get ngeoms __ngeoms || __ngeoms=0 + while [ $__geomn -le $__ngeoms ]; do + __geom=${__class}_geom_$__geomn + $__geom get name __geom_name + [ "$__name" = "$__geom_name" -o ! "$__name" ] && + __found="$__found $__geom" + __geomn=$(( $__geomn + 1 )) + done + __classn=$(( $__classn + 1 )) + done + if [ "$__var_to_set" ]; then + setvar "$__var_to_set" "${__found# }" + else + echo $__found + fi + [ "$__found" ] # Return status +} + +# f_geom_find_by $prop $find [$type [$var_to_set]] +# +# Find GEOM-related struct where $prop of the struct is equal to $find. Returns +# NULL or the name of the first GEOM struct to match. The $type argument should +# be one of the following: +# +# NULL Find any of the below +# class Find GEOM_CLASS struct +# geom Find GEOM_GEOM struct +# consumer Find GEOM_CONSUMER struct +# provider Find GEOM_PROVIDER struct +# +# The $prop argument can be any property of the given type of struct. Some +# properties are common to all types (such as id) so the $type argument is +# optional (allowing you to return any struct whose property matches $find). +# +# If $var_to_set is missing or NULL, the GEOM struct name is printed to +# standard out for capturing in a sub-shell (which is less-recommended because +# of performance degredation; for example when called in a loop). +# +f_geom_find_by() +{ + local __prop="$1" __find="$2" __type="$3" __var_to_set="$4" + local __classn=1 __class __ngeoms + local __geomn __geom __nitems + local __itype __itemn __item + local __value __found= + + if [ ! "$__prop" ]; then + [ "$__var_to_set" ] && setvar "$__var_to_set" "" + return $FAILURE + fi + + case "$__type" in + "") : OK ;; + class|GEOM_CLASS) __type=class ;; + geom|GEOM_GEOM) __type=geom ;; + consumer|GEOM_CONSUMER) __type=consumer ;; + provider|GEOM_PROVIDER) __type=provider ;; + *) + [ "$__var_to_set" ] && setvar "$__var_to_set" "" + return $FAILURE + esac + + while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do + __class=geom_class_$__classn + + if [ "${__type:-class}" = "class" ]; then + $__class get "$__prop" __value || __value= + [ "$__value" = "$__find" ] && __found="$__class" break + [ "$__type" ] && __classn=$(( $__classn + 1 )) continue + fi + + __geomn=1 + $__class get ngeoms __ngeoms || __ngeoms=0 + while [ $__geomn -le $__ngeoms ]; do + __geom=${__class}_geom_$__geomn + + if [ "${__type:-geom}" = "geom" ]; then + $__geom get "$__prop" __value || __value= + [ "$__value" = "$__find" ] && + __found="$__geom" break + [ "$__type" ] && + __geomn=$(( $__geomn + 1 )) continue + fi + + for __itype in ${__type:-consumer provider}; do + $__geom get n${__itype}s __nitems || continue + __itemn=1 + while [ $__itemn -le $__nitems ]; do + __item=${__geom}_${__itype}_$__itemn + + $__item get "$__prop" __value || + __value= + [ "$__value" = "$__find" ] && + __found="$__item" break + __itemn=$(( $__itemn + 1 )) + done + [ "$__found" ] && break + done + [ "$__found" ] && break + __geomn=$(( $__geomn + 1 )) + done + [ "$__found" ] && break + __classn=$(( $__classn + 1 )) + done + if [ "$__var_to_set" ]; then + setvar "$__var_to_set" "$__found" + else + [ "$__found" ] && echo "$__found" + fi + [ "$__found" ] # Return status +} + +# f_geom_parent $geom|$consumer|$provider|$config [$var_to_set] +# +# Get the GEOM class associated with one of $geom, $consumer, $provider or +# $config. +# +# If $var_to_set is missing or NULL, the GEOM class name is printed to standard +# out for capturing in a sub-shell (which is less-recommended because of +# performance degredation; for example when called in a loop). +# +f_geom_parent() +{ + local __struct="$1" __var_to_set="$2" + # NB: Order of pattern matches below is important + case "$__struct" in + *_config*) __struct="${__struct%_config*}" ;; + *_consumer_*) __struct="${__struct%_consumer_[0-9]*}" ;; + *_provider_*) __struct="${__struct%_provider_[0-9]*}" ;; + *_geom_*) __struct="${__struct%_geom_[0-9]*}" ;; + *) __struct= + esac + if [ "$__var_to_set" ]; then + setvar "$__var_to_set" "$__struct" + else + echo "$__struct" + fi + f_struct "$__struct" # Return status +} + +############################################################ MAIN + +# +# Parse GEOM configuration unless requested otherwise +# +f_dprintf "%s: GEOM_SELF_SCAN_ALL=[%s]" geom.subr "$GEOM_SELF_SCAN_ALL" +case "$GEOM_SELF_SCAN_ALL" in +""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;; +*) + f_geom_get_all + if [ "$debug" ]; then + debug= f_geom_find "" "$GEOM_CLASS_ANY" geoms + f_count ngeoms $geoms + f_dprintf "%s: Initialized %u geom devices in %u classes." \ + geom.subr "$ngeoms" "$NGEOM_CLASSES" + unset geoms ngeoms + fi +esac + +f_dprintf "%s: Successfully loaded." geom.subr + +fi # ! $_GEOM_SUBR |