[PATCH v3 nfacct 7/29] code-refactoring changes to the "command menu"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



* replace the existing "command menu" with more efficient code, which is
clearer and easier to maintain;

* prevent wrong number of command-line arguments being specified

* prevent the correct command line parameters being specified more than once
(like "nfacct list xml xml" for example)

Signed-off-by: Michael Zintakis <michael.zintakis@xxxxxxxxxxxxxx>
---
 src/nfacct.c | 253 ++++++++++++++++++++++++++++-------------------------------
 1 file changed, 119 insertions(+), 134 deletions(-)

diff --git a/src/nfacct.c b/src/nfacct.c
index bf50f50..fbf9aa6 100644
--- a/src/nfacct.c
+++ b/src/nfacct.c
@@ -23,18 +23,6 @@
 #include <libmnl/libmnl.h>
 #include <libnetfilter_acct/libnetfilter_acct.h>
 
-enum {
-	NFACCT_CMD_NONE = 0,
-	NFACCT_CMD_LIST,
-	NFACCT_CMD_ADD,
-	NFACCT_CMD_DELETE,
-	NFACCT_CMD_GET,
-	NFACCT_CMD_FLUSH,
-	NFACCT_CMD_VERSION,
-	NFACCT_CMD_HELP,
-	NFACCT_CMD_RESTORE,
-};
-
 static int nfacct_cmd_list(int argc, char *argv[]);
 static int nfacct_cmd_add(int argc, char *argv[]);
 static int nfacct_cmd_delete(int argc, char *argv[]);
@@ -44,9 +32,57 @@ static int nfacct_cmd_version(int argc, char *argv[]);
 static int nfacct_cmd_help(int argc, char *argv[]);
 static int nfacct_cmd_restore(int argc, char *argv[]);
 
+/* Matches two strings, including partial matches */
+static int nfacct_matches(const char *cmd, const char *pattern)
+{
+	size_t len;
+
+	if (cmd == NULL || pattern == NULL)
+		return 0;
+
+	len = strlen(cmd);
+	if (len == 0 || len > strlen(pattern))
+		return 0;
+
+	return (strncmp(cmd, pattern, len) == 0);
+}
+
+/* main command 'menu' */
+static const struct cmd {
+	const char *cmd;
+	int (*func)(int argc, char **argv);
+} cmds[] = {
+	{ "list", 	nfacct_cmd_list },
+	{ "add",	nfacct_cmd_add },
+	{ "delete",	nfacct_cmd_delete },
+	{ "get",	nfacct_cmd_get },
+	{ "flush",	nfacct_cmd_flush },
+	{ "restore",	nfacct_cmd_restore },
+	{ "version",	nfacct_cmd_version },
+	{ "help",	nfacct_cmd_help },
+	{ NULL, NULL }
+};
+
+static int nfacct_do_cmd(const char *argv0, int argc, char **argv)
+{
+	const struct cmd *c;
+
+	for (c = cmds; c->cmd; ++c) {
+		if (nfacct_matches(argv0, c->cmd)) {
+			return (c->func(argc-1, argv+1));
+		}
+	}
+	fprintf(stderr, "nfacct v%s: Unknown command: %s\n",
+		VERSION, argv0);
+	return EXIT_FAILURE;
+}
+
+
+static void usage(char *argv[]) __attribute__((noreturn));
 static void usage(char *argv[])
 {
 	fprintf(stderr, "Usage: %s command [parameters]...\n", argv[0]);
+	exit(EXIT_FAILURE);
 }
 
 static void nfacct_perror(const char *msg)
@@ -59,80 +95,24 @@ static void nfacct_perror(const char *msg)
 	}
 }
 
-/* Matches two strings, including partial matches */
-static int nfacct_matches(const char *cmd, const char *pattern)
-{
-	size_t len;
-
-	if (cmd == NULL || pattern == NULL)
-		return 0;
-
-	len = strlen(cmd);
-	if (len == 0 || len > strlen(pattern))
-		return 0;
-
-	return (strncmp(cmd, pattern, len) == 0);
-}
+#define NFACCT_RET_ERR(x)	nfacct_perror(x); \
+				goto err;
+#define NFACCT_RET_ARG_ERR()	NFACCT_RET_ERR("unknown argument")
+#define NFACCT_NEXT_ARG() 	do {		\
+					argv++;	\
+					argc--;	\
+				} while(0)
 
 int main(int argc, char *argv[])
 {
-	int cmd = NFACCT_CMD_NONE, ret = 0;
-
-	if (argc < 2) {
-		usage(argv);
-		exit(EXIT_FAILURE);
-	}
-
-	if (nfacct_matches(argv[1], "list"))
-		cmd = NFACCT_CMD_LIST;
-	else if (nfacct_matches(argv[1], "add"))
-		cmd = NFACCT_CMD_ADD;
-	else if (nfacct_matches(argv[1], "delete"))
-		cmd = NFACCT_CMD_DELETE;
-	else if (nfacct_matches(argv[1], "get"))
-		cmd = NFACCT_CMD_GET;
-	else if (nfacct_matches(argv[1], "flush"))
-		cmd = NFACCT_CMD_FLUSH;
-	else if (nfacct_matches(argv[1], "version"))
-		cmd = NFACCT_CMD_VERSION;
-	else if (nfacct_matches(argv[1], "help"))
-		cmd = NFACCT_CMD_HELP;
-	else if (nfacct_matches(argv[1], "restore"))
-		cmd = NFACCT_CMD_RESTORE;
-	else {
-		fprintf(stderr, "nfacct v%s: Unknown command: %s\n",
-			VERSION, argv[1]);
-		usage(argv);
-		exit(EXIT_FAILURE);
-	}
-
-	switch(cmd) {
-	case NFACCT_CMD_LIST:
-		ret = nfacct_cmd_list(argc, argv);
-		break;
-	case NFACCT_CMD_ADD:
-		ret = nfacct_cmd_add(argc, argv);
-		break;
-	case NFACCT_CMD_DELETE:
-		ret = nfacct_cmd_delete(argc, argv);
-		break;
-	case NFACCT_CMD_GET:
-		ret = nfacct_cmd_get(argc, argv);
-		break;
-	case NFACCT_CMD_FLUSH:
-		ret = nfacct_cmd_flush(argc, argv);
-		break;
-	case NFACCT_CMD_VERSION:
-		ret = nfacct_cmd_version(argc, argv);
-		break;
-	case NFACCT_CMD_HELP:
-		ret = nfacct_cmd_help(argc, argv);
-		break;
-	case NFACCT_CMD_RESTORE:
-		ret = nfacct_cmd_restore(argc, argv);
-		break;
-	}
-	return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+	int ret = 0;
+
+	if (argc >= 2) {
+		ret = nfacct_do_cmd(argv[1], argc-1, argv+1);
+		if (ret != EXIT_FAILURE)
+			return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+	}
+	usage(argv);
 }
 
 static bool xml_header = false;
@@ -174,29 +154,29 @@ err:
 
 static int nfacct_cmd_list(int argc, char *argv[])
 {
-	bool zeroctr = false, xml = false;
+	bool nfnl_msg = false, xml = false;
 	struct mnl_socket *nl;
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nlmsghdr *nlh;
 	unsigned int seq, portid;
-	int ret, i;
+	int ret;
+	uint8_t nfnl_cmd = NFNL_MSG_ACCT_GET;
 
-	for (i=2; i<argc; i++) {
-		if (nfacct_matches(argv[i], "reset")) {
-			zeroctr = true;
-		} else if (nfacct_matches(argv[i], "xml")) {
+	while (argc > 0) {
+		if (!nfnl_msg && nfacct_matches(argv[0],"reset")) {
+			nfnl_cmd = NFNL_MSG_ACCT_GET_CTRZERO;
+			nfnl_msg = true;
+		} else if (!xml && nfacct_matches(argv[0],"xml")) {
 			xml = true;
 		} else {
 			nfacct_perror("unknown argument");
 			return -1;
 		}
+		argc--; argv++;
 	}
 
 	seq = time(NULL);
-	nlh = nfacct_nlmsg_build_hdr(buf, zeroctr ?
-					NFNL_MSG_ACCT_GET_CTRZERO :
-					NFNL_MSG_ACCT_GET,
-				     NLM_F_DUMP, seq);
+	nlh = nfacct_nlmsg_build_hdr(buf, nfnl_cmd, NLM_F_DUMP, seq);
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
@@ -298,15 +278,15 @@ static int _nfacct_cmd_add(char *name, uint64_t pkts, uint64_t bytes)
 
 static int nfacct_cmd_add(int argc, char *argv[])
 {
-	if (argc < 3 || strlen(argv[2]) == 0) {
+	if (argc < 1 || strlen(argv[0]) == 0) {
 		nfacct_perror("missing object name");
 		return -1;
-	} else if (argc > 3) {
+	} else if (argc > 1) {
 		nfacct_perror("too many arguments");
 		return -1;
 	}
 
-	return _nfacct_cmd_add(argv[2], 0, 0);
+	return _nfacct_cmd_add(argv[0], 0, 0);
 }
 
 static int nfacct_cmd_delete(int argc, char *argv[])
@@ -318,10 +298,10 @@ static int nfacct_cmd_delete(int argc, char *argv[])
 	struct nfacct *nfacct;
 	int ret;
 
-	if (argc < 3 || strlen(argv[2]) == 0) {
+	if (argc < 1 || strlen(argv[0]) == 0) {
 		nfacct_perror("missing object name");
 		return -1;
-	} else if (argc > 3) {
+	} else if (argc > 1) {
 		nfacct_perror("too many arguments");
 		return -1;
 	}
@@ -332,7 +312,7 @@ static int nfacct_cmd_delete(int argc, char *argv[])
 		return -1;
 	}
 
-	nfacct_attr_set(nfacct, NFACCT_ATTR_NAME, argv[2]);
+	nfacct_attr_set(nfacct, NFACCT_ATTR_NAME, argv[0]);
 
 	seq = time(NULL);
 	nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_DEL,
@@ -377,41 +357,46 @@ static int nfacct_cmd_delete(int argc, char *argv[])
 
 static int nfacct_cmd_get(int argc, char *argv[])
 {
-	bool zeroctr = false, xml = false;
+	bool nfnl_msg = false, xml = false;
 	struct mnl_socket *nl;
 	char buf[MNL_SOCKET_BUFFER_SIZE];
 	struct nlmsghdr *nlh;
 	uint32_t portid, seq;
 	struct nfacct *nfacct;
-	int ret, i;
+	int ret = -1, i;
+	char *name;
+	uint8_t nfnl_cmd = NFNL_MSG_ACCT_GET;
 
-	if (argc < 3 || strlen(argv[2]) == 0) {
+	if (argc < 1 || strlen(argv[0]) == 0) {
 		nfacct_perror("missing object name");
 		return -1;
 	}
-	for (i=3; i<argc; i++) {
-		if (nfacct_matches(argv[i], "reset")) {
-			zeroctr = true;
-		} else if (nfacct_matches(argv[i], "xml")) {
+	name = strdup(argv[0]);
+	if (!name) {
+		nfacct_perror("OOM");
+		return -1;
+	}
+	NFACCT_NEXT_ARG();
+	while (argc > 0) {
+		if (!nfnl_msg && nfacct_matches(argv[0],"reset")) {
+			nfnl_cmd = NFNL_MSG_ACCT_GET_CTRZERO;
+			nfnl_msg = true;
+		} else if (!xml && nfacct_matches(argv[0],"xml")) {
 			xml = true;
 		} else {
-			nfacct_perror("unknown argument");
-			return -1;
+			NFACCT_RET_ARG_ERR();
 		}
+		argc--; argv++;
 	}
 
 	nfacct = nfacct_alloc();
 	if (nfacct == NULL) {
-		nfacct_perror("OOM");
-		return -1;
+		NFACCT_RET_ERR("OOM");
 	}
-	nfacct_attr_set(nfacct, NFACCT_ATTR_NAME, argv[2]);
+	nfacct_attr_set(nfacct, NFACCT_ATTR_NAME, name);
 
 	seq = time(NULL);
-	nlh = nfacct_nlmsg_build_hdr(buf, zeroctr ?
-					NFNL_MSG_ACCT_GET_CTRZERO :
-					NFNL_MSG_ACCT_GET,
-				     NLM_F_ACK, seq);
+	nlh = nfacct_nlmsg_build_hdr(buf, nfnl_cmd, NLM_F_ACK, seq);
 
 	nfacct_nlmsg_build_payload(nlh, nfacct);
 
@@ -419,38 +404,38 @@ static int nfacct_cmd_get(int argc, char *argv[])
 
 	nl = mnl_socket_open(NETLINK_NETFILTER);
 	if (nl == NULL) {
-		nfacct_perror("mnl_socket_open");
-		return -1;
+		NFACCT_RET_ERR("mnl_socket_open");
 	}
 
 	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
-		nfacct_perror("mnl_socket_bind");
-		return -1;
+		NFACCT_RET_ERR("mnl_socket_bind");
 	}
 	portid = mnl_socket_get_portid(nl);
 
 	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
-		nfacct_perror("mnl_socket_send");
-		return -1;
+		NFACCT_RET_ERR("mnl_socket_send");
 	}
 
-	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
-	while (ret > 0) {
-		ret = mnl_cb_run(buf, ret, seq, portid, nfacct_cb, &xml);
-		if (ret <= 0)
+	i = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+	while (i > 0) {
+		i = mnl_cb_run(buf, i, seq, portid, nfacct_cb, &xml);
+		if (i <= 0)
 			break;
-		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+		i = mnl_socket_recvfrom(nl, buf, sizeof(buf));
 	}
-	if (ret == -1) {
-		nfacct_perror("error");
-		return -1;
+	if (i == -1) {
+		NFACCT_RET_ERR("error");
 	}
 	mnl_socket_close(nl);
 
 	if (xml_header)
 		printf("</nfacct>\n");
 
-	return 0;
+	ret = 0;
+
+err:
+	free(name);
+	return ret;
 }
 
 static int nfacct_cmd_flush(int argc, char *argv[])
@@ -461,7 +446,7 @@ static int nfacct_cmd_flush(int argc, char *argv[])
 	uint32_t portid, seq;
 	int ret;
 
-	if (argc > 2) {
+	if (argc > 0) {
 		nfacct_perror("too many arguments");
 		return -1;
 	}
@@ -522,7 +507,7 @@ static int nfacct_cmd_version(int argc, char *argv[])
 static const char help_msg[] =
 	"nfacct v%s: utility for the Netfilter extended accounting "
 	"infrastructure\n"
-	"Usage: %s command [parameters]...\n\n"
+	"Usage: nfacct command [parameters]...\n\n"
 	"Commands:\n"
 	"  list [reset]\t\tList the accounting object table (and reset)\n"
 	"  add object-name\tAdd new accounting object to table\n"
@@ -535,7 +520,7 @@ static const char help_msg[] =
 
 static int nfacct_cmd_help(int argc, char *argv[])
 {
-	printf(help_msg, VERSION, argv[0]);
+	printf(help_msg, VERSION);
 	return 0;
 }
 
@@ -546,7 +531,7 @@ static int nfacct_cmd_restore(int argc, char *argv[])
 	char buffer[512];
 	int ret;
 
-	if (argc > 2) {
+	if (argc > 0) {
 		nfacct_perror("too many arguments");
 		return -1;
 	}
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux