parser: update option parsing so --config-file does not have to be first

Requiring --config-file to be first in the option list is not user
friendly fix the option parsing so that --config-file can be specified
anywhere in the option list.

This also fixes a bug where even when the --config-file option is
first the option parsing fails because the detection logic is broken
for some option cases.

PR: https://gitlab.com/apparmor/apparmor/merge_requests/175
Acked-by: Seth Arnold <seth.arnold@canonical.com>
Signed-off-by: John Johansen <john.johansen@canonical.com>
This commit is contained in:
John Johansen 2018-08-19 02:13:21 -07:00
parent 9a8e7e58d2
commit af1818c053
2 changed files with 30 additions and 30 deletions

View file

@ -359,9 +359,8 @@ profiles.
=item --config-file
Specify the config file to use instead of
/etc/apparmor/parser.conf. This option must be the first option
specified when invoking the parser, otherwise the parser will abort
with an error.
/etc/apparmor/parser.conf. This option will be processed early before
regular options regardless of the order it is specified in.
=item --print-config-file

View file

@ -59,6 +59,8 @@
#define PRIVILEGED_OPS (kernel_load)
#define UNPRIVILEGED_OPS (!(PRIVILEGED_OPS))
#define EARLY_ARG_CONFIG_FILE 141
const char *parser_title = "AppArmor parser";
const char *parser_copyright = "Copyright (C) 1999-2008 Novell Inc.\nCopyright 2009-2018 Canonical Ltd.";
@ -161,7 +163,7 @@ struct option long_options[] = {
{"kernel-features", 1, 0, 138}, /* no short option */
{"compile-features", 1, 0, 139}, /* no short option */
{"print-config-file", 0, 0, 140}, /* no short option */
{"config-file", 1, 0, 141}, /* early option, no short option */
{"config-file", 1, 0, EARLY_ARG_CONFIG_FILE}, /* early option, no short option */
{NULL, 0, 0, 0},
};
@ -219,7 +221,7 @@ static void display_usage(const char *command)
"--max-jobs n Hard cap on --jobs. Default 8*cpus\n"
"--abort-on-error Abort processing of profiles on first error\n"
"--skip-bad-cache-rebuild Do not try rebuilding the cache if it is rejected by the kernel\n"
"--config-file n Specify the parser config file location, Must be the first option.\n"
"--config-file n Specify the parser config file location, processed early before other options.\n"
"--print-config Print config file location\n"
"--warn n Enable warnings (see --help=warn)\n"
,command);
@ -388,10 +390,19 @@ static long process_jobs_arg(const char *arg, const char *val) {
}
bool early_arg(int c) {
switch(c) {
case EARLY_ARG_CONFIG_FILE:
return true;
}
return false;
}
/* process a single argment from getopt_long
* Returns: 1 if an action arg, else 0
*/
static int process_arg(int c, char *optarg, int config_count)
static int process_arg(int c, char *optarg)
{
int count = 0;
@ -639,16 +650,11 @@ static int process_arg(int c, char *optarg, int config_count)
kernel_load = 0;
print_cache_dir = true;
break;
case 141:
if (optind - config_count != 1) {
PERROR("%s: --config-file=%s must be the first option specified\n", progname, optarg);
case EARLY_ARG_CONFIG_FILE:
config_file = strdup(optarg);
if (!config_file) {
PERROR("%s: %m", progname);
exit(1);
} else {
config_file = strdup(optarg);
if (!config_file) {
PERROR("%s: %m", progname);
exit(1);
}
}
break;
case 140:
@ -663,24 +669,18 @@ static int process_arg(int c, char *optarg, int config_count)
return count;
}
static int process_early_args(int argc, char *argv[])
static void process_early_args(int argc, char *argv[])
{
int c, o, count = 1;
int c, o;
if (argc <= 1)
return 1;
if (strcmp("--config-file", argv[1]) == 0)
count = 2;
else if (strncmp("--config-file=", argv[1], 14) != 0)
return 1;
if ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1)
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1)
{
process_arg(c, optarg, count);
if (early_arg(c))
process_arg(c, optarg);
}
PDEBUG("optind = %d argc = %d\n", optind, argc);
return optind;
/* reset args, so we are ready for a second pass */
optind = 1;
}
static int process_args(int argc, char *argv[])
@ -692,7 +692,8 @@ static int process_args(int argc, char *argv[])
opterr = 1;
while ((c = getopt_long(argc, argv, short_options, long_options, &o)) != -1)
{
count += process_arg(c, optarg, 0);
if (!early_arg(c))
count += process_arg(c, optarg);
}
if (count > 1) {
@ -718,7 +719,7 @@ static int process_config_file(const char *name)
}
while ((c = getopt_long_file(f, long_options, &optarg, &o)) != -1)
process_arg(c, optarg, 0);
process_arg(c, optarg);
return 1;
}