diff mbox

[nft,RFC] datatype: add time type parser and adapt output

Message ID 1389906062-27409-1-git-send-email-pablo@netfilter.org
State Accepted
Headers show

Commit Message

Pablo Neira Ayuso Jan. 16, 2014, 9:01 p.m. UTC
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(-)

Comments

Patrick McHardy Jan. 16, 2014, 9:05 p.m. UTC | #1
On Thu, Jan 16, 2014 at 10:01:02PM +0100, Pablo Neira Ayuso wrote:
> 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().

I think this is a much more natural way to specify relative times.

>  include/utils.h |    4 ++
>  src/datatype.c  |  133 ++++++++++++++++++++++++++++++++++++++++++++++++-------
>  2 files changed, 121 insertions(+), 16 deletions(-)
> 
> diff --git a/include/utils.h b/include/utils.h
> index 854986f..f23f8e6 100644
> --- a/include/utils.h
> +++ b/include/utils.h
> @@ -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

We have array_size().
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Patrick McHardy Jan. 16, 2014, 9:23 p.m. UTC | #2
Patrick McHardy <kaber@trash.net> schrieb:
>On Thu, Jan 16, 2014 at 10:01:02PM +0100, Pablo Neira Ayuso wrote:
>> 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().
>
>I think this is a much more natural way to specify relative times.

Sorry, just realized that this was very much imprecise, I meant your patch oft course.

>
>>  include/utils.h |    4 ++
>>  src/datatype.c  |  133
>++++++++++++++++++++++++++++++++++++++++++++++++-------
>>  2 files changed, 121 insertions(+), 16 deletions(-)
>> 
>> diff --git a/include/utils.h b/include/utils.h
>> index 854986f..f23f8e6 100644
>> --- a/include/utils.h
>> +++ b/include/utils.h
>> @@ -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
>
>We have array_size().
>--
>To unsubscribe from this list: send the line "unsubscribe
>netfilter-devel" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/utils.h b/include/utils.h
index 854986f..f23f8e6 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -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);
diff --git a/src/datatype.c b/src/datatype.c
index 4594490..0541fc0 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -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,