[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#684128: PATCH: choice of binary or decimal disk storage units is runtime-configurable



<odyx@debian.org> wrote:

> I don't think anyone is trying to avoid a proper resolution of this
> bug. So the people who care mostly (and know what a gibibyte is)
> should start working on patches if they really want to get this fixed;
> this work will not come magically out of the blue.

See attached patch, and code excerpt, for new versions of the functions
longint2human() and human2longint(), which implement both base-1000 and
base-1024 conversions to/from decimal, depending on a configuration
option.

MD5 checksums:
c75b7b8e66eff67f188fa18d328897ad  partman-base_158.diff
77d5ea04ee877a29cd9246d621156f0d  cvt.sh

Apart from the 2^(10*n) versus 10^(3*n) issue, this code improves on the
current version in the following respects:

- the longint2human() function produces a result with a precision of two
decimal places, rather than just one. This is consistent with what lvm,
mdadm, and parted do. This could be extended to any number of decimal
places with no code changes, just by altering a few constants.

- if the unit displayed is bytes, then the decimal places are omitted. 
There cannot be a fractional number of bytes allocated, so it makes no
sense to suggest this by printing a decimal point followed by zeros.

- the current code suffers from the following anomaly: longint2human()
maps the value 999999 to "1000.0 kB", and 1000000 to "1.0 MB". These
rounded values are equivalent, so they ought to be displayed the same
way. The new code maps the entire range [995000..1004999] to "1.00 MB",
and behaves analogously with other units.

- the new code is twelve lines shorter than the original.

By defining a single environment variable, the new code can be
configured to use the binary, rather than decimal, values of the
suffixes {K, M, G, T} for both input and output, while retaining the
above features.

*******

I take the point that it is not currently feasible to get translations
of new or changed text for the installer. What I propose is to apply
this small patch, and make no changes at all to any text. When operating
in decimal mode, the new code is functionally identical to the old,
apart from the improvements listed above. When operating in binary mode,
identical input text will simply be interpreted as s*(2^(10*n)) rather
than s*(10^(3*n)).

The choice of whether the partitioner operates in binary or decimal mode
can be controlled by a boot parameter, so as not to introduce any new
user-visible text into the installer.

http://www.debian.org/releases/stable/i386/ch05s03.html.en#installer-args

*******

Now we can all fight about whether the default partitioning mode should
be binary or decimal. I'm curious to hear why, if just about nobody
cares about the difference between 2^(10*n) and 10^(3*n), it would be
unacceptable to default to 2^(10*n), which is what just about everybody
who does care would expect.


-- 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-08 23:28:58.000000000 -0700
@@ -278,45 +278,44 @@
 	else
 		return 1
 	fi
 }
 
+suffix_units=(B kB MB GB TB)
+
+decimal_units=(1 1000 1000000 1000000000 1000000000000)  # (10^3)^{0,1,2,3,4}
+
+binary_units=(1 1024 1048576 1073741824 1099511627776)   # (2^10)^{0,1,2,3,4}
+
 longint2human () {
-	local longint suffix bytes int frac deci
+	local longint radix bytes int frac deci units 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
+	[ "$USE_BINARY_UNITS" ] && units=(${binary_units[*]}) \
+				|| units=(${decimal_units[*]})
+	bytes=$1
+	exp=${#units[*]}
+	while ((exp>0))
+	do
+		((exp-=1))
+		radix=${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>0))
+	then
+		printf "%i%s%02i %s\n" $int $deci $frac ${suffix_units[exp]}
+	else
+		printf "%i %s\n" $int ${suffix_units[exp]}
+	fi
 }
 
 human2longint () {
-	local human orighuman gotb suffix int frac longint
+	local human orighuman gotb suffix int frac longint units 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=''
@@ -330,46 +329,35 @@
 		;;
 	*)
 		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 ;;
 	esac
-	echo $longint
+	[ "$USE_BINARY_UNITS" ] && units=(${binary_units[*]}) \
+				|| units=(${decimal_units[*]})
+	expr $longint \* ${units[exp]} / 10000
 }
 
 valid_human () {
 	local IFS patterns
 	patterns='[0-9][0-9]* *$

Attachment: cvt.sh
Description: application/shellscript


Reply to: