blob: fb378ba1ddff915fe13fc33ad801e5dc8f1947dd [file] [log] [blame]
/* Copyright 2007-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <assert.h> /* assert */
#include <string.h> /* memcmp, str* */
#include <libipset/linux_ip_set.h> /* IPSET_CMD_* */
#include <libipset/icmp.h> /* id_to_icmp */
#include <libipset/icmpv6.h> /* id_to_icmpv6 */
#include <libipset/types.h> /* IPSET_*_ARG */
#include <libipset/session.h> /* ipset_envopt_parse */
#include <libipset/parse.h> /* ipset_parse_family */
#include <libipset/print.h> /* ipset_print_family */
#include <libipset/utils.h> /* STREQ */
#include <libipset/ui.h> /* prototypes */
/* Commands and environment options */
const struct ipset_commands ipset_commands[] = {
/* Order is important */
{ /* c[reate], --create, n[ew], -N */
.cmd = IPSET_CMD_CREATE,
.name = { "create", "new", "-N" },
.has_arg = IPSET_MANDATORY_ARG2,
.help = "SETNAME TYPENAME [type-specific-options]\n"
" Create a new set",
},
{ /* a[dd], --add, -A */
.cmd = IPSET_CMD_ADD,
.name = { "add", "-A", NULL },
.has_arg = IPSET_MANDATORY_ARG2,
.help = "SETNAME ENTRY\n"
" Add entry to the named set",
},
{ /* d[el], --del, -D */
.cmd = IPSET_CMD_DEL,
.name = { "del", "-D", NULL },
.has_arg = IPSET_MANDATORY_ARG2,
.help = "SETNAME ENTRY\n"
" Delete entry from the named set",
},
{ /* t[est], --test, -T */
.cmd = IPSET_CMD_TEST,
.name = { "test", "-T", NULL },
.has_arg = IPSET_MANDATORY_ARG2,
.help = "SETNAME ENTRY\n"
" Test entry in the named set",
},
{ /* des[troy], --destroy, x, -X */
.cmd = IPSET_CMD_DESTROY,
.name = { "destroy", "x", "-X" },
.has_arg = IPSET_OPTIONAL_ARG,
.help = "[SETNAME]\n"
" Destroy a named set or all sets",
},
{ /* l[ist], --list, -L */
.cmd = IPSET_CMD_LIST,
.name = { "list", "-L", NULL },
.has_arg = IPSET_OPTIONAL_ARG,
.help = "[SETNAME]\n"
" List the entries of a named set or all sets",
},
{ /* s[save], --save, -S */
.cmd = IPSET_CMD_SAVE,
.name = { "save", "-S", NULL },
.has_arg = IPSET_OPTIONAL_ARG,
.help = "[SETNAME]\n"
" Save the named set or all sets to stdout",
},
{ /* r[estore], --restore, -R */
.cmd = IPSET_CMD_RESTORE,
.name = { "restore", "-R", NULL },
.has_arg = IPSET_NO_ARG,
.help = "\n"
" Restore a saved state",
},
{ /* f[lush], --flush, -F */
.cmd = IPSET_CMD_FLUSH,
.name = { "flush", "-F", NULL },
.has_arg = IPSET_OPTIONAL_ARG,
.help = "[SETNAME]\n"
" Flush a named set or all sets",
},
{ /* ren[ame], --rename, e, -E */
.cmd = IPSET_CMD_RENAME,
.name = { "rename", "e", "-E" },
.has_arg = IPSET_MANDATORY_ARG2,
.help = "FROM-SETNAME TO-SETNAME\n"
" Rename two sets",
},
{ /* sw[ap], --swap, w, -W */
.cmd = IPSET_CMD_SWAP,
.name = { "swap", "w", "-W" },
.has_arg = IPSET_MANDATORY_ARG2,
.help = "FROM-SETNAME TO-SETNAME\n"
" Swap the contect of two existing sets",
},
{ /* h[elp, --help, -H */
.cmd = IPSET_CMD_HELP,
.name = { "help", "-h", "-H" },
.has_arg = IPSET_OPTIONAL_ARG,
.help = "[TYPENAME]\n"
" Print help, and settype specific help",
},
{ /* v[ersion], --version, -V */
.cmd = IPSET_CMD_VERSION,
.name = { "version", "-v", "-V" },
.has_arg = IPSET_NO_ARG,
.help = "\n"
" Print version information",
},
{ /* q[uit] */
.cmd = IPSET_CMD_QUIT,
.name = { "quit", NULL },
.has_arg = IPSET_NO_ARG,
.help = "\n"
" Quit interactive mode",
},
{ },
};
/* Match a command: try to match as a prefix or letter-command */
bool
ipset_match_cmd(const char *arg, const char * const name[])
{
size_t len, skip = 0;
int i;
assert(arg);
assert(name && name[0]);
/* Ignore two leading dashes */
if (arg[0] == '-' && arg[1] == '-')
skip = 2;
len = strlen(arg);
if (len <= skip || (len == 1 && arg[0] == '-'))
return false;
for (i = 0; i < IPSET_CMD_ALIASES && name[i] != NULL; i++) {
/* New command name options */
if (STRNEQ(arg + skip, name[i], len - skip))
return true;
}
return false;
}
/* Used up so far
*
* -A add
* -D del
* -E rename
* -f -file
* -F flush
* -h help
* -H help
* -L list
* -n -name
* -N create
* -o -output
* -r -resolve
* -R restore
* -s -sorted
* -S save
* -t -terse
* -T test
* -q -quiet
* -X destroy
* -v version
* -V version
* -W swap
* -! -exist
*/
const struct ipset_envopts ipset_envopts[] = {
{ .name = { "-o", "-output" },
.has_arg = IPSET_MANDATORY_ARG, .flag = IPSET_OPT_MAX,
.parse = ipset_parse_output,
.help = "plain|save|xml\n"
" Specify output mode for listing sets.\n"
" Default value for \"list\" command is mode \"plain\"\n"
" and for \"save\" command is mode \"save\".",
},
{ .name = { "-s", "-sorted" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_SORTED,
.help = "\n"
" Print elements sorted (if supported by the set type).",
},
{ .name = { "-q", "-quiet" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_QUIET,
.help = "\n"
" Suppress any notice or warning message.",
},
{ .name = { "-r", "-resolve" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_RESOLVE,
.help = "\n"
" Try to resolve IP addresses in the output (slow!)",
},
{ .name = { "-!", "-exist" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_EXIST,
.help = "\n"
" Ignore errors when creating or adding sets or\n"
" elements that do exist or when deleting elements\n"
" that don't exist.",
},
{ .name = { "-n", "-name" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_SETNAME,
.help = "\n"
" When listing, just list setnames from the kernel.\n",
},
{ .name = { "-t", "-terse" },
.parse = ipset_envopt_parse,
.has_arg = IPSET_NO_ARG, .flag = IPSET_ENV_LIST_HEADER,
.help = "\n"
" When listing, list setnames and set headers\n"
" from kernel only.",
},
{ .name = { "-f", "-file" },
.parse = ipset_parse_file,
.has_arg = IPSET_MANDATORY_ARG, .flag = IPSET_OPT_MAX,
.help = "\n"
" Read from the given file instead of standard\n"
" input (restore) or write to given file instead\n"
" of standard output (list/save).",
},
{ },
};
/* Strict option matching */
bool
ipset_match_option(const char *arg, const char * const name[])
{
assert(arg);
assert(name && name[0]);
/* Skip two leading dashes */
if (arg[0] == '-' && arg[1] == '-')
arg++, arg++;
return STREQ(arg, name[0]) ||
(name[1] != NULL && STREQ(arg, name[1]));
}
/* Strict envopt matching */
bool
ipset_match_envopt(const char *arg, const char * const name[])
{
assert(arg);
assert(name && name[0]);
/* Skip one leading dash */
if (arg[0] == '-' && arg[1] == '-')
arg++;
return STREQ(arg, name[0]) ||
(name[1] != NULL && STREQ(arg, name[1]));
}
/**
* ipset_shift_argv - shift off an argument
* @arc: argument count
* @argv: array of argument strings
* @from: from where shift off an argument
*
* Shift off the argument at "from" from the array of
* arguments argv of size argc.
*/
void
ipset_shift_argv(int *argc, char *argv[], int from)
{
int i;
assert(*argc >= from + 1);
for (i = from + 1; i <= *argc; i++)
argv[i-1] = argv[i];
(*argc)--;
return;
}