} \
} while (0)
+#define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
+
+/* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
+ * returns the value or ULONG_MAX on integer overflow or incorrect format
+ * Notes:
+ * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
+ * 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
+ * 3. empty integer value is interpreted as 0
+ */
+
+static unsigned long str2sec(const char* timestr) {
+ const char spec[] = "smhdw";
+ const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
+ unsigned long val = 0;
+ char *tail;
+
+ if (strpbrk(timestr, spec) == NULL) {
+ /* no specifiers inside the time string,
+ should treat it as an integer value */
+ val = strtoul(timestr, &tail, 10);
+ return *tail ? ULONG_MAX : val;
+ }
+
+ /* format string is XXwXXdXXhXXmXXs */
+ while (*timestr) {
+ unsigned long v;
+ int ind;
+ char* ptr;
+
+ v = strtoul(timestr, &tail, 10);
+ if (v == ULONG_MAX || *tail == '\0')
+ /* value too large (ULONG_MAX or more)
+ or missing specifier */
+ goto error;
+
+ ptr = strchr(spec, *tail);
+ if (ptr == NULL)
+ /* unknown specifier */
+ goto error;
+
+ ind = ptr - spec;
+
+ /* check if product will overflow the type */
+ if (!(v < ULONG_MAX / mult[ind]))
+ goto error;
+
+ ADD_OVERFLOW(val, mult[ind] * v);
+ if (val == ULONG_MAX)
+ goto error;
+
+ timestr = tail + 1;
+ }
+
+ return val;
+
+error:
+ return ULONG_MAX;
+}
+
int lfs_setquota(int argc, char **argv)
{
int c;
if (optind + 3 != argc)
return CMD_HELP;
- ARG2INT(dqi->dqi_bgrace, argv[optind++], "block-grace");
- ARG2INT(dqi->dqi_igrace, argv[optind++], "inode-grace");
+ if ((dqi->dqi_bgrace = str2sec(argv[optind++])) == ULONG_MAX) {
+ fprintf(stderr, "error: bad %s: %s\n", "block-grace", argv[optind - 1]);
+ return CMD_HELP;
+ }
+ if ((dqi->dqi_igrace = str2sec(argv[optind++])) == ULONG_MAX) {
+ fprintf(stderr, "error: bad %s: %s\n", "inode-grace", argv[optind - 1]);
+ return CMD_HELP;
+ }
}
mnt = argv[optind];
}
-static void grace2str(time_t seconds,char *buf)
+/* Converts seconds value into format string
+ * result is returned in buf
+ * Notes:
+ * 1. result is in descenting order: 1w2d3h4m5s
+ * 2. zero fields are not filled (except for p. 3): 5d1s
+ * 3. zero seconds value is presented as "0s"
+ */
+static void sec2str(time_t seconds, char *buf)
{
- uint minutes, hours, days;
-
- minutes = (seconds + 30) / 60;
- hours = minutes / 60;
- minutes %= 60;
- days = hours / 24;
- hours %= 24;
- if (days >= 2)
- snprintf(buf, 40, "%ddays", days);
- else
- snprintf(buf, 40, "%02d:%02d", hours + days * 24, minutes);
+ const char spec[] = "smhdw";
+ const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
+ unsigned long c;
+ char* tail = buf;
+ int i;
+
+ for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
+ c = seconds / mult[i];
+
+ if (c > 0 || (i == 0 && buf == tail))
+ tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
+
+ seconds %= mult[i];
+ }
}
strcpy(buf, "none");
return;
}
- grace2str(seconds - now, buf);
+ sec2str(seconds - now, buf);
}
static void print_quota_title(char *name, struct if_quotactl *qctl)
char bgtimebuf[40];
char igtimebuf[40];
- grace2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
- grace2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
+ sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
+ sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
printf("Block grace time: %s; Inode grace time: %s\n",
bgtimebuf, igtimebuf);
}