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