1264840Sdteskeif [ ! "$_GEOM_SUBR" ]; then _GEOM_SUBR=1
2264840Sdteske#
3264840Sdteske# Copyright (c) 2012-2014 Devin Teske
4264840Sdteske# All rights reserved.
5264840Sdteske#
6264840Sdteske# Redistribution and use in source and binary forms, with or without
7264840Sdteske# modification, are permitted provided that the following conditions
8264840Sdteske# are met:
9264840Sdteske# 1. Redistributions of source code must retain the above copyright
10264840Sdteske#    notice, this list of conditions and the following disclaimer.
11264840Sdteske# 2. Redistributions in binary form must reproduce the above copyright
12264840Sdteske#    notice, this list of conditions and the following disclaimer in the
13264840Sdteske#    documentation and/or other materials provided with the distribution.
14264840Sdteske#
15264840Sdteske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16264840Sdteske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17264840Sdteske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18264840Sdteske# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19264840Sdteske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20264840Sdteske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21264840Sdteske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22264840Sdteske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23264840Sdteske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24264840Sdteske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25264840Sdteske# SUCH DAMAGE.
26264840Sdteske#
27264840Sdteske# $FreeBSD: releng/11.0/usr.sbin/bsdconfig/share/geom.subr 298884 2016-05-01 16:38:12Z pfg $
28264840Sdteske#
29264840Sdteske############################################################ INCLUDES
30264840Sdteske
31264840SdteskeBSDCFG_SHARE="/usr/share/bsdconfig"
32264840Sdteske. $BSDCFG_SHARE/common.subr || exit 1
33264840Sdteskef_dprintf "%s: loading includes..." geom.subr
34264840Sdteskef_include $BSDCFG_SHARE/strings.subr
35264840Sdteskef_include $BSDCFG_SHARE/struct.subr
36264840Sdteske
37264840Sdteske############################################################ GLOBALS
38264840Sdteske
39264840SdteskeNGEOM_CLASSES=0 # Set by f_geom_get_all()/f_geom_reset()
40264840Sdteske
41264840Sdteske#
42264840Sdteske# GEOM classes for use with f_geom_find()
43264840Sdteske#
44264840Sdteske# NB: Since $GEOM_CLASS_ANY is the NULL string, make sure you quote it whenever
45264840Sdteske#     you put arguments after it.
46264840Sdteske#
47264840Sdteskesetvar GEOM_CLASS_ANY		"any"
48264840Sdteskesetvar GEOM_CLASS_DEV		"DEV"
49264840Sdteskesetvar GEOM_CLASS_DISK		"DISK"
50264840Sdteskesetvar GEOM_CLASS_ELI		"ELI"
51264840Sdteskesetvar GEOM_CLASS_FD		"FD"
52264840Sdteskesetvar GEOM_CLASS_LABEL		"LABEL"
53264840Sdteskesetvar GEOM_CLASS_MD		"MD"
54264840Sdteskesetvar GEOM_CLASS_NOP		"NOP"
55264840Sdteskesetvar GEOM_CLASS_PART		"PART"
56264840Sdteskesetvar GEOM_CLASS_RAID		"RAID"
57264840Sdteskesetvar GEOM_CLASS_SWAP		"SWAP"
58264840Sdteskesetvar GEOM_CLASS_VFS		"VFS"
59264840Sdteskesetvar GEOM_CLASS_ZFS_VDEV	"ZFS::VDEV"
60264840Sdteskesetvar GEOM_CLASS_ZFS_ZVOL	"ZFS::ZVOL"
61264840Sdteske
62264840Sdteske#
63264840Sdteske# GEOM structure definitions
64264840Sdteske#
65264840Sdteskef_struct_define GEOM_CLASS \
66264840Sdteske	id name ngeoms
67264840Sdteskef_struct_define GEOM_GEOM \
68264840Sdteske	id class_ref config name nconsumers nproviders rank
69264840Sdteske	# Also consumerN where N is 1 through nconsumers
70264840Sdteske	# Also providerN where N is 1 through nproviders
71264840Sdteskef_struct_define GEOM_CONSUMER \
72264840Sdteske	id geom_ref config mode provider_ref
73264840Sdteskef_struct_define GEOM_PROVIDER \
74264840Sdteske	id geom_ref config mode name mediasize
75264840Sdteske
76264840Sdteske# The config property of GEOM_GEOM struct is defined as this
77264840Sdteskef_struct_define GEOM_GEOM_CONFIG \
78264840Sdteske	entries first fwheads fwsectors last modified scheme state
79264840Sdteske
80264840Sdteske# The config property of GEOM_PROVIDER struct is defined as this
81264840Sdteskef_struct_define GEOM_PROVIDER_CONFIG \
82264840Sdteske	descr file fwheads fwsectors ident length type unit
83264840Sdteske
84264840Sdteske#
85264840Sdteske# Default behavior is to call f_geom_get_all() automatically when loaded.
86264840Sdteske#
87264840Sdteske: ${GEOM_SELF_SCAN_ALL=1}
88264840Sdteske
89264840Sdteske############################################################ FUNCTIONS
90264840Sdteske
91264840Sdteske# f_geom_get_all
92264840Sdteske#
93264840Sdteske# Parse sysctl(8) `kern.geom.confxml' data into a series of structs. GEOM
94298884Spfg# classes are at the top of the hierarchy and are stored as numbered structs
95264840Sdteske# from 1 to $NGEOM_CLASSES (set by this function) named `geom_class_C'. GEOM
96264840Sdteske# objects within each class are stored as numbered structs from 1 to `ngeoms'
97264840Sdteske# (a property of the GEOM class struct) named `geom_class_C_geom_N' (where C
98264840Sdteske# is the class number and N is the geom number).
99264840Sdteske#
100264840Sdteske# Use the function f_geom_find() to get a list of geoms (execute without
101264840Sdteske# arguments) or find specific geoms by class or name.
102264840Sdteske#
103264840Sdteskef_geom_get_all()
104264840Sdteske{
105264840Sdteske	eval "$( sysctl -n kern.geom.confxml | awk '
106264840Sdteske	BEGIN {
107264840Sdteske		struct_count["class"] = 0
108264840Sdteske		struct_count["geom"] = 0
109264840Sdteske		struct_count["consumer"] = 0
110264840Sdteske		struct_count["provider"] = 0
111264840Sdteske	}
112264840Sdteske	############################################### FUNCTIONS
113264840Sdteske	function set_value(prop, value)
114264840Sdteske	{
115264840Sdteske		if (!struct_stack[cur_struct]) return
116264840Sdteske		printf "%s set %s \"%s\"\n",
117264840Sdteske			struct_stack[cur_struct], prop, value
118264840Sdteske	}
119264840Sdteske	function create(type, id)
120264840Sdteske	{
121264840Sdteske		if (struct = created[type "_" id])
122264840Sdteske			print "f_struct_free", struct
123264840Sdteske		else {
124264840Sdteske			struct = struct_stack[cur_struct]
125264840Sdteske			struct = struct ( struct ? "" : "geom" )
126264840Sdteske			struct = struct "_" type "_" ++struct_count[type]
127264840Sdteske			created[type "_" id] = struct
128264840Sdteske		}
129264840Sdteske		print "debug= f_struct_new GEOM_" toupper(type), struct
130264840Sdteske		cur_struct++
131264840Sdteske		struct_stack[cur_struct] = struct
132264840Sdteske		type_stack[cur_struct] = type
133264840Sdteske		set_value("id", id)
134264840Sdteske	}
135264840Sdteske	function create_config()
136264840Sdteske	{
137264840Sdteske		struct = struct_stack[cur_struct]
138264840Sdteske		struct = struct ( struct ? "" : "geom" )
139264840Sdteske		struct = struct "_config"
140264840Sdteske		set_value("config", struct)
141264840Sdteske		type = type_stack[cur_struct]
142264840Sdteske		print "debug= f_struct_new GEOM_" toupper(type) "_CONFIG", \
143264840Sdteske		      struct
144264840Sdteske		cur_struct++
145264840Sdteske		struct_stack[cur_struct] = struct
146264840Sdteske		type_stack[cur_struct] = type "_config"
147264840Sdteske	}
148264840Sdteske	function extract_attr(field, attr)
149264840Sdteske	{
150264840Sdteske		if (match(field, attr "=\"0x[[:xdigit:]]+\"")) {
151264840Sdteske			len = length(attr)
152264840Sdteske			return substr($2, len + 3, RLENGTH - len - 3)
153264840Sdteske		}
154264840Sdteske	}
155264840Sdteske	function extract_data(type)
156264840Sdteske	{
157264840Sdteske		data = $0
158264840Sdteske		sub("^[[:space:]]*<" type ">", "", data)
159264840Sdteske		sub("</" type ">.*$", "", data)
160264840Sdteske		return data
161264840Sdteske	}
162264840Sdteske	############################################### OPENING PATTERNS
163264840Sdteske	$1 == "<mesh>" { mesh = 1 }
164264840Sdteske	$1 ~ /^<(class|geom)$/ && mesh {
165264840Sdteske		prop = substr($1, 2)
166264840Sdteske		if ((ref = extract_attr($2, "ref")) != "")
167264840Sdteske			set_value(prop "_ref", ref)
168264840Sdteske		else if ((id = extract_attr($2, "id")) != "")
169264840Sdteske			create(prop, id)
170264840Sdteske	}
171264840Sdteske	$1 ~ /^<(consumer|provider)$/ && mesh {
172264840Sdteske		prop = substr($1, 2)
173264840Sdteske		if ((ref = extract_attr($2, "ref")) != "")
174264840Sdteske			set_value(prop "_ref", ref)
175264840Sdteske		else if ((id = extract_attr($2, "id")) != "") {
176264840Sdteske			create(prop, id)
177264840Sdteske			cur_struct--
178264840Sdteske			propn = struct_count[prop]
179264840Sdteske			set_value(prop propn, struct_stack[cur_struct+1])
180264840Sdteske			cur_struct++
181264840Sdteske		}
182264840Sdteske	}
183264840Sdteske	$1 == "<config>" && mesh { create_config() }
184264840Sdteske	############################################### PROPERTIES
185264840Sdteske	$1 ~ /^<[[:alnum:]]+>/ {
186264840Sdteske		prop = $1
187264840Sdteske		sub(/^</, "", prop); sub(/>.*/, "", prop)
188264840Sdteske		set_value(prop, extract_data(prop))
189264840Sdteske	}
190264840Sdteske	############################################### CLOSING PATTERNS
191264840Sdteske	$1 ~ "^</(consumer|provider|config)>$" { cur_struct-- }
192264840Sdteske	$1 == "</geom>" {
193264840Sdteske		set_value("nconsumers", struct_count["consumer"])
194264840Sdteske		set_value("nproviders", struct_count["provider"])
195264840Sdteske		cur_struct--
196264840Sdteske		struct_count["consumer"] = 0
197264840Sdteske		struct_count["provider"] = 0
198264840Sdteske	}
199264840Sdteske	$1 == "</class>" {
200264840Sdteske		set_value("ngeoms", struct_count["geom"])
201264840Sdteske		cur_struct--
202264840Sdteske		struct_count["consumer"] = 0
203264840Sdteske		struct_count["provider"] = 0
204264840Sdteske		struct_count["geom"] = 0
205264840Sdteske	}
206264840Sdteske	$1 == "</mesh>" {
207264840Sdteske		printf "NGEOM_CLASSES=%u\n", struct_count["class"]
208264840Sdteske		delete struct_count
209264840Sdteske		mesh = 0
210264840Sdteske	}' )"
211264840Sdteske}
212264840Sdteske
213264840Sdteske# f_geom_reset
214264840Sdteske#
215264840Sdteske# Reset the registered GEOM chain.
216264840Sdteske#
217264840Sdteskef_geom_reset()
218264840Sdteske{
219264840Sdteske	local classn=1 class ngeoms geomn geom
220264840Sdteske	while [ $classn -le ${NGEOM_CLASSES:-0} ]; do
221264840Sdteske		class=geom_class_$classn
222264840Sdteske		$class get ngeoms ngeoms
223264840Sdteske		geomn=1
224264840Sdteske		while [ $geomn -le $ngeoms ]; do
225264840Sdteske			f_struct_free ${class}_geom_$geomn
226264840Sdteske			geomn=$(( $geomn + 1 ))
227264840Sdteske		done
228264840Sdteske		classn=$(( $classn + 1 ))
229264840Sdteske	done
230264840Sdteske	NGEOM_CLASSES=0
231264840Sdteske}
232264840Sdteske
233264840Sdteske# f_geom_rescan
234264840Sdteske#
235264840Sdteske# Rescan all GEOMs - convenience function.
236264840Sdteske#
237264840Sdteskef_geom_rescan()
238264840Sdteske{
239264840Sdteske	f_geom_reset
240264840Sdteske	f_geom_get_all
241264840Sdteske}
242264840Sdteske
243264840Sdteske# f_geom_find $name [$type [$var_to_set]]
244264840Sdteske#
245264840Sdteske# Find one or more registered GEOMs by name, type, or both. Returns a space-
246264840Sdteske# separated list of GEOMs matching the search criterion. The $type argument
247264840Sdteske# should be the GEOM class (see $GEOM_CLASS_* variables in GLOBALS above).
248264840Sdteske#
249264840Sdteske# If $var_to_set is missing or NULL, the GEOM name(s) are printed to standard
250264840Sdteske# out for capturing in a sub-shell (which is less-recommended because of
251264840Sdteske# performance degredation; for example, when called in a loop).
252264840Sdteske#
253264840Sdteskef_geom_find()
254264840Sdteske{
255264840Sdteske	local __name="$1" __type="${2:-$GEOM_CLASS_ANY}" __var_to_set="$3"
256264840Sdteske	local __classn=1 __class __class_name __ngeoms
257264840Sdteske	local __geomn __geom __geom_name __found=
258264840Sdteske	while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do
259264840Sdteske		__class=geom_class_$__classn
260264840Sdteske		$__class get name __class_name
261264840Sdteske		if [ "$__type" != "$GEOM_CLASS_ANY" -a \
262264840Sdteske		     "$__type" != "$__class_name" ]
263264840Sdteske		then
264264840Sdteske			__classn=$(( $__classn + 1 ))
265264840Sdteske			continue
266264840Sdteske		fi
267264840Sdteske
268264840Sdteske		__geomn=1
269264840Sdteske		$__class get ngeoms __ngeoms || __ngeoms=0
270264840Sdteske		while [ $__geomn -le $__ngeoms ]; do
271264840Sdteske			__geom=${__class}_geom_$__geomn
272264840Sdteske			$__geom get name __geom_name
273264840Sdteske			[ "$__name" = "$__geom_name" -o ! "$__name" ] &&
274264840Sdteske				__found="$__found $__geom"
275264840Sdteske			__geomn=$(( $__geomn + 1 ))
276264840Sdteske		done
277264840Sdteske		__classn=$(( $__classn + 1 ))
278264840Sdteske	done
279264840Sdteske	if [ "$__var_to_set" ]; then
280264840Sdteske		setvar "$__var_to_set" "${__found# }"
281264840Sdteske	else
282264840Sdteske		echo $__found
283264840Sdteske	fi
284264840Sdteske	[ "$__found" ] # Return status
285264840Sdteske}
286264840Sdteske
287264840Sdteske# f_geom_find_by $prop $find [$type [$var_to_set]]
288264840Sdteske#
289264840Sdteske# Find GEOM-related struct where $prop of the struct is equal to $find. Returns
290264840Sdteske# NULL or the name of the first GEOM struct to match. The $type argument should
291264840Sdteske# be one of the following:
292264840Sdteske#
293264840Sdteske# 	NULL		Find any of the below
294264840Sdteske# 	class		Find GEOM_CLASS struct
295264840Sdteske# 	geom		Find GEOM_GEOM struct
296264840Sdteske# 	consumer	Find GEOM_CONSUMER struct
297264840Sdteske# 	provider	Find GEOM_PROVIDER struct
298264840Sdteske#
299264840Sdteske# The $prop argument can be any property of the given type of struct. Some
300264840Sdteske# properties are common to all types (such as id) so the $type argument is
301264840Sdteske# optional (allowing you to return any struct whose property matches $find).
302264840Sdteske#
303264840Sdteske# If $var_to_set is missing or NULL, the GEOM struct name is printed to
304264840Sdteske# standard out for capturing in a sub-shell (which is less-recommended because
305264840Sdteske# of performance degredation; for example when called in a loop).
306264840Sdteske#
307264840Sdteskef_geom_find_by()
308264840Sdteske{
309264840Sdteske	local __prop="$1" __find="$2" __type="$3" __var_to_set="$4"
310264840Sdteske	local __classn=1 __class __ngeoms
311264840Sdteske	local __geomn __geom __nitems
312264840Sdteske	local __itype __itemn __item
313264840Sdteske	local __value __found=
314264840Sdteske
315264840Sdteske	if [ ! "$__prop" ]; then
316264840Sdteske		[ "$__var_to_set" ] && setvar "$__var_to_set" ""
317264840Sdteske		return $FAILURE
318264840Sdteske	fi
319264840Sdteske
320264840Sdteske	case "$__type" in
321264840Sdteske	"") : OK ;;
322264840Sdteske	class|GEOM_CLASS) __type=class ;;
323264840Sdteske	geom|GEOM_GEOM) __type=geom ;;
324264840Sdteske	consumer|GEOM_CONSUMER) __type=consumer ;;
325264840Sdteske	provider|GEOM_PROVIDER) __type=provider ;;
326264840Sdteske	*)
327264840Sdteske		[ "$__var_to_set" ] && setvar "$__var_to_set" ""
328264840Sdteske		return $FAILURE
329264840Sdteske	esac
330264840Sdteske
331264840Sdteske	while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do
332264840Sdteske		__class=geom_class_$__classn
333264840Sdteske
334264840Sdteske		if [ "${__type:-class}" = "class" ]; then
335264840Sdteske			$__class get "$__prop" __value || __value=
336264840Sdteske			[ "$__value" = "$__find" ] && __found="$__class" break
337264840Sdteske			[ "$__type" ] && __classn=$(( $__classn + 1 )) continue
338264840Sdteske		fi
339264840Sdteske
340264840Sdteske		__geomn=1
341264840Sdteske		$__class get ngeoms __ngeoms || __ngeoms=0
342264840Sdteske		while [ $__geomn -le $__ngeoms ]; do
343264840Sdteske			__geom=${__class}_geom_$__geomn
344264840Sdteske
345264840Sdteske			if [ "${__type:-geom}" = "geom" ]; then
346264840Sdteske				$__geom get "$__prop" __value || __value=
347264840Sdteske				[ "$__value" = "$__find" ] &&
348264840Sdteske					__found="$__geom" break
349264840Sdteske				[ "$__type" ] &&
350264840Sdteske					__geomn=$(( $__geomn + 1 )) continue
351264840Sdteske			fi
352264840Sdteske
353264840Sdteske			for __itype in ${__type:-consumer provider}; do
354264840Sdteske				$__geom get n${__itype}s __nitems || continue
355264840Sdteske				__itemn=1
356264840Sdteske				while [ $__itemn -le $__nitems ]; do
357264840Sdteske					__item=${__geom}_${__itype}_$__itemn
358264840Sdteske
359264840Sdteske					$__item get "$__prop" __value ||
360264840Sdteske						__value=
361264840Sdteske					[ "$__value" = "$__find" ] &&
362264840Sdteske						__found="$__item" break
363264840Sdteske					__itemn=$(( $__itemn + 1 ))
364264840Sdteske				done
365264840Sdteske				[ "$__found" ] && break
366264840Sdteske			done
367264840Sdteske			[ "$__found" ] && break
368264840Sdteske			__geomn=$(( $__geomn + 1 ))
369264840Sdteske		done
370264840Sdteske		[ "$__found" ] && break
371264840Sdteske		__classn=$(( $__classn + 1 ))
372264840Sdteske	done
373264840Sdteske	if [ "$__var_to_set" ]; then
374264840Sdteske		setvar "$__var_to_set" "$__found"
375264840Sdteske	else
376264840Sdteske		[ "$__found" ] && echo "$__found"
377264840Sdteske	fi
378264840Sdteske	[ "$__found" ] # Return status
379264840Sdteske}
380264840Sdteske
381264840Sdteske# f_geom_parent $geom|$consumer|$provider|$config [$var_to_set]
382264840Sdteske#
383264840Sdteske# Get the GEOM class associated with one of $geom, $consumer, $provider or
384264840Sdteske# $config.
385264840Sdteske#
386264840Sdteske# If $var_to_set is missing or NULL, the GEOM class name is printed to standard
387264840Sdteske# out for capturing in a sub-shell (which is less-recommended because of
388264840Sdteske# performance degredation; for example when called in a loop).
389264840Sdteske#
390264840Sdteskef_geom_parent()
391264840Sdteske{
392264840Sdteske	local __struct="$1" __var_to_set="$2"
393264840Sdteske	# NB: Order of pattern matches below is important
394264840Sdteske	case "$__struct" in
395264840Sdteske	*_config*) __struct="${__struct%_config*}" ;;
396264840Sdteske	*_consumer_*) __struct="${__struct%_consumer_[0-9]*}" ;;
397264840Sdteske	*_provider_*) __struct="${__struct%_provider_[0-9]*}" ;;
398264840Sdteske	*_geom_*) __struct="${__struct%_geom_[0-9]*}" ;;
399264840Sdteske	*) __struct=
400264840Sdteske	esac
401264840Sdteske	if [ "$__var_to_set" ]; then
402264840Sdteske		setvar "$__var_to_set" "$__struct"
403264840Sdteske	else
404264840Sdteske		echo "$__struct"
405264840Sdteske	fi
406264840Sdteske	f_struct "$__struct" # Return status
407264840Sdteske}
408264840Sdteske
409264840Sdteske############################################################ MAIN
410264840Sdteske
411264840Sdteske#
412280921Sdteske# Parse GEOM configuration unless requested otherwise
413264840Sdteske#
414264840Sdteskef_dprintf "%s: GEOM_SELF_SCAN_ALL=[%s]" geom.subr "$GEOM_SELF_SCAN_ALL"
415264840Sdteskecase "$GEOM_SELF_SCAN_ALL" in
416264840Sdteske""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
417264840Sdteske*)
418264840Sdteske	f_geom_get_all
419264840Sdteske	if [ "$debug" ]; then
420264840Sdteske		debug= f_geom_find "" "$GEOM_CLASS_ANY" geoms
421264840Sdteske		f_count ngeoms $geoms
422264840Sdteske		f_dprintf "%s: Initialized %u geom devices in %u classes." \
423264840Sdteske		          geom.subr "$ngeoms" "$NGEOM_CLASSES"
424264840Sdteske		unset geoms ngeoms
425264840Sdteske	fi
426264840Sdteskeesac
427264840Sdteske
428264840Sdteskef_dprintf "%s: Successfully loaded." geom.subr
429264840Sdteske
430264840Sdteskefi # ! $_GEOM_SUBR
431