]> sourceware.org Git - lvm2.git/blame - scripts/fsadm.sh
update reworded string
[lvm2.git] / scripts / fsadm.sh
CommitLineData
75153387 1#!/bin/bash
f29e7ac5 2#
829fe014 3# Copyright (C) 2007-2010 Red Hat, Inc. All rights reserved.
f29e7ac5
AK
4#
5# This file is part of LVM2.
6#
7# This copyrighted material is made available to anyone wishing to use,
8# modify, copy, or redistribute it subject to the terms and conditions
9# of the GNU General Public License v.2.
10#
11# You should have received a copy of the GNU General Public License
12# along with this program; if not, write to the Free Software Foundation,
13# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14#
50c41b09 15# Author: Zdenek Kabelac <zkabelac at redhat.com>
f29e7ac5
AK
16#
17# Script for resizing devices (usable for LVM resize)
18#
19# Needed utilities:
20# mount, umount, grep, readlink, blockdev, blkid, fsck, xfs_check
21#
cd96532e 22# ext2/ext3/ext4: resize2fs, tune2fs
f29e7ac5
AK
23# reiserfs: resize_reiserfs, reiserfstune
24# xfs: xfs_growfs, xfs_info
25#
4886fa21
ZK
26# Return values:
27# 0 success
28# 1 error
29# 2 break detected
30# 3 unsupported online filesystem check for given mounted fs
f29e7ac5
AK
31
32TOOL=fsadm
33
53c09bce 34_SAVEPATH=$PATH
f29e7ac5
AK
35PATH=/sbin:/usr/sbin:/bin:/usr/sbin:$PATH
36
37# utilities
38TUNE_EXT=tune2fs
39RESIZE_EXT=resize2fs
40TUNE_REISER=reiserfstune
41RESIZE_REISER=resize_reiserfs
42TUNE_XFS=xfs_info
43RESIZE_XFS=xfs_growfs
44
45MOUNT=mount
46UMOUNT=umount
47MKDIR=mkdir
50c41b09
ZK
48RMDIR=rmdir
49BLOCKDEV=blockdev
50BLKID=blkid
f0fffb8c 51DATE=date
f29e7ac5
AK
52GREP=grep
53READLINK=readlink
9ad2ba2a 54READLINK_E="-e"
f29e7ac5
AK
55FSCK=fsck
56XFS_CHECK=xfs_check
57
33048414 58# user may override lvm location by setting LVM_BINARY
0d9ed7ad 59LVM=${LVM_BINARY:-lvm}
17dd04ca 60
685940c0 61YES=${_FSADM_YES}
f29e7ac5 62DRY=0
17dd04ca 63VERB=
f29e7ac5
AK
64FORCE=
65EXTOFF=0
17dd04ca 66DO_LVRESIZE=0
f29e7ac5
AK
67FSTYPE=unknown
68VOLUME=unknown
69TEMPDIR="${TMPDIR:-/tmp}/${TOOL}_${RANDOM}$$/m"
8f8c5580 70DM_DEV_DIR="${DM_DEV_DIR:-/dev}"
f29e7ac5
AK
71BLOCKSIZE=
72BLOCKCOUNT=
73MOUNTPOINT=
74MOUNTED=
75REMOUNT=
55b94bf3 76PROCMOUNTS="/proc/mounts"
8f8c5580 77NULL="$DM_DEV_DIR/null"
f29e7ac5
AK
78
79IFS_OLD=$IFS
33048414
ZK
80# without bash $'\n'
81NL='
82'
f29e7ac5
AK
83
84tool_usage() {
d7b5bfc2
AK
85 echo "${TOOL}: Utility to resize or check the filesystem on a device"
86 echo
87 echo " ${TOOL} [options] check device"
88 echo " - Check the filesystem on device using fsck"
89 echo
50c41b09 90 echo " ${TOOL} [options] resize device [new_size[BKMGTPE]]"
d7b5bfc2
AK
91 echo " - Change the size of the filesystem on device to new_size"
92 echo
93 echo " Options:"
94 echo " -h | --help Show this help message"
95 echo " -v | --verbose Be verbose"
cd96532e 96 echo " -e | --ext-offline unmount filesystem before ext2/ext3/ext4 resize"
d7b5bfc2
AK
97 echo " -f | --force Bypass sanity checks"
98 echo " -n | --dry-run Print commands without running them"
17dd04ca 99 echo " -l | --lvresize Resize given device (if it is LVM device)"
d7b5bfc2
AK
100 echo " -y | --yes Answer \"yes\" at any prompts"
101 echo
102 echo " new_size - Absolute number of filesystem blocks to be in the filesystem,"
103 echo " or an absolute size using a suffix (in powers of 1024)."
104 echo " If new_size is not supplied, the whole device is used."
105
f29e7ac5
AK
106 exit
107}
108
109verbose() {
17dd04ca 110 test -n "$VERB" && echo "$TOOL: $@" || true
f29e7ac5
AK
111}
112
113error() {
114 echo "$TOOL: $@" >&2
115 cleanup 1
116}
117
118dry() {
50c41b09
ZK
119 if [ "$DRY" -ne 0 ]; then
120 verbose "Dry execution $@"
121 return 0
122 fi
f29e7ac5 123 verbose "Executing $@"
f29e7ac5
AK
124 $@
125}
126
127cleanup() {
128 trap '' 2
129 # reset MOUNTPOINT - avoid recursion
130 test "$MOUNTPOINT" = "$TEMPDIR" && MOUNTPOINT="" temp_umount
131 if [ -n "$REMOUNT" ]; then
132 verbose "Remounting unmounted filesystem back"
d2010960 133 dry "$MOUNT" "$VOLUME" "$MOUNTED"
f29e7ac5
AK
134 fi
135 IFS=$IFS_OLD
136 trap 2
17dd04ca 137
4886fa21
ZK
138 test "$1" -eq 2 && verbose "Break detected"
139
fd867543
ZK
140 if [ "$DO_LVRESIZE" -eq 2 ]; then
141 # start LVRESIZE with the filesystem modification flag
142 # and allow recursive call of fsadm
685940c0
ZK
143 _FSADM_YES=$YES
144 export _FSADM_YES
fd867543 145 unset FSADM_RUNNING
53c09bce 146 test -n "$LVM_BINARY" && PATH=$_SAVEPATH
d2010960 147 dry exec "$LVM" lvresize $VERB $FORCE -r -L${NEWSIZE}b "$VOLUME_ORIG"
fd867543 148 fi
53c09bce 149
829fe014
ZK
150 # error exit status for break
151 exit ${1:-1}
f29e7ac5
AK
152}
153
50c41b09
ZK
154# convert parameter from Exa/Peta/Tera/Giga/Mega/Kilo/Bytes and blocks
155# (2^(60/50/40/30/20/10/0))
f29e7ac5
AK
156decode_size() {
157 case "$1" in
50c41b09
ZK
158 *[eE]) NEWSIZE=$(( ${1%[eE]} * 1152921504606846976 )) ;;
159 *[pP]) NEWSIZE=$(( ${1%[pP]} * 1125899906842624 )) ;;
f29e7ac5
AK
160 *[tT]) NEWSIZE=$(( ${1%[tT]} * 1099511627776 )) ;;
161 *[gG]) NEWSIZE=$(( ${1%[gG]} * 1073741824 )) ;;
162 *[mM]) NEWSIZE=$(( ${1%[mM]} * 1048576 )) ;;
163 *[kK]) NEWSIZE=$(( ${1%[kK]} * 1024 )) ;;
164 *[bB]) NEWSIZE=${1%[bB]} ;;
165 *) NEWSIZE=$(( $1 * $2 )) ;;
166 esac
167 #NEWBLOCKCOUNT=$(round_block_size $NEWSIZE $2)
168 NEWBLOCKCOUNT=$(( $NEWSIZE / $2 ))
17dd04ca
ZK
169
170 if [ $DO_LVRESIZE -eq 1 ]; then
171 # start lvresize, but first cleanup mounted dirs
172 DO_LVRESIZE=2
173 cleanup 0
174 fi
f29e7ac5
AK
175}
176
177# detect filesystem on the given device
178# dereference device name if it is symbolic link
179detect_fs() {
55b94bf3 180 VOLUME_ORIG=$1
8f8c5580
ZK
181 VOLUME=${1/#"${DM_DEV_DIR}/"/}
182 VOLUME=$("$READLINK" $READLINK_E "$DM_DEV_DIR/$VOLUME") || error "Cannot get readlink \"$1\""
55b94bf3
ZK
183 RVOLUME=$VOLUME
184 case "$RVOLUME" in
8f8c5580 185 # hardcoded /dev since udev does not create these entries elsewhere
55b94bf3 186 /dev/dm-[0-9]*)
8f8c5580 187 read </sys/block/${RVOLUME#/dev/}/dm/name SYSVOLUME 2>&1 && VOLUME="$DM_DEV_DIR/mapper/$SYSVOLUME"
55b94bf3
ZK
188 ;;
189 esac
8f8c5580 190 # use null device as cache file to be sure about the result
284f4496 191 # not using option '-o value' to be compatible with older version of blkid
8f8c5580 192 FSTYPE=$("$BLKID" -c "$NULL" -s TYPE "$VOLUME") || error "Cannot get FSTYPE of \"$VOLUME\""
284f4496
ZK
193 FSTYPE=${FSTYPE##*TYPE=\"} # cut quotation marks
194 FSTYPE=${FSTYPE%%\"*}
f29e7ac5
AK
195 verbose "\"$FSTYPE\" filesystem found on \"$VOLUME\""
196}
197
198# check if the given device is already mounted and where
55b94bf3 199# FIXME: resolve swap usage and device stacking
f29e7ac5 200detect_mounted() {
d2010960 201 test -e "$PROCMOUNTS" || error "Cannot detect mounted device \"$VOLUME\""
55b94bf3 202
d2010960 203 MOUNTED=$("$GREP" ^"$VOLUME" "$PROCMOUNTS")
55b94bf3
ZK
204
205 # for empty string try again with real volume name
d2010960 206 test -z "$MOUNTED" && MOUNTED=$("$GREP" ^"$RVOLUME" "$PROCMOUNTS")
55b94bf3
ZK
207
208 # cut device name prefix and trim everything past mountpoint
209 # echo translates \040 to spaces
210 MOUNTED=${MOUNTED#* }
211 MOUNTED=$(echo -n -e ${MOUNTED%% *})
a9d6333b
ZK
212
213 # for systems with different device names - check also mount output
214 if test -z "$MOUNTED" ; then
d2010960
ZK
215 MOUNTED=$(LANG=C "$MOUNT" | "$GREP" ^"$VOLUME")
216 test -z "$MOUNTED" && MOUNTED=$(LANG=C "$MOUNT" | "$GREP" ^"$RVOLUME")
a9d6333b
ZK
217 MOUNTED=${MOUNTED##* on }
218 MOUNTED=${MOUNTED% type *} # allow type in the mount name
219 fi
220
f29e7ac5
AK
221 test -n "$MOUNTED"
222}
223
224# get the full size of device in bytes
225detect_device_size() {
9ad2ba2a 226 # check if blockdev supports getsize64
8f8c5580 227 "$BLOCKDEV" 2>&1 | "$GREP" getsize64 >"$NULL"
c8669f6b 228 if test $? -eq 0; then
d2010960 229 DEVSIZE=$("$BLOCKDEV" --getsize64 "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
9ad2ba2a 230 else
d2010960
ZK
231 DEVSIZE=$("$BLOCKDEV" --getsize "$VOLUME") || error "Cannot read size of device \"$VOLUME\""
232 SSSIZE=$("$BLOCKDEV" --getss "$VOLUME") || error "Cannot block size read device \"$VOLUME\""
9ad2ba2a
ZK
233 DEVSIZE=$(($DEVSIZE * $SSSIZE))
234 fi
f29e7ac5
AK
235}
236
237# round up $1 / $2
238# could be needed to gaurantee 'at least given size'
239# but it makes many troubles
240round_up_block_size() {
241 echo $(( ($1 + $2 - 1) / $2 ))
242}
243
244temp_mount() {
d2010960
ZK
245 dry "$MKDIR" -p -m 0000 "$TEMPDIR" || error "Failed to create $TEMPDIR"
246 dry "$MOUNT" "$VOLUME" "$TEMPDIR" || error "Failed to mount $TEMPDIR"
f29e7ac5
AK
247}
248
249temp_umount() {
d2010960
ZK
250 dry "$UMOUNT" "$TEMPDIR" || error "Failed to umount \"$TEMPDIR\""
251 dry "$RMDIR" "${TEMPDIR}" || error "Failed to remove \"$TEMPDIR\""
252 dry "$RMDIR" "${TEMPDIR%%m}" || error "Failed to remove \"${TEMPDIR%%m}\""
f29e7ac5
AK
253}
254
255yes_no() {
256 echo -n "$@? [Y|n] "
c8669f6b 257
f29e7ac5 258 if [ -n "$YES" ]; then
c8669f6b 259 echo y ; return 0
f29e7ac5 260 fi
c8669f6b
ZK
261
262 while read -r -s -n 1 ANS ; do
263 case "$ANS" in
264 "y" | "Y" | "") echo y ; return 0 ;;
265 "n" | "N") echo n ; return 1 ;;
266 esac
267 done
f29e7ac5
AK
268}
269
270try_umount() {
d2010960 271 yes_no "Do you want to unmount \"$MOUNTED\"" && dry "$UMOUNT" "$MOUNTED" && return 0
3a6e5f36 272 error "Cannot proceed with mounted filesystem \"$MOUNTED\""
f29e7ac5
AK
273}
274
275validate_parsing() {
276 test -n "$BLOCKSIZE" -a -n "$BLOCKCOUNT" || error "Cannot parse $1 output"
277}
278####################################
cd96532e 279# Resize ext2/ext3/ext4 filesystem
f29e7ac5
AK
280# - unmounted or mounted for upsize
281# - unmounted for downsize
282####################################
283resize_ext() {
284 verbose "Parsing $TUNE_EXT -l \"$VOLUME\""
d2010960 285 for i in $(LANG=C "$TUNE_EXT" -l "$VOLUME"); do
f29e7ac5
AK
286 case "$i" in
287 "Block size"*) BLOCKSIZE=${i##* } ;;
288 "Block count"*) BLOCKCOUNT=${i##* } ;;
289 esac
290 done
d2010960 291 validate_parsing "$TUNE_EXT"
f29e7ac5
AK
292 decode_size $1 $BLOCKSIZE
293 FSFORCE=$FORCE
294
50c41b09 295 if [ "$NEWBLOCKCOUNT" -lt "$BLOCKCOUNT" -o "$EXTOFF" -eq 1 ]; then
f29e7ac5
AK
296 detect_mounted && verbose "$RESIZE_EXT needs unmounted filesystem" && try_umount
297 REMOUNT=$MOUNTED
a9d6333b
ZK
298 if test -n "$MOUNTED" ; then
299 # Forced fsck -f for umounted extX filesystem.
300 case "$-" in
d2010960
ZK
301 *i*) dry "$FSCK" $YES -f "$VOLUME" ;;
302 *) dry "$FSCK" -f -p "$VOLUME" ;;
a9d6333b
ZK
303 esac
304 fi
f29e7ac5
AK
305 fi
306
c8669f6b 307 verbose "Resizing filesystem on device \"$VOLUME\" to $NEWSIZE bytes ($BLOCKCOUNT -> $NEWBLOCKCOUNT blocks of $BLOCKSIZE bytes)"
d2010960 308 dry "$RESIZE_EXT" $FSFORCE "$VOLUME" $NEWBLOCKCOUNT
f29e7ac5
AK
309}
310
311#############################
312# Resize reiserfs filesystem
313# - unmounted for upsize
314# - unmounted for downsize
315#############################
316resize_reiser() {
c8669f6b
ZK
317 detect_mounted && verbose "ReiserFS resizes only unmounted filesystem" && try_umount
318 REMOUNT=$MOUNTED
f29e7ac5 319 verbose "Parsing $TUNE_REISER \"$VOLUME\""
d2010960 320 for i in $(LANG=C "$TUNE_REISER" "$VOLUME"); do
f29e7ac5
AK
321 case "$i" in
322 "Blocksize"*) BLOCKSIZE=${i##*: } ;;
323 "Count of blocks"*) BLOCKCOUNT=${i##*: } ;;
324 esac
325 done
d2010960 326 validate_parsing "$TUNE_REISER"
f29e7ac5
AK
327 decode_size $1 $BLOCKSIZE
328 verbose "Resizing \"$VOLUME\" $BLOCKCOUNT -> $NEWBLOCKCOUNT blocks ($NEWSIZE bytes, bs: $NEWBLOCKCOUNT)"
329 if [ -n "$YES" ]; then
d2010960 330 echo y | dry "$RESIZE_REISER" -s $NEWSIZE "$VOLUME"
f29e7ac5 331 else
d2010960 332 dry "$RESIZE_REISER" -s $NEWSIZE "$VOLUME"
f29e7ac5
AK
333 fi
334}
335
336########################
337# Resize XFS filesystem
338# - mounted for upsize
3a6e5f36 339# - cannot downsize
f29e7ac5
AK
340########################
341resize_xfs() {
342 detect_mounted
343 MOUNTPOINT=$MOUNTED
344 if [ -z "$MOUNTED" ]; then
345 MOUNTPOINT=$TEMPDIR
346 temp_mount || error "Cannot mount Xfs filesystem"
347 fi
348 verbose "Parsing $TUNE_XFS \"$MOUNTPOINT\""
d2010960 349 for i in $(LANG=C "$TUNE_XFS" "$MOUNTPOINT"); do
f29e7ac5
AK
350 case "$i" in
351 "data"*) BLOCKSIZE=${i##*bsize=} ; BLOCKCOUNT=${i##*blocks=} ;;
352 esac
353 done
354 BLOCKSIZE=${BLOCKSIZE%%[^0-9]*}
355 BLOCKCOUNT=${BLOCKCOUNT%%[^0-9]*}
d2010960 356 validate_parsing "$TUNE_XFS"
f29e7ac5
AK
357 decode_size $1 $BLOCKSIZE
358 if [ $NEWBLOCKCOUNT -gt $BLOCKCOUNT ]; then
359 verbose "Resizing Xfs mounted on \"$MOUNTPOINT\" to fill device \"$VOLUME\""
d2010960 360 dry "$RESIZE_XFS" $MOUNTPOINT
f29e7ac5
AK
361 elif [ $NEWBLOCKCOUNT -eq $BLOCKCOUNT ]; then
362 verbose "Xfs filesystem already has the right size"
363 else
364 error "Xfs filesystem shrinking is unsupported"
365 fi
366}
367
368####################
369# Resize filesystem
370####################
371resize() {
17dd04ca 372 NEWSIZE=$2
f29e7ac5
AK
373 detect_fs "$1"
374 detect_device_size
c8669f6b 375 verbose "Device \"$VOLUME\" size is $DEVSIZE bytes"
f29e7ac5 376 # if the size parameter is missing use device size
17dd04ca 377 #if [ -n "$NEWSIZE" -a $NEWSIZE <
50c41b09 378 test -z "$NEWSIZE" && NEWSIZE=${DEVSIZE}b
33048414 379 IFS=$NL
f29e7ac5 380 case "$FSTYPE" in
cd96532e 381 "ext3"|"ext2"|"ext4") resize_ext $NEWSIZE ;;
f29e7ac5
AK
382 "reiserfs") resize_reiser $NEWSIZE ;;
383 "xfs") resize_xfs $NEWSIZE ;;
384 *) error "Filesystem \"$FSTYPE\" on device \"$VOLUME\" is not supported by this tool" ;;
385 esac || error "Resize $FSTYPE failed"
17dd04ca 386 cleanup 0
f29e7ac5
AK
387}
388
a9d6333b
ZK
389####################################
390# Calclulate diff between two dates
391# LANG=C input is expected the
392# only one supported
393####################################
394diff_dates() {
8f8c5580 395 echo $(( $("$DATE" -u -d"$1" +%s 2>"$NULL") - $("$DATE" -u -d"$2" +%s 2>"$NULL") ))
a9d6333b
ZK
396}
397
f29e7ac5
AK
398###################
399# Check filesystem
400###################
401check() {
402 detect_fs "$1"
4886fa21
ZK
403 if detect_mounted ; then
404 verbose "Skipping filesystem check for device \"$VOLUME\" as the filesystem is mounted on $MOUNTED";
405 cleanup 3
406 fi
a9d6333b
ZK
407
408 case "$FSTYPE" in
409 "ext2"|"ext3"|"ext4")
410 IFS_CHECK=$IFS
411 IFS=$NL
d2010960 412 for i in $(LANG=C "$TUNE_EXT" -l "$VOLUME"); do
a9d6333b
ZK
413 case "$i" in
414 "Last mount"*) LASTMOUNT=${i##*: } ;;
415 "Last checked"*) LASTCHECKED=${i##*: } ;;
416 esac
417 done
418 case "$LASTMOUNT" in
419 *"n/a") ;; # nothing to do - system was not mounted yet
420 *)
421 LASTDIFF=$(diff_dates $LASTMOUNT $LASTCHECKED)
422 if test "$LASTDIFF" -gt 0 ; then
423 verbose "Filesystem has not been checked after the last mount, using fsck -f"
424 FORCE="-f"
425 fi
426 ;;
427 esac
428 IFS=$IFS_CHECK
429 esac
430
f29e7ac5 431 case "$FSTYPE" in
d2010960 432 "xfs") dry "$XFS_CHECK" "$VOLUME" ;;
bd79af9f
ZK
433 *) # check if executed from interactive shell environment
434 case "$-" in
d2010960
ZK
435 *i*) dry "$FSCK" $YES $FORCE "$VOLUME" ;;
436 *) dry "$FSCK" $FORCE -p "$VOLUME" ;;
bd79af9f 437 esac
f29e7ac5
AK
438 esac
439}
440
441#############################
442# start point of this script
443# - parsing parameters
444#############################
4886fa21 445trap "cleanup 2" 2
50c41b09 446
17dd04ca
ZK
447# test if we are not invoked recursively
448test -n "$FSADM_RUNNING" && exit 0
449
50c41b09
ZK
450# test some prerequisities
451test -n "$TUNE_EXT" -a -n "$RESIZE_EXT" -a -n "$TUNE_REISER" -a -n "$RESIZE_REISER" \
452 -a -n "$TUNE_XFS" -a -n "$RESIZE_XFS" -a -n "$MOUNT" -a -n "$UMOUNT" -a -n "$MKDIR" \
453 -a -n "$RMDIR" -a -n "$BLOCKDEV" -a -n "$BLKID" -a -n "$GREP" -a -n "$READLINK" \
dd96ceda 454 -a -n "$DATE" -a -n "$FSCK" -a -n "$XFS_CHECK" -a -n "$LVM" \
17dd04ca 455 || error "Required command definitions in the script are missing!"
9ad2ba2a 456
8f8c5580
ZK
457"$LVM" version >"$NULL" 2>&1 || error "Could not run lvm binary \"$LVM\""
458$("$READLINK" -e / >"$NULL" 2>&1) || READLINK_E="-f"
50c41b09 459TEST64BIT=$(( 1000 * 1000000000000 ))
d2010960 460test "$TEST64BIT" -eq 1000000000000000 || error "Shell does not handle 64bit arithmetic"
8f8c5580 461$(echo Y | "$GREP" Y >"$NULL") || error "Grep does not work properly"
d2010960 462test $("$DATE" -u -d"Jan 01 00:00:01 1970" +%s) -eq 1 || error "Date translation does not work"
50c41b09
ZK
463
464
c8669f6b 465if [ "$#" -eq 0 ] ; then
f29e7ac5
AK
466 tool_usage
467fi
468
c8669f6b 469while [ "$#" -ne 0 ]
f29e7ac5 470do
c8669f6b
ZK
471 case "$1" in
472 "") ;;
473 "-h"|"--help") tool_usage ;;
474 "-v"|"--verbose") VERB="-v" ;;
475 "-n"|"--dry-run") DRY=1 ;;
476 "-f"|"--force") FORCE="-f" ;;
477 "-e"|"--ext-offline") EXTOFF=1 ;;
478 "-y"|"--yes") YES="-y" ;;
479 "-l"|"--lvresize") DO_LVRESIZE=1 ;;
480 "check") CHECK="$2" ; shift ;;
481 "resize") RESIZE="$2"; NEWSIZE="$3" ; shift 2 ;;
482 *) error "Wrong argument \"$1\". (see: $TOOL --help)"
f29e7ac5
AK
483 esac
484 shift
485done
486
487if [ -n "$CHECK" ]; then
488 check "$CHECK"
489elif [ -n "$RESIZE" ]; then
17dd04ca 490 export FSADM_RUNNING="fsadm"
f29e7ac5
AK
491 resize "$RESIZE" "$NEWSIZE"
492else
493 error "Missing command. (see: $TOOL --help)"
494fi
This page took 0.117584 seconds and 5 git commands to generate.