On Thu, 9 Aug 2012 10:59:20 -0400
Joey Hess <joeyh@debian.org> wrote:
> I hate to bring this news, but this cannot be used in the installer,
> because shell arrays are a bashism, and the installer uses busybox sh.
Thanks for pointing that out. It seems that shell arrays are more of a
ksh-ism; see the manual page for mksh(1). I did try to avoid obvious
bashisms, but I didn't know that Bourne shell doesn't have arrays, or
that its arithmetic was so crippled.
Fixed now; I've tested this version with busybox, and it seems to work
fine. See attachments.
checksums:
425334e865579c218e15f66fa018dd50 partman-base_158.diff
0e38d0168a14c42cccd24857c0fd219c cvt.sh
> FWIW, it is possible, though painful to emulate shell arrays using
> eval, or other tricks.
I'll remember that trick; it will be useful sometime. In this case, the
arrays are read-only, so a case statement wrapped up in a function will
do fine. Arrays are just functions on a subset of integers, anyway.
As a special bonus, this version outputs "KiB", "MiB", etc, when
operating in binary mode.
As an extra special bonus, it now has support for {peta,pebi}bytes, just
in case somebody wants to set up an array of 400 three-terabyte disks.
Unfortunately, this isn't currently working, apparently because of
64-bit arithmetic overflows in "expr". (Isn't that what "expr" is
supposed to avoid?)
For those who don't care, a decimal petabyte is only 8/9 of a binary
pebibyte.
-- Ian Bruce
--- partman-base-158/lib/base.sh.orig 2012-01-03 07:49:51.000000000 -0800
+++ partman-base-158/lib/base.sh 2012-08-10 00:55:43.000000000 -0700
@@ -278,110 +278,142 @@
else
return 1
fi
}
+name_units ()
+{
+ local n=$1 s
+ if [ "$USE_BINARY_UNITS" ]
+ then
+ case $n in
+ 0) s=B ;;
+ 1) s=KiB ;;
+ 2) s=MiB ;;
+ 3) s=GiB ;;
+ 4) s=TiB ;;
+ 5) s=PiB ;;
+ esac
+ else
+ case $n in
+ 0) s=B ;;
+ 1) s=kB ;;
+ 2) s=MB ;;
+ 3) s=GB ;;
+ 4) s=TB ;;
+ 5) s=PB ;;
+ esac
+ fi
+ echo $s
+}
+
+disk_units ()
+{
+ local n=$1 r
+ if [ "$USE_BINARY_UNITS" ]
+ then
+ case $n in # (2^10)^{0,1,2,3,4,5}
+ 0) r=1 ;;
+ 1) r=1024 ;;
+ 2) r=1048576 ;;
+ 3) r=1073741824 ;;
+ 4) r=1099511627776 ;;
+ 5) r=1125899906842624 ;;
+ esac
+ else
+ case $n in # (10^3)^{0,1,2,3,4,5}
+ 0) r=1 ;;
+ 1) r=1000 ;;
+ 2) r=1000000 ;;
+ 3) r=1000000000 ;;
+ 4) r=1000000000000 ;;
+ 5) r=1000000000000000 ;;
+ esac
+ fi
+ echo $r
+}
+
longint2human () {
- local longint suffix bytes int frac deci
+ local longint radix bytes int frac deci exp
# fallback value for $deci:
deci="${deci:-.}"
- case ${#1} in
- 1|2|3)
- suffix=B
- longint=${1}00
- ;;
- 4|5|6)
- suffix=kB
- longint=${1%?}
- ;;
- 7|8|9)
- suffix=MB
- longint=${1%????}
- ;;
- 10|11|12)
- suffix=GB
- longint=${1%???????}
- ;;
- *)
- suffix=TB
- longint=${1%??????????}
- ;;
- esac
- longint=$(($longint + 5))
- longint=${longint%?}
- int=${longint%?}
- frac=${longint#$int}
- printf "%i%s%i %s\n" $int $deci $frac $suffix
+ bytes=$1
+ exp=6 # possible units
+ while [ $exp -gt 0 ]
+ do
+ exp=$((exp-1))
+ radix=$(disk_units $exp)
+# expr $bytes ">=" $radix >/dev/null && break
+ expr 1000 \* $bytes ">=" 995 \* $radix >/dev/null && break
+ done
+ longint=$(expr $bytes \* 1000 + $radix \* 5)
+ int=$(expr $longint / \( $radix \* 1000 \) )
+ frac=$(expr $longint % \( $radix \* 1000 \) / \( $radix \* 10 \) )
+ if [ $exp -gt 0 ]
+ then
+ printf "%i%s%02i %s\n" $int $deci $frac $(name_units $exp)
+ else
+ printf "%i %s\n" $int $(name_units $exp)
+ fi
}
human2longint () {
- local human orighuman gotb suffix int frac longint
+ local human orighuman gotb suffix int frac longint exp
set -- $*; human="$1$2$3$4$5" # without the spaces
orighuman="$human"
human=${human%b} #remove last b
human=${human%B} #remove last B
gotb=''
if [ "$human" != "$orighuman" ]; then
gotb=1
fi
suffix=${human#${human%?}} # the last symbol of $human
case $suffix in
- k|K|m|M|g|G|t|T)
+ k|K|m|M|g|G|t|T|p|P)
human=${human%$suffix}
;;
*)
if [ "$gotb" ]; then
suffix=B
else
- suffix=''
+ suffix=M # default to megabytes
fi
;;
esac
int="${human%[.,]*}"
[ "$int" ] || int=0
frac=${human#$int}
frac="${frac#[.,]}0000" # to be sure there are at least 4 digits
frac=${frac%${frac#????}} # only the first 4 digits of $frac
- longint=$(expr "$int" \* 10000 + "$frac")
+ longint=$(expr $int \* 10000 + $frac)
case $suffix in
b|B)
- longint=${longint%????}
- [ "$longint" ] || longint=0
- ;;
+ exp=0 ;;
k|K)
- longint=${longint%?}
- ;;
+ exp=1 ;;
m|M)
- longint=${longint}00
- ;;
+ exp=2 ;;
g|G)
- longint=${longint}00000
- ;;
+ exp=3 ;;
t|T)
- longint=${longint}00000000
- ;;
- *) # no suffix:
- # bytes
- #longint=${longint%????}
- #[ "$longint" ] || longint=0
- # megabytes
- longint=${longint}00
- ;;
+ exp=4 ;;
+ p|P)
+ exp=5 ;;
esac
- echo $longint
+ expr $longint \* $(disk_units $exp) / 10000
}
valid_human () {
local IFS patterns
patterns='[0-9][0-9]* *$
[0-9][0-9]* *[bB] *$
-[0-9][0-9]* *[kKmMgGtT] *$
-[0-9][0-9]* *[kKmMgGtT][bB] *$
+[0-9][0-9]* *[kKmMgGtTpP] *$
+[0-9][0-9]* *[kKmMgGtTpP][bB] *$
[0-9]*[.,][0-9]* *$
[0-9]*[.,][0-9]* *[bB] *$
-[0-9]*[.,][0-9]* *[kKmMgGtT] *$
-[0-9]*[.,][0-9]* *[kKmMgGtT][bB] *$'
+[0-9]*[.,][0-9]* *[kKmMgGtTpP] *$
+[0-9]*[.,][0-9]* *[kKmMgGtTpP][bB] *$'
IFS="$NL"
for regex in $patterns; do
if expr "$1" : "$regex" >/dev/null; then return 0; fi
done
return 1
Attachment:
cvt.sh
Description: application/shellscript