| #!/usr/bin/perl |
| # |
| # check-config -- check the current config for issues |
| # |
| use strict; |
| |
| my $P = 'check-config'; |
| |
| my $test = -1; |
| if ($ARGV[0] eq '--test') { |
| $test = $ARGV[1] + 0; |
| } elsif ($#ARGV != 4) { |
| die "Usage: $P <config> <arch> <flavour> <commonconfig> <warn-only>\n"; |
| } |
| |
| my ($config, $arch, $flavour, $commonconfig, $warn_only) = @ARGV; |
| |
| my $checks = "$commonconfig/enforce"; |
| my %values = (); |
| |
| # If we are in overridden then still perform the checks and emit the messages |
| # but do not return failure. Those items marked FATAL will alway trigger |
| # failure. |
| my $fail_exit = 1; |
| $fail_exit = 0 if ($warn_only eq 'true' || $warn_only eq '1'); |
| my $exit_val = 0; |
| |
| # Predicate execution engine. |
| sub pred_first { |
| my ($rest) = @_; |
| my $depth = 0; |
| my $off; |
| my $char; |
| my $pred; |
| |
| for ($off = 0; $off <= length($rest); $off++) { |
| $char = substr($rest, $off, 1); |
| if ($char eq '(') { |
| $depth++; |
| } elsif ($char eq ')') { |
| $depth--; |
| } elsif ($depth == 0 && $char eq '&') { |
| last; |
| } elsif ($depth == 0 && $char eq '|') { |
| last; |
| } |
| } |
| if ($depth > 0) { |
| die "$P: $rest: missing close parenthesis ')'\n"; |
| } elsif ($depth < 0) { |
| die "$P: $rest: missing open parenthesis '('\n"; |
| } |
| |
| ($pred, $rest) = (substr($rest, 0, $off), substr($rest, $off + 1)); |
| |
| $pred =~ s/^\s*//; |
| $pred =~ s/\s*$//; |
| |
| #print "pred<$pred> rest<$rest> char<$char>\n"; |
| ($pred, $rest, $char); |
| } |
| |
| sub pred_do { |
| my ($pred) = @_; |
| my (@a) = split(' ', $pred); |
| |
| if ($a[0] eq 'arch') { |
| die "$P: $pred: malformed -- $pred <arch>\n" if ($#a != 1); |
| #print " *** ARCH<$arch ?? $a[1]>\n"; |
| return ($arch eq $a[1]) |
| } elsif ($a[0] eq 'flavour') { |
| die "$P: $pred: malformed -- $pred <flavour>\n" if ($#a != 1); |
| #print " *** FLAVOUR<$flavour ?? $a[1]>\n"; |
| return ($flavour eq $a[1]) |
| } elsif ($a[0] eq 'value') { |
| die "$P: $pred: malformed -- $pred <name> <val>\n" if ($#a != 2); |
| #print " *** CHECK<$a[1] $a[2] ?? " . $values{$a[1]} . ">\n"; |
| return ($values{$a[1]} eq $a[2]); |
| } elsif ($a[0] eq 'exists') { |
| die "$P: $pred: malformed -- $pred <name>\n" if ($#a != 1); |
| return (defined $values{$a[1]}); |
| } else { |
| die "$P: $pred: unknown predicate\n"; |
| } |
| return 1; |
| } |
| sub pred_exec { |
| my ($rest) = @_; |
| my $pred; |
| my $res; |
| my $sep; |
| |
| #print "pred_exec<$rest>\n"; |
| |
| ($pred, $rest, $sep) = pred_first($rest); |
| |
| # Leading ! implies inversion. |
| if ($pred =~ /^\s*!\s*(.*)$/) { |
| #print " invert<$1>\n"; |
| $res = !pred_exec($1); |
| |
| # Recurse left for complex expressions. |
| } elsif ($pred =~ /^\s*\((.*)\)\s*$/) { |
| #print " left<$1>\n"; |
| $res = pred_exec($1); |
| |
| # Check for common syntax issues. |
| } elsif ($pred eq '') { |
| if ($sep eq '&' || $sep eq '|') { |
| die "$P: $pred$rest: malformed binary operator\n"; |
| } else { |
| die "$P: $pred$rest: syntax error\n"; |
| } |
| |
| # A predicate, execute it. |
| } else { |
| #print " DO<$pred> sep<$sep>\n"; |
| $res = pred_do($pred); |
| } |
| |
| #print " pre-return res<$res> sep<$sep>\n"; |
| if ($sep eq '') { |
| # |
| |
| # Recurse right for binary operators -- note these are lazy. |
| } elsif ($sep eq '&' || $sep eq '|') { |
| #print " right<$rest> ? sep<$sep> res<$res>\n"; |
| if ($rest =~ /^\s*($|\||\&)/) { |
| die "$P: $pred$rest: malformed binary operator\n"; |
| } |
| if (($res && $sep eq '&') || (!$res && $sep eq '|')) { |
| #print " right<$rest>\n"; |
| $res = pred_exec($rest); |
| } |
| |
| } else { |
| die "$P: $pred$rest: malformed predicate\n"; |
| } |
| #print " return res<$res> sep<$sep>\n"; |
| return $res; |
| } |
| |
| # |
| # PREDICATE TESTS |
| # |
| my $test_total = 1; |
| my $test_good = 0; |
| sub pred_test { |
| my ($pred, $eres, $eerr) = @_; |
| my ($res, $err, $fail); |
| |
| $test_total++; |
| if ($test != 0 && $test != $test_total - 1) { |
| return; |
| } |
| |
| eval { |
| $res = pred_exec($pred); |
| }; |
| $err = $@; |
| chomp($err); |
| |
| $res = !!$res; |
| $eres = !!$eres; |
| |
| $fail = ''; |
| if (defined $eres && $res != $eres) { |
| $fail = "result missmatch, expected $eres returned $res"; |
| } |
| if (defined $eerr && $err eq '') { |
| $fail = "error missmatch, expected '$eerr' returned success"; |
| } elsif (defined $eerr && $err !~ /$eerr/) { |
| $fail = "error missmatch, expected '$eerr' returned '$err'"; |
| } elsif (!defined $eerr && $err ne '') { |
| $fail = "error missmatch, expected success returned '$err'"; |
| } |
| |
| if ($fail eq '') { |
| $test_good++; |
| } else { |
| print "$pred: $test_total: FAIL: $fail\n"; |
| } |
| #print "TEST<$pred> eres<$eres> eerr<$eerr> res<$res> err<$err>\n"; |
| } |
| if ($test >= 0) { |
| $arch = 'MYARCH'; |
| $flavour = 'MYFLAVOUR'; |
| %values = ( 'ENABLED' => 'y', 'DISABLED' => 'n' ); |
| |
| # Errors. |
| my $eunkn = 'unknown predicate'; |
| my $epred = 'malformed'; |
| my $eclose = 'missing close parenthesis'; |
| my $eopen = 'missing open parenthesis'; |
| my $ebinary = 'malformed binary operator'; |
| |
| # Basic predicate tests. |
| print "TEST: $test_total: basic predicate tests ...\n"; |
| |
| pred_test('nosuchcommand', undef, $eunkn); |
| pred_test('arch', undef, $epred); |
| pred_test('arch MYARCH MYARCH', undef, $epred); |
| pred_test('arch MYARCH', 1, undef); |
| pred_test('arch NOTMYARCH', 0, undef); |
| |
| pred_test('flavour', undef, $epred); |
| pred_test('flavour MYFLAVOUR myflavour', undef, $epred); |
| pred_test('flavour MYFLAVOUR', 1, undef); |
| pred_test('flavour NOTMYFLAVOUR', 0, undef); |
| |
| pred_test('value', undef, $epred); |
| pred_test('value ENABLED', undef, $epred); |
| pred_test('value ENABLED ENABLED ENABLED', undef, $epred); |
| pred_test('value ENABLED y', 1, undef); |
| pred_test('value ENABLED n', 0, undef); |
| pred_test('value DISABLED n', 1, undef); |
| pred_test('value DISABLED y', 0, undef); |
| |
| pred_test('exists', undef, $epred); |
| pred_test('exists ENABLED ENABLED', undef, $epred); |
| pred_test('exists ENABLED', 1, undef); |
| pred_test('exists DISABLED', 1, undef); |
| pred_test('exists MISSING', 0, undef); |
| |
| print "TEST: $test_total: inversion tests ...\n"; |
| pred_test('!exists ENABLED', 0, undef); |
| pred_test('!exists MISSING', 1, undef); |
| pred_test('!!exists ENABLED', 1, undef); |
| pred_test('!!exists MISSING', 0, undef); |
| pred_test('!!!exists ENABLED', 0, undef); |
| pred_test('!!!exists MISSING', 1, undef); |
| |
| print "TEST: $test_total: parentheses tests ...\n"; |
| pred_test('(exists ENABLED)', 1, undef); |
| pred_test('((exists ENABLED))', 1, undef); |
| pred_test('(((exists ENABLED)))', 1, undef); |
| pred_test('(exists MISSING)', 0, undef); |
| pred_test('((exists MISSING))', 0, undef); |
| pred_test('(((exists MISSING)))', 0, undef); |
| |
| pred_test('(!exists ENABLED)', 0, undef); |
| pred_test('((!exists ENABLED))', 0, undef); |
| pred_test('(((!exists ENABLED)))', 0, undef); |
| pred_test('(!exists MISSING)', 1, undef); |
| pred_test('((!exists MISSING))', 1, undef); |
| pred_test('(((!exists MISSING)))', 1, undef); |
| |
| pred_test('((!(exists ENABLED)))', 0, undef); |
| pred_test('((!(exists MISSING)))', 1, undef); |
| pred_test('(!((exists ENABLED)))', 0, undef); |
| pred_test('(!((exists MISSING)))', 1, undef); |
| pred_test('!(((exists ENABLED)))', 0, undef); |
| pred_test('!(((exists MISSING)))', 1, undef); |
| pred_test('!((!(exists ENABLED)))', 1, undef); |
| pred_test('!((!(exists MISSING)))', 0, undef); |
| pred_test('!(!(!(exists ENABLED)))', 0, undef); |
| pred_test('!(!(!(exists MISSING)))', 1, undef); |
| |
| pred_test('(', undef, $eclose); |
| pred_test('()(', undef, $eclose); |
| pred_test('(())(', undef, $eclose); |
| pred_test('((()))(', undef, $eclose); |
| pred_test('(()', undef, $eclose); |
| pred_test('((())', undef, $eclose); |
| pred_test('(((()))', undef, $eclose); |
| pred_test('(()()', undef, $eclose); |
| pred_test('((())()', undef, $eclose); |
| |
| pred_test(')', undef, $eopen); |
| pred_test('())', undef, $eopen); |
| pred_test('(()))', undef, $eopen); |
| pred_test('((())))', undef, $eopen); |
| |
| print "TEST: $test_total: binary and tests ...\n"; |
| |
| pred_test('exists ENABLED &', undef, $ebinary); |
| pred_test('& exists ENABLED', undef, $ebinary); |
| pred_test('exists ENABLED & & exists ENABLED', undef, $ebinary); |
| |
| pred_test('exists MISSING & exists MISSING', 0, undef); |
| pred_test('exists MISSING & exists ENABLED', 0, undef); |
| pred_test('exists ENABLED & exists MISSING', 0, undef); |
| pred_test('exists ENABLED & exists ENABLED', 1, undef); |
| |
| pred_test('exists MISSING & exists MISSING & exists MISSING', 0, undef); |
| pred_test('exists MISSING & exists MISSING & exists ENABLED', 0, undef); |
| pred_test('exists MISSING & exists ENABLED & exists MISSING', 0, undef); |
| pred_test('exists MISSING & exists ENABLED & exists ENABLED', 0, undef); |
| pred_test('exists ENABLED & exists MISSING & exists MISSING', 0, undef); |
| pred_test('exists ENABLED & exists MISSING & exists ENABLED', 0, undef); |
| pred_test('exists ENABLED & exists ENABLED & exists MISSING', 0, undef); |
| pred_test('exists ENABLED & exists ENABLED & exists ENABLED', 1, undef); |
| |
| print "TEST: $test_total: binary or tests ...\n"; |
| |
| pred_test('exists ENABLED |', undef, $ebinary); |
| pred_test('| exists ENABLED', undef, $ebinary); |
| pred_test('exists ENABLED | | exists ENABLED', undef, $ebinary); |
| |
| pred_test('exists MISSING | exists MISSING', 0, undef); |
| pred_test('exists MISSING | exists ENABLED', 1, undef); |
| pred_test('exists ENABLED | exists MISSING', 1, undef); |
| pred_test('exists ENABLED | exists ENABLED', 1, undef); |
| |
| pred_test('exists MISSING | exists MISSING | exists MISSING', 0, undef); |
| pred_test('exists MISSING | exists MISSING | exists ENABLED', 1, undef); |
| pred_test('exists MISSING | exists ENABLED | exists MISSING', 1, undef); |
| pred_test('exists MISSING | exists ENABLED | exists ENABLED', 1, undef); |
| pred_test('exists ENABLED | exists MISSING | exists MISSING', 1, undef); |
| pred_test('exists ENABLED | exists MISSING | exists ENABLED', 1, undef); |
| pred_test('exists ENABLED | exists ENABLED | exists MISSING', 1, undef); |
| pred_test('exists ENABLED | exists ENABLED | exists ENABLED', 1, undef); |
| |
| print "TEST: $test_total: binary or/and combination tests ...\n"; |
| |
| pred_test('exists MISSING | exists MISSING & exists MISSING', 0, undef); |
| pred_test('exists MISSING | exists MISSING & exists ENABLED', 0, undef); |
| pred_test('exists MISSING | exists ENABLED & exists MISSING', 0, undef); |
| pred_test('exists MISSING | exists ENABLED & exists ENABLED', 1, undef); |
| pred_test('exists ENABLED | exists MISSING & exists MISSING', 1, undef); |
| pred_test('exists ENABLED | exists MISSING & exists ENABLED', 1, undef); |
| pred_test('exists ENABLED | exists ENABLED & exists MISSING', 1, undef); |
| pred_test('exists ENABLED | exists ENABLED & exists ENABLED', 1, undef); |
| |
| print "TEST: $test_total: binary and/or combination tests ...\n"; |
| |
| pred_test('exists MISSING & exists MISSING | exists MISSING', 0, undef); |
| pred_test('exists MISSING & exists MISSING | exists ENABLED', 0, undef); |
| pred_test('exists MISSING & exists ENABLED | exists MISSING', 0, undef); |
| pred_test('exists MISSING & exists ENABLED | exists ENABLED', 0, undef); |
| pred_test('exists ENABLED & exists MISSING | exists MISSING', 0, undef); |
| pred_test('exists ENABLED & exists MISSING | exists ENABLED', 1, undef); |
| pred_test('exists ENABLED & exists ENABLED | exists MISSING', 1, undef); |
| pred_test('exists ENABLED & exists ENABLED | exists ENABLED', 1, undef); |
| |
| $test_total--; |
| print "TEST: $test_good/$test_total succeeded\n"; |
| |
| exit $exit_val; |
| } |
| |
| # Load up the current configuration values -- FATAL if this fails |
| print "$P: $config: loading config\n"; |
| open(CONFIG, "<$config") || die "$P: $config: open failed -- $! -- aborting\n"; |
| while (<CONFIG>) { |
| # Pull out values. |
| /^#*\s*(CONFIG_\w+)[\s=](.*)$/ or next; |
| if ($2 eq 'is not set') { |
| $values{$1} = 'n'; |
| } else { |
| $values{$1} = $2; |
| } |
| } |
| close(CONFIG); |
| |
| # FATAL: Check if we have an enforcement list. |
| my $pass = 0; |
| my $total = 0; |
| my $line = ''; |
| print "$P: $checks: loading checks\n"; |
| open(CHECKS, "<$checks") || die "$P: $checks: open failed -- $! -- aborting\n"; |
| while (<CHECKS>) { |
| /^#/ && next; |
| chomp; |
| |
| $line .= $_; |
| if ($line =~ /\\$/) { |
| chop($line); |
| $line .= " "; |
| next; |
| } |
| $line =~ /^\s*$/ && next; |
| |
| #print "CHECK: <$line>\n"; |
| $total++; |
| my $result = pred_exec($line); |
| if (!$result) { |
| print "$P: FAIL: $line\n"; |
| $exit_val = $fail_exit; |
| } else { |
| $pass++; |
| } |
| |
| $line = ''; |
| } |
| close(CHECKS); |
| |
| print "$P: $pass/$total checks passed -- exit $exit_val\n"; |
| exit $exit_val; |