3 # kmsg kernel messages check and print tool.
5 # To check the source code for missing messages the script is called
6 # with check, the name compiler and the compile parameters
7 # kmsg-doc check $(CC) $(c_flags) $<
8 # To create man pages for the messages the script is called with
9 # kmsg-doc print $(CC) $(c_flags) $<
11 # Copyright IBM Corp. 2008
12 # Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
13 # Michael Holzheu <holzheu@linux.vnet.ibm.com>
33 foreach my $str (split(/([\\"])/, $string)) {
34 if ($inside && ($str ne "\"" || $slash)) {
37 # Check for backslash before quote
43 } elsif ($str eq "\\") {
45 } elsif ($str ne "") {
52 sub string_to_bytes($)
55 my %is_escape = ('"', 0x22, '\'', 0x27, 'n', 0x0a, 'r', 0x0d, 'b', 0x08,
56 't', 0x09, 'f', 0x0c, 'a', 0x07, 'v', 0x0b, '?', 0x3f);
57 my (@ar, $slash, $len);
59 # scan string, interpret backslash escapes and write bytes to @ar
61 foreach my $ch (split(//, $string)) {
65 $ar[$len] = ord('\\');
68 } elsif ($slash && defined $is_escape{$ch}) {
69 # C99 backslash escapes: \\ \" \' \n \r \b \t \f \a \v \?
70 $ar[$len] = $is_escape{$ch};
74 # FIXME: C99 backslash escapes \nnn \xhh
75 die("Unknown backslash escape in message $string.");
89 my ($a, $b, $c, $i, $length, $len);
91 @ar = string_to_bytes($string);
93 # add dummy elements to @ar to avoid if then else hell
94 push @ar, (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
99 for ($len = $length + 12; $len >= 12; $len -= 12) {
101 # add length for last round
104 $a += $ar[$i] + ($ar[$i+1]<<8) + ($ar[$i+2]<<16) + ($ar[$i+3]<<24);
105 $b += $ar[$i+4] + ($ar[$i+5]<<8) + ($ar[$i+6]<<16) + ($ar[$i+7]<<24);
107 $c += $ar[$i+8] + ($ar[$i+9]<<8) + ($ar[$i+10]<<16) + ($ar[$i+11]<<24);
109 $c += ($ar[$i+8]<<8) + ($ar[$i+9]<<16) + ($ar[$i+10]<<24);
111 $a &= 0xffffffff; $b &= 0xffffffff; $c &= 0xffffffff;
112 $a -= $b; $a -= $c; $a ^= ($c >> 13); $a &= 0xffffffff;
113 $b -= $c; $b -= $a; $b ^= ($a << 8); $b &= 0xffffffff;
114 $c -= $a; $c -= $b; $c ^= ($b >> 13); $c &= 0xffffffff;
115 $a -= $b; $a -= $c; $a ^= ($c >> 12); $a &= 0xffffffff;
116 $b -= $c; $b -= $a; $b ^= ($a << 16); $b &= 0xffffffff;
117 $c -= $a; $c -= $b; $c ^= ($b >> 5); $c &= 0xffffffff;
118 $a -= $b; $a -= $c; $a ^= ($c >> 3); $a &= 0xffffffff;
119 $b -= $c; $b -= $a; $b ^= ($a << 10); $b &= 0xffffffff;
120 $c -= $a; $c -= $b; $c ^= ($b >> 15); $c &= 0xffffffff;
126 sub add_kmsg_desc($$$$$$)
128 my ($component, $text, $sev, $argv, $desc, $user) = @_;
131 $text = remove_quotes($text);
132 $hash = substr(sprintf("%08x", calc_jhash($text)), 2, 6);
133 $tag = $component . "." . $hash;
135 if ($kmsg_desc{$tag}) {
136 if ($text ne $kmsg_desc{$tag}->{'TEXT'}) {
137 warn "Duplicate message with tag $tag\n";
138 warn " --- $kmsg_desc{$tag}->{'TEXT'}\n";
141 warn "Duplicate message description for \"$text\"\n";
146 $kmsg_desc{$tag}->{'TEXT'} = $text;
147 $kmsg_desc{$tag}->{'SEV'} = $sev;
148 $kmsg_desc{$tag}->{'ARGV'} = $argv;
149 $kmsg_desc{$tag}->{'DESC'} = $desc;
150 $kmsg_desc{$tag}->{'USER'} = $user;
153 sub add_kmsg_print($$$$)
155 my ($component, $sev, $text, $argv) = @_;
156 my ($hash, $tag, $count, $parm);
158 $text = remove_quotes($text);
159 $hash = substr(sprintf("%08x", calc_jhash($text)), 2, 6);
160 $tag = $component . "." . $hash;
162 # Pretty print severity
163 $sev =~ s/"<0>"/Emerg/;
164 $sev =~ s/"<1>"/Alert/;
165 $sev =~ s/"<2>"/Critical/;
166 $sev =~ s/"<3>"/Error/;
167 $sev =~ s/"<4>"/Warning/;
168 $sev =~ s/"<5>"/Notice/;
169 $sev =~ s/"<6>"/Informational/;
170 $sev =~ s/"<7>"/Debug/;
171 $kmsg_print{$kmsg_count}->{'TAG'} = $tag;
172 $kmsg_print{$kmsg_count}->{'TEXT'} = $text;
173 $kmsg_print{$kmsg_count}->{'SEV'} = $sev;
174 $kmsg_print{$kmsg_count}->{'ARGV'} = $argv;
178 sub process_source_file($$)
180 my ($component, $file) = @_;
182 my ($text, $sev, $argv, $desc, $user);
184 if (!open(FD, "$file")) {
191 # kmsg message component: #define KMSG_COMPONENT "<component>"
192 if (/^#define\s+KMSG_COMPONENT\s+\"(.*)\"[^\"]*$/o) {
196 # single line kmsg for undocumented messages, format:
197 # /*? Text: "<message>" */
198 if (/^\s*\/\*\?\s*Text:\s*(\".*\")\s*\*\/\s*$/o) {
199 add_kmsg_desc($component, $1, "", "", "", "");
201 # kmsg message start: '/*?'
202 if (/^\s*\/\*\?\s*$/o) {
204 ($text, $sev, $argv, $desc, $user) = ( "", "", "", "", "" );
206 } elsif ($state == 1) {
207 # kmsg message end: ' */'
208 if (/^\s*\*\/\s*/o) {
209 add_kmsg_desc($component, $text, $sev, $argv, $desc, $user);
212 # kmsg message text: ' * Text: "<message>"'
213 elsif (/^\s*\*\s*Text:\s*(\".*\")\s*$/o) {
216 # kmsg message severity: ' * Severity: <sev>'
217 elsif (/^\s*\*\s*Severity:\s*(\S*)\s*$/o) {
220 # kmsg message parameter: ' * Parameter: <argv>'
221 elsif (/^\s*\*\s*Parameter:\s*(\S*)\s*$/o) {
229 # kmsg message description start: ' * Description:'
230 elsif (/^\s*\*\s*Description:\s*(\S*)\s*$/o) {
238 # kmsg has unrecognizable lines
240 warn "Warning(${file}:$.): Cannot understand $_";
244 } elsif ($state == 2) {
245 # kmsg message end: ' */'
247 warn "Warning(${file}:$.): Missing description, skipping message";
251 # kmsg message description start: ' * Description:'
252 elsif (/^\s*\*\s*Description:\s*$/o) {
256 # kmsg message parameter line: ' * <argv>'
257 elsif (/^\s*\*(.*)$/o) {
260 warn "Warning(${file}:$.): Cannot understand $_";
264 } elsif ($state == 3) {
265 # kmsg message end: ' */'
266 if (/^\s*\*\/\s*/o) {
267 add_kmsg_desc($component, $text, $sev, $argv, $desc, $user);
270 # kmsg message description start: ' * User action:'
271 elsif (/^\s*\*\s*User action:\s*$/o) {
275 # kmsg message description line: ' * <text>'
276 elsif (/^\s*\*\s*(.*)$/o) {
279 warn "Warning(${file}:$.): Cannot understand $_";
283 } elsif ($state == 4) {
284 # kmsg message end: ' */'
285 if (/^\s*\*\/\s*/o) {
286 add_kmsg_desc($component, $text, $sev, $argv, $desc, $user);
289 # kmsg message user action line: ' * <text>'
290 elsif (/^\s*\*\s*(.*)$/o) {
293 warn "Warning(${file}:$.): Cannot understand $_";
302 sub process_cpp_file($$$$)
304 my ($cc, $options, $file, $component) = @_;
306 open(FD, "$cc $gcc_options|") or die ("Preprocessing failed.");
310 if (/.*__KMSG_PRINT\(\s*(\S*)\s*_FMT_(.*)_ARGS_\s*"(.*)"\s*_END_\s*\)/o) {
311 if ($component ne "") {
312 add_kmsg_print($component, $1, $2, $3);
314 warn "Error(${file}:$.): kmsg without component\n";
317 } elsif (/.*__KMSG_DEV\(\s*(\S*)\s*_FMT_(.*)_ARGS_\s*(.*)?_END_\s*\)/o) {
318 if ($component ne "") {
319 add_kmsg_print($component, $1, "\"%s: \"" . $2, $3);
321 warn "Error(${file}:$.): kmsg without component\n";
328 sub check_messages($)
330 my $component = "@_";
333 for ($i = 0; $i < $kmsg_count; $i++) {
334 $tag = $kmsg_print{$i}->{'TAG'};
335 if (!defined($kmsg_desc{$tag})) {
336 add_kmsg_desc($component,
337 "\"" . $kmsg_print{$i}->{'TEXT'} . "\"",
338 $kmsg_print{$i}->{'SEV'},
339 $kmsg_print{$i}->{'ARGV'},
340 "Please insert description here",
341 "What is the user supposed to do");
342 $kmsg_desc{$tag}->{'CHECK'} = 1;
344 warn "$component: Missing description for: ".
345 $kmsg_print{$i}->{'TEXT'}."\n";
349 if ($kmsg_desc{$tag}->{'SEV'} ne "" &&
350 $kmsg_desc{$tag}->{'SEV'} ne $kmsg_print{$i}->{'SEV'}) {
351 warn "Message severity mismatch for \"$kmsg_print{$i}->{'TEXT'}\"\n";
352 warn " --- $kmsg_desc{$tag}->{'SEV'}\n";
353 warn " +++ $kmsg_print{$i}->{'SEV'}\n";
359 sub print_templates()
361 print "Templates for missing messages:\n";
362 foreach $tag ( sort { $kmsg_desc{$a} <=> $kmsg_desc{$b} } keys %kmsg_desc ) {
363 if (!defined($kmsg_desc{$tag}->{'CHECK'})) {
367 print " * Text: \"$kmsg_desc{$tag}->{'TEXT'}\"\n";
368 print " * Severity: $kmsg_desc{$tag}->{'SEV'}\n";
369 $argv = $kmsg_desc{$tag}->{'ARGV'};
371 print " * Parameter:\n";
372 @parms = split(/\s*,\s*/,$kmsg_desc{$tag}->{'ARGV'});
374 foreach $parm (@parms) {
376 if (!($parm eq "")) {
377 print " * \@$count: $parm\n";
381 print " * Description:\n";
382 print " * $kmsg_desc{$tag}->{'DESC'}\n";
383 print " * User action:\n";
384 print " * $kmsg_desc{$tag}->{'USER'}\n";
389 sub write_man_pages()
393 for ($i = 0; $i < $kmsg_count; $i++) {
394 $tag = $kmsg_print{$i}->{'TAG'};
395 if (!defined($kmsg_desc{$tag}) ||
396 defined($kmsg_desc{$tag}->{'CHECK'}) ||
397 $kmsg_desc{$tag}->{'DESC'} eq "") {
400 $file = $objtree . "man/" . $tag . ".9";
401 if (!open(WR, ">$file")) {
402 warn "Error: Cannot open file $file\n";
406 print WR ".TH \"$tag\" 9 \"Linux Messages\" LINUX\n";
407 print WR ".SH Message\n";
408 print WR $tag . ": " . $kmsg_desc{$tag}->{'TEXT'} . "\n";
409 print WR ".SH Severity\n";
410 print WR "$kmsg_desc{$tag}->{'SEV'}\n";
411 $argv = $kmsg_desc{$tag}->{'ARGV'};
413 print WR ".SH Parameters\n";
414 @parms = split(/\s*\n\s*/,$kmsg_desc{$tag}->{'ARGV'});
415 foreach $parm (@parms) {
416 $parm =~ s/^\s*(.*)\s*$/$1/;
417 if (!($parm eq "")) {
418 print WR "$parm\n\n";
422 print WR ".SH Description";
423 print WR "$kmsg_desc{$tag}->{'DESC'}\n";
424 $user = $kmsg_desc{$tag}->{'USER'};
426 print WR ".SH User action";
432 if (defined($ENV{'srctree'})) {
433 $srctree = "$ENV{'srctree'}" . "/";
438 if (defined($ENV{'objtree'})) {
439 $objtree = "$ENV{'objtree'}" . "/";
444 if (defined($ENV{'SRCARCH'})) {
445 $srcarch = "$ENV{'SRCARCH'}" . "/";
447 print "kmsg-doc called without a valid \$SRCARCH\n";
454 $gcc_options = "-E -D __KMSG_CHECKER ";
455 foreach $tmp (@ARGV) {
458 $gcc_options .= " $tmp";
462 $component = process_source_file("", $filename);
463 if ($component ne "") {
464 process_source_file($component, $srctree . "Documentation/kmsg/" .
465 $srcarch . $component);
466 process_source_file($component, $srctree . "Documentation/kmsg/" .
470 process_cpp_file($cc, $gcc_options, $filename, $component);
471 if ($option eq "check") {
472 if (check_messages($component)) {
475 } elsif ($option eq "print") {