Permalink
Please sign in to comment.
Browse files
Add module for parsing command line arguments.
This patch adds a new module that does what current snap-confine main() does with regards to argument parsing. The module is fully tested and has simple API sufficient to drive rest of snap-confine. Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
- Loading branch information...
Showing
with
502 additions
and 2 deletions.
- +5 −2 src/Makefile.am
- +262 −0 src/snap-confine-args-test.c
- +158 −0 src/snap-confine-args.c
- +77 −0 src/snap-confine-args.h
| @@ -0,0 +1,262 @@ | ||
| +/* | ||
| + * Copyright (C) 2016 Canonical Ltd | ||
| + * | ||
| + * This program is free software: you can redistribute it and/or modify | ||
| + * it under the terms of the GNU General Public License version 3 as | ||
| + * published by the Free Software Foundation. | ||
| + * | ||
| + * This program is distributed in the hope that it will be useful, | ||
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| + * GNU General Public License for more details. | ||
| + * | ||
| + * You should have received a copy of the GNU General Public License | ||
| + * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| + * | ||
| + */ | ||
| + | ||
| +#include "snap-confine-args.h" | ||
| +#include "snap-confine-args.c" | ||
| + | ||
| +#include <stdarg.h> | ||
| + | ||
| +#include <glib.h> | ||
| + | ||
| +/** | ||
| + * Create an argc + argv pair out of a NULL terminated argument list. | ||
| + **/ | ||
| +static void | ||
| + __attribute__ ((sentinel)) test_argc_argv(int *argcp, char ***argvp, ...) | ||
| +{ | ||
| + int argc = 0; | ||
| + char **argv = NULL; | ||
| + g_test_queue_free(argv); | ||
| + | ||
| + va_list ap; | ||
| + va_start(ap, argvp); | ||
| + const char *arg; | ||
| + do { | ||
| + arg = va_arg(ap, const char *); | ||
| + // XXX: yeah, wrong way but the worse that can happen is for test to fail | ||
| + argv = realloc(argv, sizeof(const char **) * (argc + 1)); | ||
| + g_assert_nonnull(argv); | ||
| + if (arg != NULL) { | ||
| + char *arg_copy = strdup(arg); | ||
| + g_test_queue_free(arg_copy); | ||
| + argv[argc] = arg_copy; | ||
| + argc += 1; | ||
| + } else { | ||
| + argv[argc] = NULL; | ||
| + } | ||
| + } while (arg != NULL); | ||
| + va_end(ap); | ||
| + | ||
| + *argcp = argc; | ||
| + *argvp = argv; | ||
| +} | ||
| + | ||
| +static void test_test_argc_argv() | ||
| +{ | ||
| + // Check that test_argc_argv() correctly stores data | ||
| + int argc; | ||
| + char **argv; | ||
| + | ||
| + test_argc_argv(&argc, &argv, NULL); | ||
| + g_assert_cmpint(argc, ==, 0); | ||
| + g_assert_null(argv[0]); | ||
| + | ||
| + test_argc_argv(&argc, &argv, "zero", "one", "two", NULL); | ||
| + g_assert_cmpint(argc, ==, 3); | ||
| + g_assert_cmpstr(argv[0], ==, "zero"); | ||
| + g_assert_cmpstr(argv[1], ==, "one"); | ||
| + g_assert_cmpstr(argv[2], ==, "two"); | ||
| + g_assert_null(argv[3]); | ||
| +} | ||
| + | ||
| +static void test_sc_nonfatal_parse_args__typical() | ||
| +{ | ||
| + // Test that typical invocation of snap-confine is parsed correctly. | ||
| + struct sc_error *err __attribute__ ((cleanup(sc_cleanup_error))) = NULL; | ||
| + struct sc_args *args; | ||
| + | ||
| + int argc; | ||
| + char **argv; | ||
| + test_argc_argv(&argc, &argv, | ||
| + "/usr/lib/snapd/snap-confine", "snap.app", "--option", | ||
| + "arg", NULL); | ||
| + | ||
| + args = sc_nonfatal_parse_args(&argc, &argv, &err); | ||
| + g_test_queue_destroy((GDestroyNotify) sc_args_free, args); | ||
| + g_assert_null(err); | ||
| + g_assert_nonnull(args); | ||
| + | ||
| + // Check supported switches and arguments | ||
| + g_assert_cmpstr(sc_args_security_tag(args), ==, "snap.app"); | ||
| + g_assert_cmpint(sc_args_is_version_query(args), ==, false); | ||
| + | ||
| + // Check remaining arguments | ||
| + g_assert_cmpint(argc, ==, 3); | ||
| + g_assert_cmpstr(argv[0], ==, "/usr/lib/snapd/snap-confine"); | ||
| + g_assert_cmpstr(argv[1], ==, "--option"); | ||
| + g_assert_cmpstr(argv[2], ==, "arg"); | ||
| + g_assert_null(argv[3]); | ||
| +} | ||
| + | ||
| +static void test_sc_nonfatal_parse_args__ubuntu_core_launcher() | ||
| +{ | ||
| + // Test that typical legacy invocation of snap-confine via the | ||
| + // ubuntu-core-launcher symlink, with duplicated security tag, is parsed | ||
| + // correctly. | ||
| + struct sc_error *err __attribute__ ((cleanup(sc_cleanup_error))) = NULL; | ||
| + struct sc_args *args; | ||
| + | ||
| + int argc; | ||
| + char **argv; | ||
| + test_argc_argv(&argc, &argv, | ||
| + "/usr/bin/ubuntu-core-launcher", "snap.app", "snap.app", | ||
| + "--option", "arg", NULL); | ||
| + | ||
| + args = sc_nonfatal_parse_args(&argc, &argv, &err); | ||
| + g_test_queue_destroy((GDestroyNotify) sc_args_free, args); | ||
| + g_assert_null(err); | ||
| + g_assert_nonnull(args); | ||
| + | ||
| + // Check supported switches and arguments | ||
| + g_assert_cmpstr(sc_args_security_tag(args), ==, "snap.app"); | ||
| + g_assert_cmpint(sc_args_is_version_query(args), ==, false); | ||
| + | ||
| + // Check remaining arguments | ||
| + g_assert_cmpint(argc, ==, 3); | ||
| + g_assert_cmpstr(argv[0], ==, "/usr/bin/ubuntu-core-launcher"); | ||
| + g_assert_cmpstr(argv[1], ==, "--option"); | ||
| + g_assert_cmpstr(argv[2], ==, "arg"); | ||
| + g_assert_null(argv[3]); | ||
| +} | ||
| + | ||
| +static void test_sc_nonfatal_parse_args__version() | ||
| +{ | ||
| + // Test that snap-confine --version is detected. | ||
| + struct sc_error *err __attribute__ ((cleanup(sc_cleanup_error))) = NULL; | ||
| + struct sc_args *args; | ||
| + | ||
| + int argc; | ||
| + char **argv; | ||
| + test_argc_argv(&argc, &argv, | ||
| + "/usr/lib/snapd/snap-confine", "--version", "ignored", | ||
| + "garbage", NULL); | ||
| + | ||
| + args = sc_nonfatal_parse_args(&argc, &argv, &err); | ||
| + g_test_queue_destroy((GDestroyNotify) sc_args_free, args); | ||
| + g_assert_null(err); | ||
| + g_assert_nonnull(args); | ||
| + | ||
| + // Check supported switches and arguments | ||
| + g_assert_null(sc_args_security_tag(args)); | ||
| + g_assert_cmpint(sc_args_is_version_query(args), ==, true); | ||
| + | ||
| + // Check remaining arguments | ||
| + g_assert_cmpint(argc, ==, 3); | ||
| + g_assert_cmpstr(argv[0], ==, "/usr/lib/snapd/snap-confine"); | ||
| + g_assert_cmpstr(argv[1], ==, "ignored"); | ||
| + g_assert_cmpstr(argv[2], ==, "garbage"); | ||
| + g_assert_null(argv[3]); | ||
| +} | ||
| + | ||
| +static void test_sc_nonfatal_parse_args__nothing_to_parse() | ||
| +{ | ||
| + // Check that calling without any arguments is reported as error. | ||
| + struct sc_error *err __attribute__ ((cleanup(sc_cleanup_error))) = NULL; | ||
| + struct sc_args *args; | ||
| + | ||
| + int argc; | ||
| + char **argv; | ||
| + test_argc_argv(&argc, &argv, NULL); | ||
| + | ||
| + args = sc_nonfatal_parse_args(&argc, &argv, &err); | ||
| + g_assert_nonnull(err); | ||
| + g_assert_null(args); | ||
| + | ||
| + // Check the error that we've got | ||
| + g_assert_cmpstr(sc_error_msg(err), ==, | ||
| + "cannot parse arguments, argc is zero"); | ||
| +} | ||
| + | ||
| +static void test_sc_nonfatal_parse_args__no_security_tag() | ||
| +{ | ||
| + // Check that lack of security tag is reported as error. | ||
| + struct sc_error *err __attribute__ ((cleanup(sc_cleanup_error))) = NULL; | ||
| + struct sc_args *args; | ||
| + | ||
| + int argc; | ||
| + char **argv; | ||
| + test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine", NULL); | ||
| + | ||
| + args = sc_nonfatal_parse_args(&argc, &argv, &err); | ||
| + g_assert_nonnull(err); | ||
| + g_assert_null(args); | ||
| + | ||
| + // Check the error that we've got | ||
| + g_assert_cmpstr(sc_error_msg(err), ==, | ||
| + "application or hook security tag was not provided"); | ||
| +} | ||
| + | ||
| +static void test_sc_nonfatal_parse_args__unknown_option() | ||
| +{ | ||
| + // Check that unrecognized option switch is reported as error. | ||
| + struct sc_error *err __attribute__ ((cleanup(sc_cleanup_error))) = NULL; | ||
| + struct sc_args *args; | ||
| + | ||
| + int argc; | ||
| + char **argv; | ||
| + test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine", | ||
| + "--frozbonicator", NULL); | ||
| + | ||
| + args = sc_nonfatal_parse_args(&argc, &argv, &err); | ||
| + g_assert_nonnull(err); | ||
| + g_assert_null(args); | ||
| + | ||
| + // Check the error that we've got | ||
| + g_assert_cmpstr(sc_error_msg(err), ==, | ||
| + "unrecognized command line option: --frozbonicator"); | ||
| +} | ||
| + | ||
| +static void test_sc_nonfatal_parse_args__forwards_error() | ||
| +{ | ||
| + // Check that sc_nonfatal_parse_args() forwards errors. | ||
| + if (g_test_subprocess()) { | ||
| + int argc; | ||
| + char **argv; | ||
| + test_argc_argv(&argc, &argv, "/usr/lib/snapd/snap-confine", | ||
| + "--frozbonicator", NULL); | ||
| + | ||
| + // Call sc_nonfatal_parse_args() without an error handle | ||
| + sc_nonfatal_parse_args(&argc, &argv, NULL); | ||
| + | ||
| + g_test_message("expected not to reach this place"); | ||
| + g_test_fail(); | ||
| + return; | ||
| + } | ||
| + g_test_trap_subprocess(NULL, 0, 0); | ||
| + g_test_trap_assert_failed(); | ||
| + g_test_trap_assert_stderr | ||
| + ("unrecognized command line option: --frozbonicator\n"); | ||
| +} | ||
| + | ||
| +static void __attribute__ ((constructor)) init() | ||
| +{ | ||
| + g_test_add_func("/args/test_argc_argv", test_test_argc_argv); | ||
| + g_test_add_func("/args/sc_nonfatal_parse_args/typical", | ||
| + test_sc_nonfatal_parse_args__typical); | ||
| + g_test_add_func("/args/sc_nonfatal_parse_args/ubuntu_core_launcher", | ||
| + test_sc_nonfatal_parse_args__ubuntu_core_launcher); | ||
| + g_test_add_func("/args/sc_nonfatal_parse_args/version", | ||
| + test_sc_nonfatal_parse_args__version); | ||
| + g_test_add_func("/args/sc_nonfatal_parse_args/nothing_to_parse", | ||
| + test_sc_nonfatal_parse_args__nothing_to_parse); | ||
| + g_test_add_func("/args/sc_nonfatal_parse_args/no_security_tag", | ||
| + test_sc_nonfatal_parse_args__no_security_tag); | ||
| + g_test_add_func("/args/sc_nonfatal_parse_args/unknown_option", | ||
| + test_sc_nonfatal_parse_args__unknown_option); | ||
| + g_test_add_func("/args/sc_nonfatal_parse_args/forwards_error", | ||
| + test_sc_nonfatal_parse_args__forwards_error); | ||
| +} |
Oops, something went wrong.
0 comments on commit
a84be35