xref: /freebsd/usr.sbin/bsdconfig/share/geom.subr (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1if [ ! "$_GEOM_SUBR" ]; then _GEOM_SUBR=1
2#
3# Copyright (c) 2012-2014 Devin Teske
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25# SUCH DAMAGE.
26#
27#
28############################################################ INCLUDES
29
30BSDCFG_SHARE="/usr/share/bsdconfig"
31. $BSDCFG_SHARE/common.subr || exit 1
32f_dprintf "%s: loading includes..." geom.subr
33f_include $BSDCFG_SHARE/strings.subr
34f_include $BSDCFG_SHARE/struct.subr
35
36############################################################ GLOBALS
37
38NGEOM_CLASSES=0 # Set by f_geom_get_all()/f_geom_reset()
39
40#
41# GEOM classes for use with f_geom_find()
42#
43# NB: Since $GEOM_CLASS_ANY is the NULL string, make sure you quote it whenever
44#     you put arguments after it.
45#
46setvar GEOM_CLASS_ANY		"any"
47setvar GEOM_CLASS_DEV		"DEV"
48setvar GEOM_CLASS_DISK		"DISK"
49setvar GEOM_CLASS_ELI		"ELI"
50setvar GEOM_CLASS_FD		"FD"
51setvar GEOM_CLASS_LABEL		"LABEL"
52setvar GEOM_CLASS_MD		"MD"
53setvar GEOM_CLASS_NOP		"NOP"
54setvar GEOM_CLASS_PART		"PART"
55setvar GEOM_CLASS_RAID		"RAID"
56setvar GEOM_CLASS_SWAP		"SWAP"
57setvar GEOM_CLASS_VFS		"VFS"
58setvar GEOM_CLASS_ZFS_VDEV	"ZFS::VDEV"
59setvar GEOM_CLASS_ZFS_ZVOL	"ZFS::ZVOL"
60
61#
62# GEOM structure definitions
63#
64f_struct_define GEOM_CLASS \
65	id name ngeoms
66f_struct_define GEOM_GEOM \
67	id class_ref config name nconsumers nproviders rank
68	# Also consumerN where N is 1 through nconsumers
69	# Also providerN where N is 1 through nproviders
70f_struct_define GEOM_CONSUMER \
71	id geom_ref config mode provider_ref
72f_struct_define GEOM_PROVIDER \
73	id geom_ref config mode name mediasize
74
75# The config property of GEOM_GEOM struct is defined as this
76f_struct_define GEOM_GEOM_CONFIG \
77	entries first fwheads fwsectors last modified scheme state
78
79# The config property of GEOM_PROVIDER struct is defined as this
80f_struct_define GEOM_PROVIDER_CONFIG \
81	descr file fwheads fwsectors ident length type unit
82
83#
84# Default behavior is to call f_geom_get_all() automatically when loaded.
85#
86: ${GEOM_SELF_SCAN_ALL=1}
87
88############################################################ FUNCTIONS
89
90# f_geom_get_all
91#
92# Parse sysctl(8) `kern.geom.confxml' data into a series of structs. GEOM
93# classes are at the top of the hierarchy and are stored as numbered structs
94# from 1 to $NGEOM_CLASSES (set by this function) named `geom_class_C'. GEOM
95# objects within each class are stored as numbered structs from 1 to `ngeoms'
96# (a property of the GEOM class struct) named `geom_class_C_geom_N' (where C
97# is the class number and N is the geom number).
98#
99# Use the function f_geom_find() to get a list of geoms (execute without
100# arguments) or find specific geoms by class or name.
101#
102f_geom_get_all()
103{
104	eval "$( sysctl -n kern.geom.confxml | awk '
105	BEGIN {
106		struct_count["class"] = 0
107		struct_count["geom"] = 0
108		struct_count["consumer"] = 0
109		struct_count["provider"] = 0
110	}
111	############################################### FUNCTIONS
112	function set_value(prop, value)
113	{
114		if (!struct_stack[cur_struct]) return
115		printf "%s set %s \"%s\"\n",
116			struct_stack[cur_struct], prop, value
117	}
118	function create(type, id)
119	{
120		if (struct = created[type "_" id])
121			print "f_struct_free", struct
122		else {
123			struct = struct_stack[cur_struct]
124			struct = struct ( struct ? "" : "geom" )
125			struct = struct "_" type "_" ++struct_count[type]
126			created[type "_" id] = struct
127		}
128		print "debug= f_struct_new GEOM_" toupper(type), struct
129		cur_struct++
130		struct_stack[cur_struct] = struct
131		type_stack[cur_struct] = type
132		set_value("id", id)
133	}
134	function create_config()
135	{
136		struct = struct_stack[cur_struct]
137		struct = struct ( struct ? "" : "geom" )
138		struct = struct "_config"
139		set_value("config", struct)
140		type = type_stack[cur_struct]
141		print "debug= f_struct_new GEOM_" toupper(type) "_CONFIG", \
142		      struct
143		cur_struct++
144		struct_stack[cur_struct] = struct
145		type_stack[cur_struct] = type "_config"
146	}
147	function extract_attr(field, attr)
148	{
149		if (match(field, attr "=\"0x[[:xdigit:]]+\"")) {
150			len = length(attr)
151			return substr($2, len + 3, RLENGTH - len - 3)
152		}
153	}
154	function extract_data(type)
155	{
156		data = $0
157		sub("^[[:space:]]*<" type ">", "", data)
158		sub("</" type ">.*$", "", data)
159		return data
160	}
161	############################################### OPENING PATTERNS
162	$1 == "<mesh>" { mesh = 1 }
163	$1 ~ /^<(class|geom)$/ && mesh {
164		prop = substr($1, 2)
165		if ((ref = extract_attr($2, "ref")) != "")
166			set_value(prop "_ref", ref)
167		else if ((id = extract_attr($2, "id")) != "")
168			create(prop, id)
169	}
170	$1 ~ /^<(consumer|provider)$/ && mesh {
171		prop = substr($1, 2)
172		if ((ref = extract_attr($2, "ref")) != "")
173			set_value(prop "_ref", ref)
174		else if ((id = extract_attr($2, "id")) != "") {
175			create(prop, id)
176			cur_struct--
177			propn = struct_count[prop]
178			set_value(prop propn, struct_stack[cur_struct+1])
179			cur_struct++
180		}
181	}
182	$1 == "<config>" && mesh { create_config() }
183	############################################### PROPERTIES
184	$1 ~ /^<[[:alnum:]]+>/ {
185		prop = $1
186		sub(/^</, "", prop); sub(/>.*/, "", prop)
187		set_value(prop, extract_data(prop))
188	}
189	############################################### CLOSING PATTERNS
190	$1 ~ "^</(consumer|provider|config)>$" { cur_struct-- }
191	$1 == "</geom>" {
192		set_value("nconsumers", struct_count["consumer"])
193		set_value("nproviders", struct_count["provider"])
194		cur_struct--
195		struct_count["consumer"] = 0
196		struct_count["provider"] = 0
197	}
198	$1 == "</class>" {
199		set_value("ngeoms", struct_count["geom"])
200		cur_struct--
201		struct_count["consumer"] = 0
202		struct_count["provider"] = 0
203		struct_count["geom"] = 0
204	}
205	$1 == "</mesh>" {
206		printf "NGEOM_CLASSES=%u\n", struct_count["class"]
207		delete struct_count
208		mesh = 0
209	}' )"
210}
211
212# f_geom_reset
213#
214# Reset the registered GEOM chain.
215#
216f_geom_reset()
217{
218	local classn=1 class ngeoms geomn geom
219	while [ $classn -le ${NGEOM_CLASSES:-0} ]; do
220		class=geom_class_$classn
221		$class get ngeoms ngeoms
222		geomn=1
223		while [ $geomn -le $ngeoms ]; do
224			f_struct_free ${class}_geom_$geomn
225			geomn=$(( $geomn + 1 ))
226		done
227		classn=$(( $classn + 1 ))
228	done
229	NGEOM_CLASSES=0
230}
231
232# f_geom_rescan
233#
234# Rescan all GEOMs - convenience function.
235#
236f_geom_rescan()
237{
238	f_geom_reset
239	f_geom_get_all
240}
241
242# f_geom_find $name [$type [$var_to_set]]
243#
244# Find one or more registered GEOMs by name, type, or both. Returns a space-
245# separated list of GEOMs matching the search criterion. The $type argument
246# should be the GEOM class (see $GEOM_CLASS_* variables in GLOBALS above).
247#
248# If $var_to_set is missing or NULL, the GEOM name(s) are printed to standard
249# out for capturing in a sub-shell (which is less-recommended because of
250# performance degredation; for example, when called in a loop).
251#
252f_geom_find()
253{
254	local __name="$1" __type="${2:-$GEOM_CLASS_ANY}" __var_to_set="$3"
255	local __classn=1 __class __class_name __ngeoms
256	local __geomn __geom __geom_name __found=
257	while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do
258		__class=geom_class_$__classn
259		$__class get name __class_name
260		if [ "$__type" != "$GEOM_CLASS_ANY" -a \
261		     "$__type" != "$__class_name" ]
262		then
263			__classn=$(( $__classn + 1 ))
264			continue
265		fi
266
267		__geomn=1
268		$__class get ngeoms __ngeoms || __ngeoms=0
269		while [ $__geomn -le $__ngeoms ]; do
270			__geom=${__class}_geom_$__geomn
271			$__geom get name __geom_name
272			[ "$__name" = "$__geom_name" -o ! "$__name" ] &&
273				__found="$__found $__geom"
274			__geomn=$(( $__geomn + 1 ))
275		done
276		__classn=$(( $__classn + 1 ))
277	done
278	if [ "$__var_to_set" ]; then
279		setvar "$__var_to_set" "${__found# }"
280	else
281		echo $__found
282	fi
283	[ "$__found" ] # Return status
284}
285
286# f_geom_find_by $prop $find [$type [$var_to_set]]
287#
288# Find GEOM-related struct where $prop of the struct is equal to $find. Returns
289# NULL or the name of the first GEOM struct to match. The $type argument should
290# be one of the following:
291#
292# 	NULL		Find any of the below
293# 	class		Find GEOM_CLASS struct
294# 	geom		Find GEOM_GEOM struct
295# 	consumer	Find GEOM_CONSUMER struct
296# 	provider	Find GEOM_PROVIDER struct
297#
298# The $prop argument can be any property of the given type of struct. Some
299# properties are common to all types (such as id) so the $type argument is
300# optional (allowing you to return any struct whose property matches $find).
301#
302# If $var_to_set is missing or NULL, the GEOM struct name is printed to
303# standard out for capturing in a sub-shell (which is less-recommended because
304# of performance degredation; for example when called in a loop).
305#
306f_geom_find_by()
307{
308	local __prop="$1" __find="$2" __type="$3" __var_to_set="$4"
309	local __classn=1 __class __ngeoms
310	local __geomn __geom __nitems
311	local __itype __itemn __item
312	local __value __found=
313
314	if [ ! "$__prop" ]; then
315		[ "$__var_to_set" ] && setvar "$__var_to_set" ""
316		return $FAILURE
317	fi
318
319	case "$__type" in
320	"") : OK ;;
321	class|GEOM_CLASS) __type=class ;;
322	geom|GEOM_GEOM) __type=geom ;;
323	consumer|GEOM_CONSUMER) __type=consumer ;;
324	provider|GEOM_PROVIDER) __type=provider ;;
325	*)
326		[ "$__var_to_set" ] && setvar "$__var_to_set" ""
327		return $FAILURE
328	esac
329
330	while [ $__classn -le ${NGEOM_CLASSES:-0} ]; do
331		__class=geom_class_$__classn
332
333		if [ "${__type:-class}" = "class" ]; then
334			$__class get "$__prop" __value || __value=
335			[ "$__value" = "$__find" ] && __found="$__class" break
336			[ "$__type" ] && __classn=$(( $__classn + 1 )) continue
337		fi
338
339		__geomn=1
340		$__class get ngeoms __ngeoms || __ngeoms=0
341		while [ $__geomn -le $__ngeoms ]; do
342			__geom=${__class}_geom_$__geomn
343
344			if [ "${__type:-geom}" = "geom" ]; then
345				$__geom get "$__prop" __value || __value=
346				[ "$__value" = "$__find" ] &&
347					__found="$__geom" break
348				[ "$__type" ] &&
349					__geomn=$(( $__geomn + 1 )) continue
350			fi
351
352			for __itype in ${__type:-consumer provider}; do
353				$__geom get n${__itype}s __nitems || continue
354				__itemn=1
355				while [ $__itemn -le $__nitems ]; do
356					__item=${__geom}_${__itype}_$__itemn
357
358					$__item get "$__prop" __value ||
359						__value=
360					[ "$__value" = "$__find" ] &&
361						__found="$__item" break
362					__itemn=$(( $__itemn + 1 ))
363				done
364				[ "$__found" ] && break
365			done
366			[ "$__found" ] && break
367			__geomn=$(( $__geomn + 1 ))
368		done
369		[ "$__found" ] && break
370		__classn=$(( $__classn + 1 ))
371	done
372	if [ "$__var_to_set" ]; then
373		setvar "$__var_to_set" "$__found"
374	else
375		[ "$__found" ] && echo "$__found"
376	fi
377	[ "$__found" ] # Return status
378}
379
380# f_geom_parent $geom|$consumer|$provider|$config [$var_to_set]
381#
382# Get the GEOM class associated with one of $geom, $consumer, $provider or
383# $config.
384#
385# If $var_to_set is missing or NULL, the GEOM class name is printed to standard
386# out for capturing in a sub-shell (which is less-recommended because of
387# performance degredation; for example when called in a loop).
388#
389f_geom_parent()
390{
391	local __struct="$1" __var_to_set="$2"
392	# NB: Order of pattern matches below is important
393	case "$__struct" in
394	*_config*) __struct="${__struct%_config*}" ;;
395	*_consumer_*) __struct="${__struct%_consumer_[0-9]*}" ;;
396	*_provider_*) __struct="${__struct%_provider_[0-9]*}" ;;
397	*_geom_*) __struct="${__struct%_geom_[0-9]*}" ;;
398	*) __struct=
399	esac
400	if [ "$__var_to_set" ]; then
401		setvar "$__var_to_set" "$__struct"
402	else
403		echo "$__struct"
404	fi
405	f_struct "$__struct" # Return status
406}
407
408############################################################ MAIN
409
410#
411# Parse GEOM configuration unless requested otherwise
412#
413f_dprintf "%s: GEOM_SELF_SCAN_ALL=[%s]" geom.subr "$GEOM_SELF_SCAN_ALL"
414case "$GEOM_SELF_SCAN_ALL" in
415""|0|[Nn][Oo]|[Oo][Ff][Ff]|[Ff][Aa][Ll][Ss][Ee]) : do nothing ;;
416*)
417	f_geom_get_all
418	if [ "$debug" ]; then
419		debug= f_geom_find "" "$GEOM_CLASS_ANY" geoms
420		f_count ngeoms $geoms
421		f_dprintf "%s: Initialized %u geom devices in %u classes." \
422		          geom.subr "$ngeoms" "$NGEOM_CLASSES"
423		unset geoms ngeoms
424	fi
425esac
426
427f_dprintf "%s: Successfully loaded." geom.subr
428
429fi # ! $_GEOM_SUBR
430