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>
32 foreach my $str (split(/([\\"])/, $string)) {
33 if ($inside && ($str ne "\"" || $slash)) {
36 # Check for backslash before quote
42 } elsif ($str eq "\\") {
44 } elsif ($str ne "") {
51 sub string_to_bytes
($)
54 my %is_escape = ('"', 0x22, '\'', 0x27, 'n', 0x0a, 'r', 0x0d, 'b', 0x08,
55 't', 0x09, 'f', 0x0c, 'a', 0x07, 'v', 0x0b, '?', 0x3f);
56 my (@ar, $slash, $len);
58 # scan string, interpret backslash escapes and write bytes to @ar
60 foreach my $ch (split(//, $string)) {
64 $ar[$len] = ord('\\');
67 } elsif ($slash && defined $is_escape{$ch}) {
68 # C99 backslash escapes: \\ \" \' \n \r \b \t \f \a \v \?
69 $ar[$len] = $is_escape{$ch};
73 # FIXME: C99 backslash escapes \nnn \xhh
74 die("Unknown backslash escape in message $string.");
88 my ($a, $b, $c, $i, $length, $len);
90 @ar = string_to_bytes
($string);
92 # add dummy elements to @ar to avoid if then else hell
93 push @ar, (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
98 for ($len = $length + 12; $len >= 12; $len -= 12) {
100 # add length for last round
103 $a += $ar[$i] + ($ar[$i+1]<<8) + ($ar[$i+2]<<16) + ($ar[$i+3]<<24);
104 $b += $ar[$i+4] + ($ar[$i+5]<<8) + ($ar[$i+6]<<16) + ($ar[$i+7]<<24);
106 $c += $ar[$i+8] + ($ar[$i+9]<<8) + ($ar[$i+10]<<16) + ($ar[$i+11]<<24);
108 $c += ($ar[$i+8]<<8) + ($ar[$i+9]<<16) + ($ar[$i+10]<<24);
110 $a &= 0xffffffff; $b &= 0xffffffff; $c &= 0xffffffff;
111 $a -= $b; $a -= $c; $a ^= ($c >> 13); $a &= 0xffffffff;
112 $b -= $c; $b -= $a; $b ^= ($a << 8); $b &= 0xffffffff;
113 $c -= $a; $c -= $b; $c ^= ($b >> 13); $c &= 0xffffffff;
114 $a -= $b; $a -= $c; $a ^= ($c >> 12); $a &= 0xffffffff;
115 $b -= $c; $b -= $a; $b ^= ($a << 16); $b &= 0xffffffff;
116 $c -= $a; $c -= $b; $c ^= ($b >> 5); $c &= 0xffffffff;
117 $a -= $b; $a -= $c; $a ^= ($c >> 3); $a &= 0xffffffff;
118 $b -= $c; $b -= $a; $b ^= ($a << 10); $b &= 0xffffffff;
119 $c -= $a; $c -= $b; $c ^= ($b >> 15); $c &= 0xffffffff;
125 sub add_kmsg_desc
($$$$$$)
127 my ($component, $text, $sev, $argv, $desc, $user) = @_;
130 $text = remove_quotes
($text);
131 $hash = substr(sprintf("%08x", calc_jhash
($text)), 2, 6);
132 $tag = $component . "." . $hash;
134 if ($kmsg_desc{$tag}) {
135 if ($text ne $kmsg_desc{$tag}->{'TEXT'}) {
136 warn "Duplicate message with tag $tag\n";
137 warn " --- $kmsg_desc{$tag}->{'TEXT'}\n";
140 warn "Duplicate message description for \"$text\"\n";
145 $kmsg_desc{$tag}->{'TEXT'} = $text;
146 $kmsg_desc{$tag}->{'SEV'} = $sev;
147 $kmsg_desc{$tag}->{'ARGV'} = $argv;
148 $kmsg_desc{$tag}->{'DESC'} = $desc;
149 $kmsg_desc{$tag}->{'USER'} = $user;
152 sub add_kmsg_print($$$$)
154 my ($component, $sev, $text, $argv) = @_;
155 my ($hash, $tag, $count, $parm);
157 $text = remove_quotes($text);
158 $hash = substr(sprintf("%08x", calc_jhash($text)), 2, 6);
159 $tag = $component . "." . $hash;
161 # Pretty print severity
162 $sev =~ s/"0"/Emerg/;
163 $sev =~ s/"1"/Alert/;
164 $sev =~ s/"2"/Critical/;
165 $sev =~ s/"3"/Error/;
166 $sev =~ s/"4"/Warning/;
167 $sev =~ s/"5"/Notice/;
168 $sev =~ s/"6"/Informational/;
169 $sev =~ s/"7"/Debug/;
170 $kmsg_print{$kmsg_count}->{'TAG'} = $tag;
171 $kmsg_print{$kmsg_count}->{'TEXT'} = $text;
172 $kmsg_print{$kmsg_count}->{'SEV'} = $sev;
173 $kmsg_print{$kmsg_count}->{'ARGV'} = $argv;
177 sub process_source_file($$)
179 my ($component, $file) = @_;
181 my ($text, $sev, $argv, $desc, $user);
183 if (!open(FD, "$file")) {
190 # kmsg message component: #define KMSG_COMPONENT "<component
>"
191 if (/^#define\s+KMSG_COMPONENT\s+\"(.*)\"[^\"]*$/o) {
195 # single line kmsg for undocumented messages, format:
196 # /*? Text: "<message
>" */
197 if (/^\s*\/\*\?\s*Text:\s*(\".*\")\s*\*\/\s*$/o) {
198 add_kmsg_desc($component, $1, "", "", "", "");
200 # kmsg message start: '/*?'
201 if (/^\s*\/\*\?\s*$/o) {
203 ($text, $sev, $argv, $desc, $user) = ( "", "", "", "", "" );
205 } elsif ($state == 1) {
206 # kmsg message end: ' */'
207 if (/^\s*\*\/\s*/o) {
208 add_kmsg_desc($component, $text, $sev, $argv, $desc, $user);
211 # kmsg message text: ' * Text: "<message
>"'
212 elsif (/^\s*\*\s*Text:\s*(\".*\")\s*$/o) {
215 # kmsg message severity: ' * Severity: <sev>'
216 elsif (/^\s*\*\s*Severity:\s*(\S*)\s*$/o) {
219 # kmsg message parameter: ' * Parameter: <argv>'
220 elsif (/^\s*\*\s*Parameter:\s*(\S*)\s*$/o) {
228 # kmsg message description start: ' * Description:'
229 elsif (/^\s*\*\s*Description:\s*(\S*)\s*$/o) {
237 # kmsg has unrecognizable lines
239 warn "Warning
(${file
}:$.): Cannot understand
$_";
243 } elsif ($state == 2) {
244 # kmsg message end: ' */'
246 warn "Warning
(${file
}:$.): Missing description
, skipping message
";
250 # kmsg message description start: ' * Description:'
251 elsif (/^\s*\*\s*Description:\s*$/o) {
255 # kmsg message parameter line: ' * <argv>'
256 elsif (/^\s*\*(.*)$/o) {
259 warn "Warning
(${file
}:$.): Cannot understand
$_";
263 } elsif ($state == 3) {
264 # kmsg message end: ' */'
265 if (/^\s*\*\/\s*/o) {
266 add_kmsg_desc($component, $text, $sev, $argv, $desc, $user);
269 # kmsg message description start: ' * User action:'
270 elsif (/^\s*\*\s*User action:\s*$/o) {
274 # kmsg message description line: ' * <text>'
275 elsif (/^\s*\*\s*(.*)$/o) {
278 warn "Warning
(${file
}:$.): Cannot understand
$_";
282 } elsif ($state == 4) {
283 # kmsg message end: ' */'
284 if (/^\s*\*\/\s*/o) {
285 add_kmsg_desc($component, $text, $sev, $argv, $desc, $user);
288 # kmsg message user action line: ' * <text>'
289 elsif (/^\s*\*\s*(.*)$/o) {
292 warn "Warning
(${file
}:$.): Cannot understand
$_";
301 sub process_cpp_file($$$$)
303 my ($cc, $options, $file, $component) = @_;
305 open(FD, "$cc $gcc_options|") or die ("Preprocessing failed
.");
309 if (/.*__KMSG_PRINT\(\s*(\S*)\s*(\S*)\s*_FMT_(.*)_ARGS_\s*(.*)?_END_\s*\)/o) {
310 if ($component ne "") {
311 add_kmsg_print($component, $2, $3, $4);
313 warn "Error
(${file
}:$.): kmsg without component
\n";
316 } elsif (/.*__KMSG_DEV\(\s*(\S*)\s*(\S*)\s*_FMT_(.*)_ARGS_\s*(.*)?_END_\s*\)/o) {
317 if ($component ne "") {
318 add_kmsg_print($component, $2, "\"%s: \"" . $3, $4);
320 warn "Error
(${file
}:$.): kmsg without component
\n";
327 sub check_messages($)
329 my $component = "@_";
332 for ($i = 0; $i < $kmsg_count; $i++) {
333 $tag = $kmsg_print{$i}->{'TAG'};
334 if (!defined($kmsg_desc{$tag})) {
335 add_kmsg_desc($component,
336 "\"" . $kmsg_print{$i}->{'TEXT'} . "\"",
337 $kmsg_print{$i}->{'SEV'},
338 $kmsg_print{$i}->{'ARGV'},
339 "Please insert description here
",
340 "What
is the user supposed to
do");
341 $kmsg_desc{$tag}->{'CHECK'} = 1;
343 warn "$component: Missing description
for: ".
344 $kmsg_print{$i}->{'TEXT'}."\n";
348 if ($kmsg_desc{$tag}->{'SEV'} ne "" &&
349 $kmsg_desc{$tag}->{'SEV'} ne $kmsg_print{$i}->{'SEV'}) {
350 warn "Message severity mismatch
for \"$kmsg_print{$i}->{'TEXT'}\"\n";
351 warn " --- $kmsg_desc{$tag}->{'SEV'}\n";
352 warn " +++ $kmsg_print{$i}->{'SEV'}\n";
358 sub print_templates()
360 print "Templates
for missing messages
:\n";
361 foreach $tag ( sort { $kmsg_desc{$a} <=> $kmsg_desc{$b} } keys %kmsg_desc ) {
362 if (!defined($kmsg_desc{$tag}->{'CHECK'})) {
366 print " * Text
: \"$kmsg_desc{$tag}->{'TEXT'}\"\n";
367 print " * Severity
: $kmsg_desc{$tag}->{'SEV'}\n";
368 $argv = $kmsg_desc{$tag}->{'ARGV'};
370 print " * Parameter
:\n";
371 @parms = split(/\s*,\s*/,$kmsg_desc{$tag}->{'ARGV'});
373 foreach $parm (@parms) {
375 if (!($parm eq "")) {
376 print " * \
@$count: $parm\n";
380 print " * Description
:\n";
381 print " * $kmsg_desc{$tag}->{'DESC'}\n";
382 print " * User action
:\n";
383 print " * $kmsg_desc{$tag}->{'USER'}\n";
388 sub write_man_pages()
392 for ($i = 0; $i < $kmsg_count; $i++) {
393 $tag = $kmsg_print{$i}->{'TAG'};
394 if (!defined($kmsg_desc{$tag}) ||
395 defined($kmsg_desc{$tag}->{'CHECK'}) ||
396 $kmsg_desc{$tag}->{'DESC'} eq "") {
399 $file = $objtree . "man
/" . $tag . ".9";
400 if (!open(WR, ">$file")) {
401 warn "Error
: Cannot
open file
$file\n";
405 print WR ".TH
\"$tag\" 9 \"Linux Messages\" LINUX\n";
406 print WR
".SH Message\n";
407 print WR
$tag . ": " . $kmsg_desc{$tag}->{'TEXT'} . "\n";
408 print WR
".SH Severity\n";
409 print WR
"$kmsg_desc{$tag}->{'SEV'}\n";
410 $argv = $kmsg_desc{$tag}->{'ARGV'};
412 print WR
".SH Parameters\n";
413 @parms = split(/\s*\n\s*/,$kmsg_desc{$tag}->{'ARGV'});
414 foreach $parm (@parms) {
415 $parm =~ s/^\s*(.*)\s*$/$1/;
416 if (!($parm eq "")) {
417 print WR
"$parm\n\n";
421 print WR
".SH Description";
422 print WR
"$kmsg_desc{$tag}->{'DESC'}\n";
423 $user = $kmsg_desc{$tag}->{'USER'};
425 print WR
".SH User action";
431 if (defined($ENV{'srctree'})) {
432 $srctree = "$ENV{'srctree'}" . "/";
437 if (defined($ENV{'objtree'})) {
438 $objtree = "$ENV{'objtree'}" . "/";
443 if (defined($ENV{'SRCARCH'})) {
444 $srcarch = "$ENV{'SRCARCH'}" . "/";
446 print "kmsg-doc called without a valid \$SRCARCH\n";
453 $gcc_options = "-E -D __KMSG_CHECKER ";
454 foreach $tmp (@ARGV) {
457 $gcc_options .= " $tmp";
461 $component = process_source_file
("", $filename);
462 if ($component ne "") {
463 process_source_file
($component, $srctree . "Documentation/kmsg/" .
464 $srcarch . $component);
465 process_source_file
($component, $srctree . "Documentation/kmsg/" .
469 process_cpp_file
($cc, $gcc_options, $filename, $component);
470 if ($option eq "check") {
471 if (check_messages
($component)) {
474 } elsif ($option eq "print") {