summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2017-10-09 18:43:04 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2018-01-02 21:47:27 +0100
commitd71dd93599b932693f045301424c2276cd25a87e (patch)
treed1779c04b8bb2a44915483751ac33e498b1a2ad9 /src
parente2a84a4a7bb8cdebfe4c0990b79179e2fd717a48 (diff)
Userspace revision handling is reworked
In order to make it simpler and more straightforward to express the revisions of the set type, all keywords and their parsing are separated from the individual set types. All backward compatibility arguments are recognized and ignored arguments are supported. Recognized but ignored arguments will be removed in a later release.
Diffstat (limited to 'src')
-rw-r--r--src/ipset.c74
1 files changed, 54 insertions, 20 deletions
diff --git a/src/ipset.c b/src/ipset.c
index df0778a..ce1b73f 100644
--- a/src/ipset.c
+++ b/src/ipset.c
@@ -278,21 +278,21 @@ static int
call_parser(int *argc, char *argv[], const struct ipset_type *type,
enum ipset_adt cmd, bool family)
{
- const struct ipset_arg *args = type->args[cmd];
const struct ipset_arg *arg;
const char *optstr;
const struct ipset_type *t = type;
uint8_t revision = type->revision;
- int ret = 0, i = 1;
+ int ret = 0, i = 1, j;
/* Currently CREATE and ADT may have got additional arguments */
- if (!args && *argc > 1)
+ if (type->cmd[cmd].args[0] == IPSET_ARG_NONE && *argc > 1)
return exit_error(PARAMETER_PROBLEM, "Unknown argument: `%s'",
argv[i]);
while (*argc > i) {
ret = -1;
- for (arg = args; arg->opt; arg++) {
+ for (j = 0; type->cmd[cmd].args[j] != IPSET_ARG_NONE; j++) {
+ arg = ipset_keyword(type->cmd[cmd].args[j]);
D("argc: %u, %s vs %s", i, argv[i], arg->name[0]);
if (!(ipset_match_option(argv[i], arg->name)))
continue;
@@ -343,8 +343,8 @@ call_parser(int *argc, char *argv[], const struct ipset_type *type,
err_unknown:
while ((type = ipset_type_higher_rev(t)) != t) {
- args = type->args[cmd];
- for (arg = args; arg->opt; arg++) {
+ for (j = 0; type->cmd[cmd].args[j] != IPSET_ARG_NONE; j++) {
+ arg = ipset_keyword(type->cmd[cmd].args[j]);
D("argc: %u, %s vs %s", i, argv[i], arg->name[0]);
if (ipset_match_option(argv[i], arg->name))
return exit_error(PARAMETER_PROBLEM,
@@ -382,8 +382,9 @@ check_mandatory(const struct ipset_type *type, enum ipset_cmd command)
{
enum ipset_adt cmd = cmd2cmd(command);
uint64_t flags = ipset_data_flags(ipset_session_data(session));
- uint64_t mandatory = type->mandatory[cmd];
- const struct ipset_arg *arg = type->args[cmd];
+ uint64_t mandatory = type->cmd[cmd].need;
+ const struct ipset_arg *arg;
+ int i;
/* Range can be expressed by ip/cidr */
if (flags & IPSET_FLAG(IPSET_OPT_CIDR))
@@ -392,7 +393,7 @@ check_mandatory(const struct ipset_type *type, enum ipset_cmd command)
mandatory &= ~flags;
if (!mandatory)
return;
- if (!arg) {
+ if (type->cmd[cmd].args[0] == IPSET_ARG_NONE) {
exit_error(OTHER_PROBLEM,
"There are missing mandatory flags "
"but can't check them. "
@@ -400,13 +401,15 @@ check_mandatory(const struct ipset_type *type, enum ipset_cmd command)
return;
}
- for (; arg->opt; arg++)
+ for (i = 0; type->cmd[cmd].args[i] != IPSET_ARG_NONE; i++) {
+ arg = ipset_keyword(type->cmd[cmd].args[i]);
if (mandatory & IPSET_FLAG(arg->opt)) {
exit_error(PARAMETER_PROBLEM,
"Mandatory option `%s' is missing",
arg->name[0]);
return;
}
+ }
}
static const char *
@@ -438,11 +441,12 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
{
uint64_t flags = ipset_data_flags(ipset_session_data(session));
enum ipset_adt cmd = cmd2cmd(command);
- uint64_t allowed = type->full[cmd];
+ uint64_t allowed = type->cmd[cmd].full;
uint64_t cmdflags = command == IPSET_CMD_CREATE
? IPSET_CREATE_FLAGS : IPSET_ADT_FLAGS;
- const struct ipset_arg *arg = type->args[cmd];
+ const struct ipset_arg *arg;
enum ipset_opt i;
+ int j;
/* Range can be expressed by ip/cidr or from-to */
if (allowed & IPSET_FLAG(IPSET_OPT_IP_TO))
@@ -480,14 +484,15 @@ check_allowed(const struct ipset_type *type, enum ipset_cmd command)
break;
}
/* Other options */
- if (!arg) {
+ if (type->cmd[cmd].args[0] == IPSET_ARG_NONE) {
exit_error(OTHER_PROBLEM,
"There are not allowed options (%u) "
- "but option list is NULL. "
+ "but option list is empty. "
"It's a bug, please report the problem.", i);
return;
}
- for (; arg->opt; arg++) {
+ for (j = 0; type->cmd[cmd].args[j] != IPSET_ARG_NONE; j++) {
+ arg = ipset_keyword(type->cmd[cmd].args[j]);
if (arg->opt != i)
continue;
exit_error(OTHER_PROBLEM,
@@ -519,6 +524,21 @@ type_find(const char *name)
return NULL;
}
+static enum ipset_adt cmd_help_order[] = {
+ IPSET_CREATE,
+ IPSET_ADD,
+ IPSET_DEL,
+ IPSET_TEST,
+ IPSET_CADT_MAX,
+};
+
+static const char *cmd_prefix[] = {
+ [IPSET_CREATE] = "create SETNAME",
+ [IPSET_ADD] = "add SETNAME",
+ [IPSET_DEL] = "del SETNAME",
+ [IPSET_TEST] = "test SETNAME",
+};
+
/* Workhorse */
int
parse_commandline(int argc, char *argv[])
@@ -677,28 +697,42 @@ parse_commandline(int argc, char *argv[])
if (interactive ||
!ipset_envopt_test(session, IPSET_ENV_QUIET)) {
if (arg0) {
+ const struct ipset_arg *arg;
+ int k;
+
/* Type-specific help, without kernel checking */
type = type_find(arg0);
if (!type)
return exit_error(PARAMETER_PROBLEM,
"Unknown settype: `%s'", arg0);
- printf("\n%s type specific options:\n\n%s",
- type->name, type->usage);
+ printf("\n%s type specific options:\n\n", type->name);
+ for (i = 0; cmd_help_order[i] != IPSET_CADT_MAX; i++) {
+ cmd = cmd_help_order[i];
+ printf("%s %s %s\n",
+ cmd_prefix[cmd], type->name, type->cmd[cmd].help);
+ for (k = 0; type->cmd[cmd].args[k] != IPSET_ARG_NONE; k++) {
+ arg = ipset_keyword(type->cmd[cmd].args[k]);
+ if (!arg->help || arg->help[0] == '\0')
+ continue;
+ printf(" %s\n", arg->help);
+ }
+ }
+ printf("\n%s\n", type->usage);
if (type->usagefn)
type->usagefn();
if (type->family == NFPROTO_UNSPEC)
printf("\nType %s is family neutral.\n",
type->name);
else if (type->family == NFPROTO_IPSET_IPV46)
- printf("\nType %s supports INET "
- "and INET6.\n",
+ printf("\nType %s supports inet "
+ "and inet6.\n",
type->name);
else
printf("\nType %s supports family "
"%s only.\n",
type->name,
type->family == NFPROTO_IPV4
- ? "INET" : "INET6");
+ ? "inet" : "inet6");
} else {
printf("\nSupported set types:\n");
type = ipset_types();