summaryrefslogtreecommitdiff
path: root/quotasys.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2014-05-01 18:08:09 +0200
committerJan Kara <jack@suse.cz>2014-05-01 18:08:09 +0200
commit0214512479e04a3e118cbef8703aa1aec5240f3f (patch)
tree062986d6b72aaee00a90abb1fd0c2437667ab985 /quotasys.c
parentd8707e979a3797e416d53b11498fa430795b0ac0 (diff)
downloadlinuxquota-0214512479e04a3e118cbef8703aa1aec5240f3f.tar.gz
Properly handle signed space and inode values
For cluster filesystems, kernel can sometimes return negative values of used space or inodes (because counters are not completely synchronized across the cluster). Make quota tools properly print these. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'quotasys.c')
-rw-r--r--quotasys.c47
1 files changed, 31 insertions, 16 deletions
diff --git a/quotasys.c b/quotasys.c
index dee5118..120125a 100644
--- a/quotasys.c
+++ b/quotasys.c
@@ -376,6 +376,7 @@ int str2timeunits(time_t num, char *unit, time_t *res)
return 0;
}
+#define DIV_ROUND_UP(x, d) (((x) + d - 1) / d)
/*
* Convert number in quota blocks to some nice short form for printing
*/
@@ -383,18 +384,26 @@ void space2str(qsize_t space, char *buf, int format)
{
int i;
char suffix[8] = " MGT";
+ qsize_t aspace = space >= 0 ? space : -space;
space = qb2kb(space);
if (format) {
- for (i = 3; i > 0; i--)
- if (space >= (1LL << (QUOTABLOCK_BITS*i))*100) {
- sprintf(buf, "%llu%c", (unsigned long long)(space+(1 << (QUOTABLOCK_BITS*i))-1) >> (QUOTABLOCK_BITS*i), suffix[i]);
+ for (i = 3; i > 0; i--) {
+ long long unit = 1LL << (QUOTABLOCK_BITS*i);
+
+ if (aspace >= unit * 100) {
+ int sign = aspace != space ? -1 : 1;
+
+ sprintf(buf, "%lld%c", (long long)
+ DIV_ROUND_UP(aspace, unit) * sign,
+ suffix[i]);
return;
}
- sprintf(buf, "%lluK", (unsigned long long)space);
+ }
+ sprintf(buf, "%lldK", (long long)space);
return;
}
- sprintf(buf, "%llu", (unsigned long long)space);
+ sprintf(buf, "%lld", (long long)space);
}
/*
@@ -404,11 +413,11 @@ void space2str(qsize_t space, char *buf, int format)
const char *str2space(const char *string, qsize_t *space)
{
char *unit;
- unsigned long long int number;
+ long long int number;
int unit_shift;
- number = strtoull(string, &unit, 0);
- if (ULLONG_MAX == number)
+ number = strtoll(string, &unit, 0);
+ if (number == LLONG_MAX || number == LLONG_MIN)
return _("Integer overflow while parsing space number.");
if (!unit || unit[0] == '\0' || !strcmp(unit, _("K")))
@@ -422,7 +431,8 @@ const char *str2space(const char *string, qsize_t *space)
else
return _("Unknown space binary unit. "
"Valid units are K, M, G, T.");
- if (number > (QSIZE_MAX >> unit_shift))
+ if (number > (QSIZE_MAX >> unit_shift) ||
+ number < -(QSIZE_MAX >> unit_shift))
return _("Integer overflow while interpreting space unit.");
*space = number << unit_shift;
return NULL;
@@ -431,19 +441,23 @@ const char *str2space(const char *string, qsize_t *space)
/*
* Convert number to some nice short form for printing
*/
-void number2str(unsigned long long num, char *buf, int format)
+void number2str(long long num, char *buf, int format)
{
int i;
unsigned long long div;
char suffix[8] = " kmgt";
+ long long anum = num >= 0 ? num : -num;
if (format)
for (i = 4, div = 1000000000000LL; i > 0; i--, div /= 1000)
if (num >= 100*div) {
- sprintf(buf, "%llu%c", (num+div-1) / div, suffix[i]);
+ int sign = num != anum ? -1 : 1;
+
+ sprintf(buf, "%lld%c", (num+div-1) / div * sign,
+ suffix[i]);
return;
}
- sprintf(buf, "%llu", num);
+ sprintf(buf, "%lld", num);
}
/*
@@ -453,10 +467,10 @@ void number2str(unsigned long long num, char *buf, int format)
const char *str2number(const char *string, qsize_t *inodes)
{
char *unit;
- unsigned long long int number, multiple;
+ long long int number, multiple;
- number = strtoull(string, &unit, 0);
- if (ULLONG_MAX == number)
+ number = strtoll(string, &unit, 0);
+ if (number == LLONG_MAX || number == LLONG_MIN)
return _("Integer overflow while parsing number.");
if (!unit || unit[0] == '\0')
@@ -472,7 +486,8 @@ const char *str2number(const char *string, qsize_t *inodes)
else
return _("Unknown decimal unit. "
"Valid units are k, m, g, t.");
- if (number > QSIZE_MAX / multiple)
+ if (number > QSIZE_MAX / multiple ||
+ -number < QSIZE_MAX / multiple)
return _("Integer overflow while interpreting decimal unit.");
*inodes = number * multiple;
return NULL;