@@ -62,6 +62,10 @@
(void) (&_max1 == &_max2); \
_max1 > _max2 ? _max1 : _max2; })
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof((a)[0]))
+#endif
+
extern void memory_allocation_error(void) __noreturn;
extern void xfree(const void *ptr);
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
+#include <ctype.h> /* isdigit */
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
@@ -670,7 +671,6 @@ const struct datatype mark_type = {
static void time_type_print(const struct expr *expr)
{
uint64_t days, hours, minutes, seconds;
- const char *delim = "";
seconds = mpz_get_uint64(expr->value);
@@ -683,22 +683,122 @@ static void time_type_print(const struct expr *expr)
minutes = seconds / 60;
seconds %= 60;
- if (days > 0) {
- printf("%s%" PRIu64 " d", delim, days);
- delim = " ";
- }
- if (hours > 0) {
- printf("%s%" PRIu64 " h", delim, hours);
- delim = " ";
- }
- if (minutes > 0) {
- printf("%s%" PRIu64 " min", delim, minutes);
- delim = " ";
- }
- if (seconds > 0) {
- printf("%s%" PRIu64 " s", delim, seconds);
- delim = " ";
+ printf("\"");
+
+ if (days > 0)
+ printf("%"PRIu64"d", days);
+ if (hours > 0)
+ printf("%"PRIu64"h", hours);
+ if (minutes > 0)
+ printf("%"PRIu64"m", minutes);
+ if (seconds > 0)
+ printf("%"PRIu64"s", seconds);
+
+ printf("\"");
+}
+
+enum {
+ DAY = (1 << 0),
+ HOUR = (1 << 1),
+ MIN = (1 << 2),
+ SECS = (1 << 3),
+};
+
+static uint32_t str2int(char *tmp, const char *c, int k)
+{
+ if (k == 0)
+ return 0;
+
+ strncpy(tmp, c-k, k+1);
+ return atoi(tmp);
+}
+
+static struct error_record *time_type_parse(const struct expr *sym,
+ struct expr **res)
+{
+ int i, k = 0, len;
+ char tmp[8];
+ const char *c;
+ uint64_t d = 0, h = 0, m = 0, s = 0;
+ uint32_t mask = 0;
+
+ c = sym->identifier;
+ len = strlen(c);
+ for (i = 0; i < len; i++, c++) {
+ switch (*c) {
+ case 'd':
+ if (mask & DAY) {
+ return error(&sym->location,
+ "Day has been specified twice");
+ }
+ d = str2int(tmp, c, k);
+ k = 0;
+ mask |= DAY;
+ break;
+ case 'h':
+ if (mask & HOUR) {
+ return error(&sym->location,
+ "Hour has been specified twice");
+ }
+ h = str2int(tmp, c, k);
+ k = 0;
+ if (h > 23) {
+ return error(&sym->location,
+ "Hour needs to be 0-23");
+ }
+ mask |= HOUR;
+ break;
+ case 'm':
+ if (mask & MIN) {
+ return error(&sym->location,
+ "Minute has been specified twice");
+ }
+ m = str2int(tmp, c, k);
+ k = 0;
+ if (m > 59) {
+ return error(&sym->location,
+ "Minute needs to be 0-59");
+ }
+ mask |= MIN;
+ break;
+ case 's':
+ if (mask & SECS) {
+ return error(&sym->location,
+ "Second has been specified twice");
+ }
+ s = str2int(tmp, c, k);
+ k = 0;
+ if (s > 59) {
+ return error(&sym->location,
+ "second needs to be 0-59");
+ }
+ mask |= SECS;
+ break;
+ default:
+ if (!isdigit(*c))
+ return error(&sym->location, "wrong format");
+
+ if (k++ >= ARRAY_SIZE(tmp)) {
+ return error(&sym->location,
+ "value too large");
+ }
+ break;
+ }
}
+
+ /* default to seconds if no unit was specified */
+ if (!mask)
+ s = atoi(sym->identifier);
+ else
+ s = 24*60*60*d+60*60*h+60*m+s;
+
+ if (s > UINT32_MAX)
+ return error(&sym->location, "value too large");
+
+ *res = constant_expr_alloc(&sym->location, &time_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(uint32_t) * BITS_PER_BYTE, &s);
+ return NULL;
}
const struct datatype time_type = {
@@ -709,6 +809,7 @@ const struct datatype time_type = {
.size = 8 * BITS_PER_BYTE,
.basetype = &integer_type,
.print = time_type_print,
+ .parse = time_type_parse,
};
static struct error_record *concat_type_parse(const struct expr *sym,
This patch allows to specify a string to indicate the time, eg. nft add rule filter output ct expiration \"1d2h3m4s\" counter Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> --- An alternative to this patch is to use seconds as input/output, that only needs a smaller patch to fix time_type_print(). include/utils.h | 4 ++ src/datatype.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 121 insertions(+), 16 deletions(-)