]>
Commit | Line | Data |
---|---|---|
356bd1e1 LO |
1 | #!/usr/bin/perl |
2 | # | |
3 | # check-config -- check the current config for issues | |
4 | # | |
5 | use strict; | |
6 | ||
7 | my $P = 'check-config'; | |
8 | ||
9 | my $test = -1; | |
10 | if ($ARGV[0] eq '--test') { | |
11 | $test = $ARGV[1] + 0; | |
12 | } elsif ($#ARGV != 4) { | |
13 | die "Usage: $P <config> <arch> <flavour> <commonconfig> <warn-only>\n"; | |
14 | } | |
15 | ||
16 | my ($config, $arch, $flavour, $commonconfig, $warn_only) = @ARGV; | |
17 | ||
18 | my $checks = "$commonconfig/enforce"; | |
19 | my %values = (); | |
20 | ||
21 | # If we are in overridden then still perform the checks and emit the messages | |
22 | # but do not return failure. Those items marked FATAL will alway trigger | |
23 | # failure. | |
24 | my $fail_exit = 1; | |
25 | $fail_exit = 0 if ($warn_only eq 'true' || $warn_only eq '1'); | |
26 | my $exit_val = 0; | |
27 | ||
28 | # Predicate execution engine. | |
29 | sub pred_first { | |
30 | my ($rest) = @_; | |
31 | my $depth = 0; | |
32 | my $off; | |
33 | my $char; | |
34 | my $pred; | |
35 | ||
36 | for ($off = 0; $off <= length($rest); $off++) { | |
37 | $char = substr($rest, $off, 1); | |
38 | if ($char eq '(') { | |
39 | $depth++; | |
40 | } elsif ($char eq ')') { | |
41 | $depth--; | |
42 | } elsif ($depth == 0 && $char eq '&') { | |
43 | last; | |
44 | } elsif ($depth == 0 && $char eq '|') { | |
45 | last; | |
46 | } | |
47 | } | |
48 | if ($depth > 0) { | |
49 | die "$P: $rest: missing close parenthesis ')'\n"; | |
50 | } elsif ($depth < 0) { | |
51 | die "$P: $rest: missing open parenthesis '('\n"; | |
52 | } | |
53 | ||
54 | ($pred, $rest) = (substr($rest, 0, $off), substr($rest, $off + 1)); | |
55 | ||
56 | $pred =~ s/^\s*//; | |
57 | $pred =~ s/\s*$//; | |
58 | ||
59 | #print "pred<$pred> rest<$rest> char<$char>\n"; | |
60 | ($pred, $rest, $char); | |
61 | } | |
62 | ||
63 | sub pred_do { | |
64 | my ($pred) = @_; | |
65 | my (@a) = split(' ', $pred); | |
66 | my $possible; | |
67 | ||
68 | if ($a[0] eq 'arch') { | |
69 | die "$P: $pred: malformed -- $pred <arch>\n" if ($#a < 1); | |
70 | for $possible (@a[1..$#a]) { | |
71 | #print " *** ARCH<$flavour ?? $possible>\n"; | |
72 | return 1 if ($arch eq $possible); | |
73 | } | |
74 | return 0; | |
75 | } elsif ($a[0] eq 'flavour') { | |
76 | die "$P: $pred: malformed -- $pred <flavour>\n" if ($#a < 1); | |
77 | for $possible (@a[1..$#a]) { | |
78 | #print " *** FLAVOUR<$flavour ?? $a[1]>\n"; | |
79 | return 1 if ($flavour eq $possible); | |
80 | } | |
81 | return 0; | |
82 | } elsif ($a[0] eq 'value') { | |
83 | die "$P: $pred: malformed -- $pred <name> <val>\n" if ($#a != 2); | |
84 | #print " *** CHECK<$a[1] $a[2] ?? " . $values{$a[1]} . ">\n"; | |
85 | return ($values{$a[1]} eq $a[2]); | |
86 | } elsif ($a[0] eq 'exists') { | |
87 | die "$P: $pred: malformed -- $pred <name>\n" if ($#a != 1); | |
88 | return (defined $values{$a[1]}); | |
89 | } else { | |
90 | die "$P: $pred: unknown predicate\n"; | |
91 | } | |
92 | return 1; | |
93 | } | |
94 | sub pred_exec { | |
95 | my ($rest) = @_; | |
96 | my $pred; | |
97 | my $cut = 0; | |
98 | my $res; | |
99 | my $sep; | |
100 | ||
101 | #print "pred_exec<$rest>\n"; | |
102 | ||
103 | ($pred, $rest, $sep) = pred_first($rest); | |
104 | ||
105 | # Leading ! implies inversion. | |
106 | if ($pred =~ /^\s*!\s*(.*)$/) { | |
107 | #print " invert<$1>\n"; | |
108 | ($cut, $res) = pred_exec($1); | |
109 | $res = !$res; | |
110 | ||
111 | # Leading / implies a CUT operation. | |
112 | } elsif ($pred =~ /^\s*\/\s*(.*)$/) { | |
113 | #print " cut<$1>\n"; | |
114 | ($cut, $res) = pred_exec($1); | |
115 | $cut = 1; | |
116 | ||
117 | # Recurse left for complex expressions. | |
118 | } elsif ($pred =~ /^\s*\((.*)\)\s*$/) { | |
119 | #print " left<$1>\n"; | |
120 | ($cut, $res) = pred_exec($1); | |
121 | ||
122 | # Check for common syntax issues. | |
123 | } elsif ($pred eq '') { | |
124 | if ($sep eq '&' || $sep eq '|') { | |
125 | die "$P: $pred$rest: malformed binary operator\n"; | |
126 | } else { | |
127 | die "$P: $pred$rest: syntax error\n"; | |
128 | } | |
129 | ||
130 | # A predicate, execute it. | |
131 | } else { | |
132 | #print " DO<$pred> sep<$sep>\n"; | |
133 | $res = pred_do($pred); | |
134 | } | |
135 | ||
136 | #print " pre-return res<$res> sep<$sep>\n"; | |
137 | if ($sep eq '') { | |
138 | # | |
139 | ||
140 | # Recurse right for binary operators -- note these are lazy. | |
141 | } elsif ($sep eq '&' || $sep eq '|') { | |
142 | #print " right<$rest> ? sep<$sep> res<$res>\n"; | |
143 | if ($rest =~ /^\s*($|\||\&)/) { | |
144 | die "$P: $pred$rest: malformed binary operator\n"; | |
145 | } | |
146 | if ($cut == 0 && (($res && $sep eq '&') || (!$res && $sep eq '|'))) { | |
147 | #print " right<$rest>\n"; | |
148 | ($cut, $res) = pred_exec($rest); | |
149 | } | |
150 | ||
151 | } else { | |
152 | die "$P: $pred$rest: malformed predicate\n"; | |
153 | } | |
154 | #warn " return cut<$cut> res<$res> sep<$sep>\n"; | |
155 | return ($cut, $res); | |
156 | } | |
157 | ||
158 | # | |
159 | # PREDICATE TESTS | |
160 | # | |
161 | my $test_total = 1; | |
162 | my $test_good = 0; | |
163 | sub pred_test { | |
164 | my ($pred, $eres, $eerr) = @_; | |
165 | my ($cut, $res, $err, $fail); | |
166 | ||
167 | $test_total++; | |
168 | if ($test != 0 && $test != $test_total - 1) { | |
169 | return; | |
170 | } | |
171 | ||
172 | eval { | |
173 | ($cut, $res) = pred_exec($pred); | |
174 | }; | |
175 | $err = $@; | |
176 | chomp($err); | |
177 | ||
178 | $res = !!$res; | |
179 | $eres = !!$eres; | |
180 | ||
181 | $fail = ''; | |
182 | if (defined $eres && $res != $eres) { | |
183 | $fail = "result missmatch, expected $eres returned $res"; | |
184 | } | |
185 | if (defined $eerr && $err eq '') { | |
186 | $fail = "error missmatch, expected '$eerr' returned success"; | |
187 | } elsif (defined $eerr && $err !~ /$eerr/) { | |
188 | $fail = "error missmatch, expected '$eerr' returned '$err'"; | |
189 | } elsif (!defined $eerr && $err ne '') { | |
190 | $fail = "error missmatch, expected success returned '$err'"; | |
191 | } | |
192 | ||
193 | if ($fail eq '') { | |
194 | $test_good++; | |
195 | } else { | |
196 | print "$pred: $test_total: FAIL: $fail\n"; | |
197 | } | |
198 | #print "TEST<$pred> eres<$eres> eerr<$eerr> res<$res> err<$err>\n"; | |
199 | } | |
200 | if ($test >= 0) { | |
201 | $arch = 'MYARCH'; | |
202 | $flavour = 'MYFLAVOUR'; | |
203 | %values = ( 'ENABLED' => 'y', 'DISABLED' => 'n' ); | |
204 | ||
205 | # Errors. | |
206 | my $eunkn = 'unknown predicate'; | |
207 | my $epred = 'malformed'; | |
208 | my $eclose = 'missing close parenthesis'; | |
209 | my $eopen = 'missing open parenthesis'; | |
210 | my $ebinary = 'malformed binary operator'; | |
211 | ||
212 | # Basic predicate tests. | |
213 | print "TEST: $test_total: basic predicate tests ...\n"; | |
214 | ||
215 | pred_test('nosuchcommand', undef, $eunkn); | |
216 | pred_test('arch', undef, $epred); | |
217 | pred_test('arch MYARCH', 1, undef); | |
218 | pred_test('arch MYARCH NOTMYARCH', 1, undef); | |
219 | pred_test('arch NOTMYARCH MYARCH', 1, undef); | |
220 | pred_test('arch NOTMYARCH NOTMYARCH MYARCH', 1, undef); | |
221 | pred_test('arch NOTMYARCH MYARCH NOTMYARCH', 1, undef); | |
222 | pred_test('arch NOTMYARCH', 0, undef); | |
223 | ||
224 | pred_test('flavour', undef, $epred); | |
225 | pred_test('flavour MYFLAVOUR', 1, undef); | |
226 | pred_test('flavour NOTMYFLAVOUR MYFLAVOUR', 1, undef); | |
227 | pred_test('flavour NOTMYFLAVOUR NOTMYFLAVOUR MYFLAVOUR', 1, undef); | |
228 | pred_test('flavour NOTMYFLAVOUR MYFLAVOUR NOTMYFLAVOUR', 1, undef); | |
229 | pred_test('flavour NOTMYFLAVOUR', 0, undef); | |
230 | ||
231 | pred_test('value', undef, $epred); | |
232 | pred_test('value ENABLED', undef, $epred); | |
233 | pred_test('value ENABLED ENABLED ENABLED', undef, $epred); | |
234 | pred_test('value ENABLED y', 1, undef); | |
235 | pred_test('value ENABLED n', 0, undef); | |
236 | pred_test('value DISABLED n', 1, undef); | |
237 | pred_test('value DISABLED y', 0, undef); | |
238 | ||
239 | pred_test('exists', undef, $epred); | |
240 | pred_test('exists ENABLED ENABLED', undef, $epred); | |
241 | pred_test('exists ENABLED', 1, undef); | |
242 | pred_test('exists DISABLED', 1, undef); | |
243 | pred_test('exists MISSING', 0, undef); | |
244 | ||
245 | print "TEST: $test_total: inversion tests ...\n"; | |
246 | pred_test('!exists ENABLED', 0, undef); | |
247 | pred_test('!exists MISSING', 1, undef); | |
248 | pred_test('!!exists ENABLED', 1, undef); | |
249 | pred_test('!!exists MISSING', 0, undef); | |
250 | pred_test('!!!exists ENABLED', 0, undef); | |
251 | pred_test('!!!exists MISSING', 1, undef); | |
252 | ||
253 | print "TEST: $test_total: parentheses tests ...\n"; | |
254 | pred_test('(exists ENABLED)', 1, undef); | |
255 | pred_test('((exists ENABLED))', 1, undef); | |
256 | pred_test('(((exists ENABLED)))', 1, undef); | |
257 | pred_test('(exists MISSING)', 0, undef); | |
258 | pred_test('((exists MISSING))', 0, undef); | |
259 | pred_test('(((exists MISSING)))', 0, undef); | |
260 | ||
261 | pred_test('(!exists ENABLED)', 0, undef); | |
262 | pred_test('((!exists ENABLED))', 0, undef); | |
263 | pred_test('(((!exists ENABLED)))', 0, undef); | |
264 | pred_test('(!exists MISSING)', 1, undef); | |
265 | pred_test('((!exists MISSING))', 1, undef); | |
266 | pred_test('(((!exists MISSING)))', 1, undef); | |
267 | ||
268 | pred_test('((!(exists ENABLED)))', 0, undef); | |
269 | pred_test('((!(exists MISSING)))', 1, undef); | |
270 | pred_test('(!((exists ENABLED)))', 0, undef); | |
271 | pred_test('(!((exists MISSING)))', 1, undef); | |
272 | pred_test('!(((exists ENABLED)))', 0, undef); | |
273 | pred_test('!(((exists MISSING)))', 1, undef); | |
274 | pred_test('!((!(exists ENABLED)))', 1, undef); | |
275 | pred_test('!((!(exists MISSING)))', 0, undef); | |
276 | pred_test('!(!(!(exists ENABLED)))', 0, undef); | |
277 | pred_test('!(!(!(exists MISSING)))', 1, undef); | |
278 | ||
279 | pred_test('(', undef, $eclose); | |
280 | pred_test('()(', undef, $eclose); | |
281 | pred_test('(())(', undef, $eclose); | |
282 | pred_test('((()))(', undef, $eclose); | |
283 | pred_test('(()', undef, $eclose); | |
284 | pred_test('((())', undef, $eclose); | |
285 | pred_test('(((()))', undef, $eclose); | |
286 | pred_test('(()()', undef, $eclose); | |
287 | pred_test('((())()', undef, $eclose); | |
288 | ||
289 | pred_test(')', undef, $eopen); | |
290 | pred_test('())', undef, $eopen); | |
291 | pred_test('(()))', undef, $eopen); | |
292 | pred_test('((())))', undef, $eopen); | |
293 | ||
294 | print "TEST: $test_total: binary and tests ...\n"; | |
295 | ||
296 | pred_test('exists ENABLED &', undef, $ebinary); | |
297 | pred_test('& exists ENABLED', undef, $ebinary); | |
298 | pred_test('exists ENABLED & & exists ENABLED', undef, $ebinary); | |
299 | ||
300 | pred_test('exists MISSING & exists MISSING', 0, undef); | |
301 | pred_test('exists MISSING & exists ENABLED', 0, undef); | |
302 | pred_test('exists ENABLED & exists MISSING', 0, undef); | |
303 | pred_test('exists ENABLED & exists ENABLED', 1, undef); | |
304 | ||
305 | pred_test('exists MISSING & exists MISSING & exists MISSING', 0, undef); | |
306 | pred_test('exists MISSING & exists MISSING & exists ENABLED', 0, undef); | |
307 | pred_test('exists MISSING & exists ENABLED & exists MISSING', 0, undef); | |
308 | pred_test('exists MISSING & exists ENABLED & exists ENABLED', 0, undef); | |
309 | pred_test('exists ENABLED & exists MISSING & exists MISSING', 0, undef); | |
310 | pred_test('exists ENABLED & exists MISSING & exists ENABLED', 0, undef); | |
311 | pred_test('exists ENABLED & exists ENABLED & exists MISSING', 0, undef); | |
312 | pred_test('exists ENABLED & exists ENABLED & exists ENABLED', 1, undef); | |
313 | ||
314 | print "TEST: $test_total: binary or tests ...\n"; | |
315 | ||
316 | pred_test('exists ENABLED |', undef, $ebinary); | |
317 | pred_test('| exists ENABLED', undef, $ebinary); | |
318 | pred_test('exists ENABLED | | exists ENABLED', undef, $ebinary); | |
319 | ||
320 | pred_test('exists MISSING | exists MISSING', 0, undef); | |
321 | pred_test('exists MISSING | exists ENABLED', 1, undef); | |
322 | pred_test('exists ENABLED | exists MISSING', 1, undef); | |
323 | pred_test('exists ENABLED | exists ENABLED', 1, undef); | |
324 | ||
325 | pred_test('exists MISSING | exists MISSING | exists MISSING', 0, undef); | |
326 | pred_test('exists MISSING | exists MISSING | exists ENABLED', 1, undef); | |
327 | pred_test('exists MISSING | exists ENABLED | exists MISSING', 1, undef); | |
328 | pred_test('exists MISSING | exists ENABLED | exists ENABLED', 1, undef); | |
329 | pred_test('exists ENABLED | exists MISSING | exists MISSING', 1, undef); | |
330 | pred_test('exists ENABLED | exists MISSING | exists ENABLED', 1, undef); | |
331 | pred_test('exists ENABLED | exists ENABLED | exists MISSING', 1, undef); | |
332 | pred_test('exists ENABLED | exists ENABLED | exists ENABLED', 1, undef); | |
333 | ||
334 | print "TEST: $test_total: binary or/and combination tests ...\n"; | |
335 | ||
336 | pred_test('exists MISSING | exists MISSING & exists MISSING', 0, undef); | |
337 | pred_test('exists MISSING | exists MISSING & exists ENABLED', 0, undef); | |
338 | pred_test('exists MISSING | exists ENABLED & exists MISSING', 0, undef); | |
339 | pred_test('exists MISSING | exists ENABLED & exists ENABLED', 1, undef); | |
340 | pred_test('exists ENABLED | exists MISSING & exists MISSING', 1, undef); | |
341 | pred_test('exists ENABLED | exists MISSING & exists ENABLED', 1, undef); | |
342 | pred_test('exists ENABLED | exists ENABLED & exists MISSING', 1, undef); | |
343 | pred_test('exists ENABLED | exists ENABLED & exists ENABLED', 1, undef); | |
344 | ||
345 | print "TEST: $test_total: binary and/or combination tests ...\n"; | |
346 | ||
347 | pred_test('exists MISSING & exists MISSING | exists MISSING', 0, undef); | |
348 | pred_test('exists MISSING & exists MISSING | exists ENABLED', 0, undef); | |
349 | pred_test('exists MISSING & exists ENABLED | exists MISSING', 0, undef); | |
350 | pred_test('exists MISSING & exists ENABLED | exists ENABLED', 0, undef); | |
351 | pred_test('exists ENABLED & exists MISSING | exists MISSING', 0, undef); | |
352 | pred_test('exists ENABLED & exists MISSING | exists ENABLED', 1, undef); | |
353 | pred_test('exists ENABLED & exists ENABLED | exists MISSING', 1, undef); | |
354 | pred_test('exists ENABLED & exists ENABLED | exists ENABLED', 1, undef); | |
355 | ||
356 | print "TEST: $test_total: cut tests ...\n"; | |
357 | pred_test('(arch MYARCH & exists MISSING) | exists ENABLED', 1, undef); | |
358 | pred_test('(arch MYARCH &/ exists MISSING) | exists ENABLED', 0, undef); | |
359 | ||
360 | $test_total--; | |
361 | print "TEST: $test_good/$test_total succeeded\n"; | |
362 | ||
363 | exit $exit_val; | |
364 | } | |
365 | ||
366 | # Load up the current configuration values -- FATAL if this fails | |
367 | print "$P: $config: loading config\n"; | |
368 | open(CONFIG, "<$config") || die "$P: $config: open failed -- $! -- aborting\n"; | |
369 | while (<CONFIG>) { | |
370 | # Pull out values. | |
371 | /^#*\s*(CONFIG_\w+)[\s=](.*)$/ or next; | |
372 | if ($2 eq 'is not set') { | |
373 | $values{$1} = 'n'; | |
374 | } else { | |
375 | $values{$1} = $2; | |
376 | } | |
377 | } | |
378 | close(CONFIG); | |
379 | ||
380 | # FATAL: Check if we have an enforcement list. | |
381 | my $pass = 0; | |
382 | my $total = 0; | |
383 | my $line = ''; | |
384 | print "$P: $checks: loading checks\n"; | |
385 | open(CHECKS, "<$checks") || die "$P: $checks: open failed -- $! -- aborting\n"; | |
386 | while (<CHECKS>) { | |
387 | /^#/ && next; | |
388 | chomp; | |
389 | ||
390 | $line .= $_; | |
391 | if ($line =~ /\\$/) { | |
392 | chop($line); | |
393 | $line .= " "; | |
394 | next; | |
395 | } | |
396 | $line =~ /^\s*$/ && next; | |
397 | ||
398 | #print "CHECK: <$line>\n"; | |
399 | $total++; | |
400 | my (undef, $result) = pred_exec($line); | |
401 | if (!$result) { | |
402 | print "$P: FAIL: $line\n"; | |
403 | $exit_val = $fail_exit; | |
404 | } else { | |
405 | $pass++; | |
406 | } | |
407 | ||
408 | $line = ''; | |
409 | } | |
410 | close(CHECKS); | |
411 | ||
412 | print "$P: $pass/$total checks passed -- exit $exit_val\n"; | |
413 | exit $exit_val; |