From 00fb4e94ab9b5084769d01592af5f835c669f4fb Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Fri, 18 Mar 2016 17:28:51 -0500 Subject: [PATCH] parser: Support stacking in exec and change_profile rules Allow for a leading '&' character to be present in the named transition target strings to indicate that the transition should stack the current profile with the specified profile. Signed-off-by: Tyler Hicks Acked-by: John Johansen --- parser/parser.h | 2 +- parser/parser_lex.l | 5 +++-- parser/parser_misc.c | 22 +++++++++++++++---- parser/parser_yacc.y | 7 +++++- .../change_profile/stacking_ok_1.sd | 7 ++++++ .../change_profile/stacking_ok_2.sd | 7 ++++++ .../change_profile/stacking_ok_3.sd | 7 ++++++ parser/tst/simple_tests/file/stacking_ok_1.sd | 7 ++++++ 8 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 parser/tst/simple_tests/change_profile/stacking_ok_1.sd create mode 100644 parser/tst/simple_tests/change_profile/stacking_ok_2.sd create mode 100644 parser/tst/simple_tests/change_profile/stacking_ok_3.sd create mode 100644 parser/tst/simple_tests/file/stacking_ok_1.sd diff --git a/parser/parser.h b/parser/parser.h index ab55a74f1..81f211ad5 100644 --- a/parser/parser.h +++ b/parser/parser.h @@ -386,7 +386,7 @@ extern char *process_var(const char *var); extern int parse_mode(const char *mode); extern int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int fail); bool label_contains_ns(const char *label); -void parse_label(char **ns, char **name, const char *label); +void parse_label(bool *stack, char **ns, char **name, const char *label); extern struct cod_entry *new_entry(char *id, int mode, char *link_id); /* returns -1 if value != true or false, otherwise 0 == false, 1 == true */ diff --git a/parser/parser_lex.l b/parser/parser_lex.l index e26b2b95b..49b1f222c 100644 --- a/parser/parser_lex.l +++ b/parser/parser_lex.l @@ -192,6 +192,7 @@ OPEN_BRACE \{ CLOSE_BRACE \} SLASH \/ COLON : +AMPERSAND & END_OF_RULE [,] RANGE - MODE_CHARS ([RrWwaLlMmkXx])|(([Pp]|[Cc])[Xx])|(([Pp]|[Cc])?([IiUu])[Xx]) @@ -225,8 +226,8 @@ SET_VAR_PREFIX @ SET_VARIABLE {SET_VAR_PREFIX}(\{{VARIABLE_NAME}\}|{VARIABLE_NAME}) BOOL_VARIABLE $(\{{VARIABLE_NAME}\}|{VARIABLE_NAME}) -LABEL (\/|{SET_VARIABLE}{POST_VAR_ID}|{COLON}){ID}* -QUOTED_LABEL \"(\/|{SET_VAR_PREFIX}|{COLON})([^\0"]|\\\")*\" +LABEL (\/|{SET_VARIABLE}{POST_VAR_ID}|{COLON}|{AMPERSAND}){ID}* +QUOTED_LABEL \"(\/|{SET_VAR_PREFIX}|{COLON}|{AMPERSAND})([^\0"]|\\\")*\" OPEN_PAREN \( CLOSE_PAREN \) diff --git a/parser/parser_misc.c b/parser/parser_misc.c index aa2967573..22f6feff4 100644 --- a/parser/parser_misc.c +++ b/parser/parser_misc.c @@ -571,6 +571,7 @@ int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int /** * parse_label - break a label down to the namespace and profile name + * @stack: Will be true if the first char in @label is '&' to indicate stacking * @ns: Will point to the first char in the namespace upon return or NULL * if no namespace is present * @ns_len: Number of chars in the namespace string or 0 if no namespace @@ -589,7 +590,8 @@ int parse_X_mode(const char *X, int valid, const char *str_mode, int *mode, int * 2) Namespace is empty meaning @label starts with "::" * 3) Profile name is empty */ -static int _parse_label(char **ns, size_t *ns_len, +static int _parse_label(bool *stack, + char **ns, size_t *ns_len, char **name, size_t *name_len, const char *label) { @@ -597,6 +599,17 @@ static int _parse_label(char **ns, size_t *ns_len, const char *ns_start = NULL; const char *ns_end = NULL; + if (label[0] == '&') { + /** + * Leading ampersand means that the current profile should + * be stacked with the rest of the label + */ + *stack = true; + label++; + } else { + *stack = false; + } + if (label[0] != ':') { /* There is no namespace specified in the label */ name_start = label; @@ -639,15 +652,16 @@ static int _parse_label(char **ns, size_t *ns_len, bool label_contains_ns(const char *label) { + bool stack = false; char *ns = NULL; char *name = NULL; size_t ns_len = 0; size_t name_len = 0; - return _parse_label(&ns, &ns_len, &name, &name_len, label) == 0 && ns; + return _parse_label(&stack, &ns, &ns_len, &name, &name_len, label) == 0 && ns; } -void parse_label(char **_ns, char **_name, const char *label) +void parse_label(bool *_stack, char **_ns, char **_name, const char *label) { char *ns = NULL; char *name = NULL; @@ -655,7 +669,7 @@ void parse_label(char **_ns, char **_name, const char *label) size_t name_len = 0; int res; - res = _parse_label(&ns, &ns_len, &name, &name_len, label); + res = _parse_label(_stack, &ns, &ns_len, &name, &name_len, label); if (res == 1) { yyerror(_("Namespace not terminated: %s\n"), label); } else if (res == 2) { diff --git a/parser/parser_yacc.y b/parser/parser_yacc.y index 69fa4ff26..44793f73a 100644 --- a/parser/parser_yacc.y +++ b/parser/parser_yacc.y @@ -305,14 +305,19 @@ opt_id_or_var: { /* nothing */ $$ = NULL; } profile_base: TOK_ID opt_id_or_var flags TOK_OPEN rules TOK_CLOSE { Profile *prof = $5; + bool self_stack = false; if (!prof) { yyerror(_("Memory allocation error.")); } - parse_label(&prof->ns, &prof->name, $1); + parse_label(&self_stack, &prof->ns, &prof->name, $1); free($1); + if (self_stack) { + yyerror(_("Profile names must begin with a '/' or a namespace")); + } + /* Honor the --namespace-string command line option */ if (profile_ns) { /** diff --git a/parser/tst/simple_tests/change_profile/stacking_ok_1.sd b/parser/tst/simple_tests/change_profile/stacking_ok_1.sd new file mode 100644 index 000000000..402bf7840 --- /dev/null +++ b/parser/tst/simple_tests/change_profile/stacking_ok_1.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION change_profile w/ stacking +#=EXRESULT PASS +# +/usr/bin/foo { + change_profile -> &/bin/foo, +} diff --git a/parser/tst/simple_tests/change_profile/stacking_ok_2.sd b/parser/tst/simple_tests/change_profile/stacking_ok_2.sd new file mode 100644 index 000000000..9b616aed9 --- /dev/null +++ b/parser/tst/simple_tests/change_profile/stacking_ok_2.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION change_profile w/ stacking +#=EXRESULT PASS +# +/usr/bin/foo { + change_profile -> &bar, +} diff --git a/parser/tst/simple_tests/change_profile/stacking_ok_3.sd b/parser/tst/simple_tests/change_profile/stacking_ok_3.sd new file mode 100644 index 000000000..cb4f3a3ad --- /dev/null +++ b/parser/tst/simple_tests/change_profile/stacking_ok_3.sd @@ -0,0 +1,7 @@ +# +#=DESCRIPTION change_profile w/ stacking +#=EXRESULT PASS +# +/usr/bin/foo { + change_profile /bin/foo -> &bar, +} diff --git a/parser/tst/simple_tests/file/stacking_ok_1.sd b/parser/tst/simple_tests/file/stacking_ok_1.sd new file mode 100644 index 000000000..f1e747e43 --- /dev/null +++ b/parser/tst/simple_tests/file/stacking_ok_1.sd @@ -0,0 +1,7 @@ +# +#=Description basic file exec rule with stacking target +#=EXRESULT PASS +# +/usr/bin/foo { + /bin/bar px -> &baz, +}