Re: [RFC/PATCH] Documentation of kernel messages

From: Andrew Morton
Date: Wed Jun 13 2007 - 14:16:38 EST


> On Wed, 13 Jun 2007 17:06:57 +0200 holzheu <holzheu@xxxxxxxxxxxxxxxxxx> wrote:
> Greetings,
>
> The operation of a Linux system sometimes requires to decode the
> meaning of a specific kernel message, e.g. an error message of a
> driver. Especially on our mainframe zSeries platform system
> administrators want to have descriptions for Linux kernel messages.
> They are used to that, because all other operating systems on that
> platform like z/OS, z/VM or z/VSE have message catalogs with detailed
> descriptions about the semantics of the messages.
>
> In general we think, that also for Linux it is a good thing to have
> documentation for the most important kernel/driver messages. Even
> kernel hackers not always are aware of the meaning of kernel messages
> for components, which they don't know in detail. Most of the messages
> are self explaining but sometimes you get something like "Clocksource
> tsc unstable (delta = 7304132729 ns)" and you wonder if your system is
> going to explode.
>
> Unfortunately currently there is no general infrastructure in the Linux
> kernel for the documentation of messages. I worked on a proposal, how
> that could be implemented in an easy way using the already existing
> kernel-doc infrastructure and using printk. The proposal is as follows
>
> 1. We use message identifiers in order to map messages to message
> descriptions. A message identifier consists out of a component name and
> within that component unique message number.
>
> 2. Messages and message descriptions are maintained together in the
> kernel sources in order to keep them up to date. Messages catalog are
> generated automatically for exactly one kernel level.
>
> 3. A special tool checks, if messages are not documented or if there
> are message descriptions without corresponding messages.
>
> 4. We use the already existing kernel-doc tool to generate an online
> message catalog or e.g. a pdf for offline documentation.
>
> Current prototype implementation:
> =================================
>
> The structure of a kernel message is: <component>.<msg number>: <msg>
>
> * component: Name of the kernel or driver component e.g. "pci", "ide",
> etc.
> * msg number: Within the component unique number of a kernel message.
> * msg: printk message
>
> New macros KMSG_ERR(), KMSG_WARN(), etc. are defined, which have to be
> used in printk. These macros have as parameter the message number and
> are using a per c-file defined macro KMSG_COMPONENT.
>
> Example: Define message 2 in component "kmsgtest":
>
> #define KMSG_COMPONENT "kmsgtest"
>
> void f(void)
> {
> printk(KMSG_ERR(1) "device %x not online\n", devno);
> }
>
> The output of that kernel message would be:
> "kmsgtest.1: device 4711 not online"
>
> The messages have to be documented within the C source file
> in the following way:
>
> /**
> * message
> * @0: device number of device.
> *
> * Description:
> * An operation has been performed on the msgtest device, but the
> * device has not been set online. Therefore the operation failed
> *
> * User Response:
> * Operator should set device online.
> * Issue "chccwdev -e <device number>".
> *
> */
>
> KMSG_DOC(kmsgtest, 2, "Device %x not online");
>
> I created a patch for the kernel-doc tool so it can be used to generate
> a catalog of all kernel messages:
>
> >> kernel-doc -man kmsgtest.c > kmsgtest.2
> >> man ./kmsgtest.2
>
> # Kernel API(9) Linux Messages Kernel API(9)
> #
> # MESSAGE:
> # kmsgtest.2: "device %x not online"
> #
> # Parameter:
> # 1 Device number of device.
> #
> # Description:
> # An operation has been performed on the msgtest device, but
> # the device has not been set online. Therefore the operation failed.
> #
> # User Response:
> # Operator should set device online.
> # Issue "chccwdev -e <device number>".
> #
> # May 2007 kmsgtest.2 Kernel API(9)
>
> A nice thing would be to include the online kernel message catalog in
> the kernel rpm. One possibility for that would be to have one man page
> per message. If an operator finds the message kmsgtest.2 in
> var/log/messages and wants to know what the message means, he simply
> issues "man kmsgtest.2" and gets the description.
>
> To ensure that all messages are documented and there are no message
> descriptions without corresponding messages, a checker tool is
> provided. To enable message checking, in the toplevel Makefile the
> following has to be added:
>
> CHECK = scripts/kmsg_check.pl check
>
> To enable message checking during kernel build, the "C" option has
> to be used:
>
> >> make modules C=1
> CHK include/linux/version.h
> CHK include/linux/utsrelease.h
> CHECK drivers/kmsgtest/kmsgtest.c
> drivers/kmsgtest/kmsgtest.c: Missing description for: kmsgtest.1
> drivers/kmsgtest/kmsgtest.c: Description without message for: kmsgtest.3
>
> Please note, that the patch for the kernel-doc and kmsg-doc tools
> is just a prototype and is neither complete nor perfect.
>
> Michael
>
> Acked-by: Martin Schwidefsky <schwidefsky@xxxxxxxxxx>
> Acked-by: Heiko Carstens <heiko.carstens@xxxxxxxxxx>
> Signed-off-by: Michael Holzheu <holzheu@xxxxxxxxxxxxxxxxxxx>

Your proposal is similar to one I made to some Japanese developers
earlier this year. I was more modest, proposing that we

- add an enhanced printk

xxprintk(msgid, KERN_ERR "some text %d\n", some_number);

- An externally managed database will provide translations, diagnostics,
remedial actions, etc, keyed off the msgid string

- Format and management of the msgid hasn't been clearly identified yet
as far as I know. But all we really need is that each ID be unique,
kernel-wide. We develop a simple tool which can check the whole tree
for duplicated msgids.

- From a practical day-to-day POV what this means is that a person
from the kernel-messages team will prepare a patch for your driver
which adds the msgids and you the driver author should take care not
to break the tagging.

This is deliberately designed to be minimum-impact upon general
developers. We want a system in place where driver/fs/etc developers
can concentrate on what they do, and kernel-message developers can
as independently as possibe take care of what _they_ do.

- A project has started up and there is a mailing list (cc'ed here) and
meetings are happening at the LF collaboration summit this week.

Please see https://lists.linux-foundation.org/mailman/listinfo/lf_kernel_messages
and don't miss the next conference call ;)

(argh. The lf_kernel_messages archives are subscriber-only and it could be that
only members can post to it. Oh well. Please subscribe, and review the archives)

>
> Makefile | 5
> drivers/Makefile | 1
> drivers/kmsgtest/Makefile | 5
> drivers/kmsgtest/kmsgtest.c | 59 +++++++++++
> include/linux/kmsg.h | 32 ++++++
> scripts/kernel-doc | 116 +++++++++++++++++++++-
> scripts/kmsg-doc | 231 ++++++++++++++++++++++++++++++++++++++++++++
> 7 files changed, 445 insertions(+), 4 deletions(-)
>
> diff -Naur linux-2.6.21/Makefile linux-2.6.21-kmsg/Makefile
> --- linux-2.6.21/Makefile 2007-04-26 05:08:32.000000000 +0200
> +++ linux-2.6.21-kmsg/Makefile 2007-06-05 15:17:51.000000000 +0200
> @@ -293,9 +293,8 @@
> DEPMOD = /sbin/depmod
> KALLSYMS = scripts/kallsyms
> PERL = perl
> -CHECK = sparse
> -
> -CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF)
> +CHECK = scripts/kmsg-doc check
> +CHECKFLAGS =
> MODFLAGS = -DMODULE
> CFLAGS_MODULE = $(MODFLAGS)
> AFLAGS_MODULE = $(MODFLAGS)
> diff -Naur linux-2.6.21/drivers/Makefile linux-2.6.21-kmsg/drivers/Makefile
> --- linux-2.6.21/drivers/Makefile 2007-04-26 05:08:32.000000000 +0200
> +++ linux-2.6.21-kmsg/drivers/Makefile 2007-06-05 15:17:51.000000000 +0200
> @@ -8,6 +8,7 @@
> obj-$(CONFIG_PCI) += pci/
> obj-$(CONFIG_PARISC) += parisc/
> obj-$(CONFIG_RAPIDIO) += rapidio/
> +obj-m += kmsgtest/
> obj-y += video/
> obj-$(CONFIG_ACPI) += acpi/
> # PnP must come after ACPI since it will eventually need to check if acpi
> diff -Naur linux-2.6.21/drivers/kmsgtest/Makefile linux-2.6.21-kmsg/drivers/kmsgtest/Makefile
> --- linux-2.6.21/drivers/kmsgtest/Makefile 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.21-kmsg/drivers/kmsgtest/Makefile 2007-06-05 15:17:51.000000000 +0200
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for kernel message test module
> +#
> +
> +obj-m += kmsgtest.o
> diff -Naur linux-2.6.21/drivers/kmsgtest/kmsgtest.c linux-2.6.21-kmsg/drivers/kmsgtest/kmsgtest.c
> --- linux-2.6.21/drivers/kmsgtest/kmsgtest.c 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.21-kmsg/drivers/kmsgtest/kmsgtest.c 2007-06-05 15:17:51.000000000 +0200
> @@ -0,0 +1,59 @@
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/kmsg.h>
> +
> +static int devno = 0x4711;
> +static int status = 1;
> +
> +#define KMSG_COMPONENT "kmsgtest"
> +
> +static int __init kmsgtest_init(void)
> +{
> + printk(KMSG_INFO(1) "device %x has status %i\n", devno, status);
> + printk(KMSG_ERR(2) "device %x not online\n", devno);
> +
> + return 0;
> +}
> +
> +static void __exit kmsgtest_exit(void)
> +{
> + printk("kmsgtest module exit\n");
> +}
> +
> +module_init(kmsgtest_init);
> +module_exit(kmsgtest_exit);
> +
> +/**
> + * message
> + * @0: Device number of device
> + * @1: Status of device
> + *
> + * Description:
> + * Information message about the status of our virtual msgtest device. The
> + * following values for the status parameter are available.
> + *
> + * 0 - Device is offline
> + *
> + * 1 - Device is online
> + *
> + * 2 - Device is broken
> + *
> + * User Response:
> + * If device is broken, replace it or fix it.
> + */
> +
> +KMSG_DOC(kmsgtest, 1, "device %x has status %i");
> +
> +/**
> + * message
> + * @0: Device number of device.
> + *
> + * Description:
> + * An operation has been performed on the msgtest device, but the device has
> + * not been set online. Therefore the operation failed.
> + *
> + * User Response:
> + * Operator should set device online. Issue "chccwdev -e <device number>".
> + */
> +
> +KMSG_DOC(kmsgtest, 2, "device %x not online");
> diff -Naur linux-2.6.21/include/linux/kmsg.h linux-2.6.21-kmsg/include/linux/kmsg.h
> --- linux-2.6.21/include/linux/kmsg.h 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.21-kmsg/include/linux/kmsg.h 2007-06-05 15:17:51.000000000 +0200
> @@ -0,0 +1,32 @@
> +#ifndef _LINUX_KMSG_H
> +#define _LINUX_KMSG_H
> +
> +#ifdef __KMSG_CHECKER
> +
> +#define KMSG_EMERG(num) __KMSG_CHECK(EMERG, num)
> +#define KMSG_ALERT(num) __KMSG_CHECK(ALERT, num)
> +#define KMSG_CRIT(num) __KMSG_CHECK(CRIT, num)
> +#define KMSG_ERR(num) __KMSG_CHECK(ERR, num)
> +#define KMSG_WARNING(num) __KMSG_CHECK(WARNING, num)
> +#define KMSG_NOTICE(num) __KMSG_CHECK(NOTICE, num)
> +#define KMSG_INFO(num) __KMSG_CHECK(INFO, num)
> +#define KMSG_DEBUG(num) __KMSG_CHECK(DEBUG, num)
> +
> +#define KMSG_DOC(comp, num, str) __KMSG_DOC(comp, num, str)
> +
> +#else
> +
> +#define KMSG_EMERG(num) KERN_EMERG KMSG_COMPONENT "." #num ": "
> +#define KMSG_ALERT(num) KERN_ALERT KMSG_COMPONENT "." #num ": "
> +#define KMSG_CRIT(num) KERN_CRIT KMSG_COMPONENT "." #num ": "
> +#define KMSG_ERR(num) KERN_ERR KMSG_COMPONENT "." #num ": "
> +#define KMSG_WARNING(num) KERN_WARNING KMSG_COMPONENT "." #num ": "
> +#define KMSG_NOTICE(num) KERN_NOTICE KMSG_COMPONENT "." #num ": "
> +#define KMSG_INFO(num) KERN_INFO KMSG_COMPONENT "." #num ": "
> +#define KMSG_DEBUG(num) KERN_DEBUG KMSG_COMPONENT "." #num ": "
> +
> +#define KMSG_DOC(comp, num, str)
> +
> +#endif /* __KMSG_CHECKER */
> +
> +#endif /* _LINUX_KMSG_H */
> diff -Naur linux-2.6.21/scripts/kernel-doc linux-2.6.21-kmsg/scripts/kernel-doc
> --- linux-2.6.21/scripts/kernel-doc 2007-04-26 05:08:32.000000000 +0200
> +++ linux-2.6.21-kmsg/scripts/kernel-doc 2007-06-05 15:17:51.000000000 +0200
> @@ -256,7 +256,7 @@
> my $in_doc_sect;
>
> #declaration types: can be
> -# 'function', 'struct', 'union', 'enum', 'typedef'
> +# 'function', 'struct', 'union', 'enum', 'typedef', 'message'
> my $decl_type;
>
> my $doc_special = "\@\%\$\&";
> @@ -1163,6 +1163,55 @@
> output_section_text(@_);
> }
>
> +##
> +# output message in text
> +sub output_message_text(%) {
> + my %args = %{$_[0]};
> + my ($parameter);
> +
> + print $args{'id'}.": \"".$args{'message'}."\"\n\n";
> +
> + print "Parameters:\n\n";
> + foreach $parameter (@{$args{'parameterlist'}}) {
> + ($parameter =~ /^#/) && next;
> + my $parameter_name = $parameter;
> + $parameter_name =~ s/\[.*//;
> + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
> + print "$parameter\n\t";
> + print $args{'parameterdescs'}{$parameter_name}."\n";
> + }
> + output_section_text(@_);
> +}
> +
> +##
> +# output message in man
> +sub output_message_man(%) {
> + my %args = %{$_[0]};
> + my ($parameter, $section);
> +
> + print ".TH \"$args{'module'}\" 9 \"".$args{'id'}."\" \"$man_date\" \"Linux Messages\" LINUX\n";
> +
> + print ".SH MESSAGE\n";
> + print $args{'id'}.": "."\"".$args{'message'}."\"\n";
> +
> + print ".SH Parameters\n";
> + foreach $parameter (@{$args{'parameterlist'}}) {
> + ($parameter =~ /^#/) && next;
> +
> + my $parameter_name = $parameter;
> + $parameter_name =~ s/\[.*//;
> +
> + ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
> + print ".IP \"".$parameter."\" 12\n";
> + output_highlight($args{'parameterdescs'}{$parameter_name});
> + }
> + foreach $section (@{$args{'sectionlist'}}) {
> + print ".SH \"$section\"\n";
> + output_highlight($args{'sections'}{$section});
> + print "\n";
> + }
> +}
> +
> #output sections in text
> sub output_section_text(%) {
> my %args = %{$_[0]};
> @@ -1607,6 +1656,69 @@
> });
> }
>
> +sub create_parameterlist_msg($$) {
> + my $args = shift;
> + my $file = shift;
> + my $splitter = "%";
> + my $type;
> + my $param = 0;
> + my $first = 1;
> +
> + # temporarily replace commas
> + while ($args =~ /(\([^\),]+),/) {
> + $args =~ s/(\([^\),]+),/$1#/g;
> + }
> +
> + foreach my $arg (split($splitter, $args)) {
> + if ($first) {
> + $first = 0;
> + next;
> + }
> + $type = substr($arg,0,1);
> +
> + # XXX introduce better type checking
> +
> + push_parameter($param, $type, $file);
> + $param += 1;
> + }
> +}
> +
> +##
> +# takes a message prototype and the name of the current file being
> +# processed and spits out all the details stored in the global
> +# arrays/hashes.
> +sub dump_message($$) {
> + my $x = shift;
> + my $file = shift;
> +
> + if ($x =~/(KMSG_DOC)\(\s*(\w+)\s*\,\s*(\w+)\s*\,\s*\"(.*)\"\)/) {
> + $declaration_name = "$2.$3";
> + my $members = $4;
> + # strip comments:
> + $members =~ s/\/\*.*?\*\///gos;
> +
> + create_parameterlist_msg($members, $file);
> +
> + output_declaration($declaration_name,
> + 'message',
> + {'message' => $members,
> + 'id' => $declaration_name,
> + 'module' => $modulename,
> + 'parameterlist' => \@parameterlist,
> + 'parameterdescs' => \%parameterdescs,
> + 'parametertypes' => \%parametertypes,
> + 'sectionlist' => \@sectionlist,
> + 'sections' => \%sections,
> + 'purpose' => $declaration_purpose,
> + 'type' => $decl_type
> + });
> + }
> + else {
> + print STDERR "Error(${file}:$.): Cannot parse message!\n";
> + ++$errors;
> + }
> +}
> +
> sub process_file($);
>
> # Read the file that maps relative names to absolute names for
> @@ -1782,6 +1894,8 @@
> $decl_type = 'enum';
> } elsif ($identifier =~ m/^typedef/) {
> $decl_type = 'typedef';
> + } elsif ($identifier =~ m/^message/) {
> + $decl_type = 'message';
> } else {
> $decl_type = 'function';
> }
> diff -Naur linux-2.6.21/scripts/kmsg-doc linux-2.6.21-kmsg/scripts/kmsg-doc
> --- linux-2.6.21/scripts/kmsg-doc 1970-01-01 01:00:00.000000000 +0100
> +++ linux-2.6.21-kmsg/scripts/kmsg-doc 2007-06-05 15:17:51.000000000 +0200
> @@ -0,0 +1,231 @@
> +#!/usr/bin/perl
> +#
> +# Tool to check kernel messages
> +#
> +# Can be used in toplevel Linux Makefile in the following way:
> +#
> +# CHECK = scripts/kmsg-doc check
> +# CHECKFLAGS =
> +#
> +# Note: This is just a prototype and neither perfect nor complete!
> +#
> +# Copyright (C) IBM Corp. 2007
> +# Author(s): Michael Holzheu <holzheu@xxxxxxxxxx>
> +#
> +
> +sub create_message($$$$$)
> +{
> + my ($sev, $component, $number, $text, $params) = @_;
> +
> + $text =~ s/\\n//; # remove trailing newline character
> + $message_id = "$component.$number";
> + $messages{$message_count}->{'ID'} = $message_id;
> + $messages{$message_count}->{'COMP'} = $component;
> + $messages{$message_count}->{'NR'} = $number;
> + $messages{$message_count}->{'MSG'} = $text;
> + $messages{$message_count}->{'SEV'} = $sev;
> +
> + @parms = split(/[\s]*,[\s]*/,$params);
> + $parm_count = 0;
> + foreach $parm (@parms) {
> + if (!($parm eq "")) {
> + $messages{$message_count}->{'PARM_NAME'}->{$parm_count} = $parm;
> + $parm_count += 1;
> + }
> + }
> + $messages{$message_count}->{'PARM_COUNT'} = $parm_count;
> + $message_count += 1;
> +}
> +
> +sub get_msgs($)
> +{
> + my ($filename)=@_;
> +
> + $message_count = 0;
> + open(FD, $filename);
> + my @lines=<FD>;
> + foreach $line (@lines) {
> + if ($line =~ /\s*printk\([\s]*__KMSG_CHECK\((.*)\,[\s]*(.*)\)[\s]*"(.*)"[\s]*(.*)[\s]*\);/) {
> + create_message($1, $component, $2, $3, $4);
> + }
> + }
> +}
> +
> +sub get_descriptions($)
> +{
> + my ($filename)=@_;
> + my $desc_start;
> +
> + $description_count = 0;
> + $desc_start = 0;
> + open(FD, $filename);
> + my @lines=<FD>;
> + foreach $line (@lines) {
> + if ($line =~ /#define [\s]*KMSG_COMPONENT [\s]*"(.*)"/) {
> + $component = $1;
> + }
> + if ($line =~ /\s*\/\*\*$/) {
> + $msg_start = 1;
> + $parm_count = 0;
> + next;
> + }
> + if (($msg_start == 1) && ($line =~ / \* message/)) {
> + $desc_start = 1;
> + next;
> + }
> + if ($line =~ / \*\//) {
> + $desc_start = 0;
> + next;
> + }
> + if ($desc_start == 1) {
> + $descriptions{$description_count}->{'DESC'} .= "$line";
> + next;
> + }
> + if ($line =~
> + /\s*KMSG_DOC\(\s*(.*)\s*\,\s*(.*)\s*\,\s*\"(.*)\"\s*\);/) {
> + my $param_count = 0;
> + my $first = 1;
> + my $type;
> +
> + $descriptions{$description_count}->{'ID'} = "$1\.$2";
> + $descriptions{$description_count}->{'COMP'} = "$1";
> + $descriptions{$description_count}->{'NR'} = "$2";
> + $descriptions{$description_count}->{'MSG'} = "$3";
> + foreach my $arg (split("%", $3)) {
> + if ($first) {
> + $first = 0;
> + next;
> + }
> + $type = substr($arg, 0, 1);
> + $descriptions{$description_count}->{'PARM_TYPE'}->{$param_count} = $type;
> + $param_count += 1;
> + }
> + $descriptions{$description_count}->{'PARM_COUNT'} = $param_count;
> + $description_count += 1;
> + }
> + }
> +}
> +
> +sub print_messages()
> +{
> + for ($i = 0; $i < $message_count; $i++) {
> + print "MESSAGE: $messages{$i}->{'ID'}\n";
> + }
> +}
> +
> +sub print_descriptions($)
> +{
> + my ($message_id)=@_;
> +
> + for ($i = 0; $i < $description_count; $i++) {
> + if (($descriptions{$i}->{'ID'} eq $message_id) || $message_id eq "all") {
> + print "==============================================================================\n";
> + print "\[$descriptions{$i}->{'COMP'}\.$descriptions{$i}->{'NR'}\] $descriptions{$i}->{'MSG'}\n";
> + print "\n";
> + print "Parameters:\n";
> + for ($j = 0; $j < $descriptions{$i}->{'PARM_COUNT'}; $j++) {
> + print " $descriptions{$i}->{'PARM_TYPE'}->{$j}: $descriptions{$i}->{'PARM_DESC'}->{$j}\n";
> + }
> + print "\n";
> + print "Description:\n";
> + print "$descriptions{$i}->{'DESC'}\n";
> + print "==============================================================================\n";
> + }
> + }
> +}
> +
> +sub check_messages($)
> +{
> + my ($filename)=@_;
> +
> + for ($i = 0; $i < $message_count; $i++) {
> + $found = 0;
> + for ($j = 0; $j < $description_count; $j++) {
> + if ($messages{$i}->{'ID'} eq $descriptions{$j}->{'ID'}) {
> + $found = 1;
> + last;
> + }
> + }
> + if (!$found) {
> + print STDERR "$filename: Missing description for: $messages{$i}->{'ID'}\n";
> + }
> + }
> + for ($i = 0; $i < $description_count; $i++) {
> + $found = 0;
> + for ($j = 0; $j < $message_count; $j++) {
> + if ($messages{$j}->{'ID'} eq $descriptions{$i}->{'ID'}) {
> + $found = 1;
> + last;
> + }
> + }
> + if (!$found) {
> + print STDERR "$filename: Description without message for: $descriptions{$i}->{'ID'}\n";
> + }
> + }
> +}
> +
> +sub print_templates()
> +{
> +
> + for ($i = 0; $i < $message_count; $i++) {
> + $found = 0;
> + for ($j = 0; $j < $description_count; $j++) {
> + if ($messages{$i}->{'ID'} eq $descriptions{$j}->{'ID'}) {
> + $found = 1;
> + }
> + }
> + if (!$found) {
> + print "/**\n";
> + print " * message\n";
> + for ($k = 0; $k < $messages{$i}->{'PARM_COUNT'}; $k++) {
> + print " * \@$k: $messages{$i}->{'PARM_NAME'}->{$k}\n";
> + }
> + print " *\n";
> + print " * Description:\n";
> + print " *\n";
> + print " * User Response:\n";
> + print " */\n";
> + print "\n";
> + print "KMSG_DOC($messages{$i}->{'COMP'}, $messages{$i}->{'NR'}, \"$messages{$i}->{'MSG'}\");\n"
> + }
> + }
> +}
> +
> +sub usage()
> +{
> + print "USAGE: kmsg_tool print | check <file>\n";
> + exit 1;
> +}
> +
> +$option = shift;
> +
> +if ($option eq "check") {
> + $gcc_options = "-E -D __KMSG_CHECKER ";
> + do {
> + $filename = $tmp;
> + $tmp = shift;
> + $tmp =~ s/\(/\\\(/;
> + $tmp =~ s/\)/\\\)/;
> + $gcc_options .= " $tmp";
> + } while (!($tmp eq ""));
> +
> + $gcc_options =~ s/-Wbitwise//; # XXX hack to remove -Wbitwise CHECKFLAG
> + $gcc_options =~ s/-D__STDC__//; # XXX hack to remove -D__STDC__
> + $tmp_file = "$filename.msg";
> + system("gcc $gcc_options > $tmp_file");
> + get_descriptions($filename);
> + get_msgs($tmp_file);
> + check_messages($filename);
> + print_templates();
> + system("rm $tmp_file");
> +} elsif ($option eq "print") {
> + $filename = shift;
> + do {
> + print STDERR "Processing: $filename\n";
> + get_descriptions($filename);
> + print_descriptions("all");
> + $filename = shift;
> + } while (!($filename eq ""));
> +} else {
> + usage();
> +}
>
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/