Imported Upstream version 0.7.6 upstream/0.7.6
authorDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:18 +0000 (13:50 +0900)
committerDongHun Kwak <dh0128.kwak@samsung.com>
Fri, 14 Jan 2022 04:50:18 +0000 (13:50 +0900)
42 files changed:
Makefile.inc
README
kpartx/devmapper.c
kpartx/lopart.c
kpartx/solaris.c
kpartx/test-kpartx
libdmmp/DEV_NOTES
libdmmp/docs/kernel-doc [changed mode: 0644->0755]
libdmmp/libdmmp.c
libmpathpersist/mpath_persist.c
libmpathpersist/mpath_pr_ioctl.c
libmultipath/checkers/Makefile
libmultipath/checkers/hp_sw.c
libmultipath/defaults.h
libmultipath/devmapper.c
libmultipath/dict.c
libmultipath/discovery.c
libmultipath/foreign.h
libmultipath/foreign/Makefile
libmultipath/hwtable.c
libmultipath/io_err_stat.c
libmultipath/memory.c
libmultipath/memory.h
libmultipath/parser.c
libmultipath/parser.h
libmultipath/prioritizers/Makefile
libmultipath/prioritizers/alua_rtpg.c
libmultipath/prioritizers/alua_spc3.h
libmultipath/prioritizers/ontap.c
libmultipath/uevent.c
libmultipath/uevent.h
libmultipath/unaligned.h [new file with mode: 0644]
libmultipath/version.h
multipath/main.c
multipath/multipath.conf.5
multipathd/cli.c
multipathd/main.c
multipathd/uxlsnr.c
tests/Makefile
tests/globals.c
tests/parser.c [new file with mode: 0644]
tests/uevent.c

index a5b9d4e..5d6123d 100644 (file)
@@ -127,4 +127,5 @@ check_file = $(shell        \
        )
 
 %.o:   %.c
+       @echo building $@ because of $?
        $(CC) $(CFLAGS) -c -o $@ $<
diff --git a/README b/README
index 570224d..89bab74 100644 (file)
--- a/README
+++ b/README
@@ -20,7 +20,8 @@ git archive --format=tar.gz --prefix=multipath-tools-X.Y.Z/ X.Y.Z > ../multipath
 
 Alternatively it may be obtained from gitweb, go to:
 https://git.opensvc.com/?p=multipath-tools/.git;a=tags
-select a release-tag and then click on "snapshot".
+select a release-tag and then click on "snapshot". Or get it with
+wget "https://git.opensvc.com/?p=multipath-tools/.git;a=snapshot;sf=tgz;h=refs/tags/X.Y.Z" -O multipath-tools-X.Y.Z.tar.gz
 
 
 Source code
index eb9dac6..8f68a24 100644 (file)
@@ -302,7 +302,7 @@ out:
 /*
  * dm_get_first_dep
  *
- * Return the device number of the first dependend device
+ * Return the device number of the first dependent device
  * for a given target.
  */
 dev_t dm_get_first_dep(char *devname)
index 02b29e8..69c1eda 100644 (file)
@@ -64,7 +64,7 @@ char *find_loop_by_file(const char *filename)
        DIR *dir;
        struct dirent *dent;
        char dev[64], *found = NULL, *p;
-       int fd;
+       int fd, bytes_read;
        struct stat statbuf;
        struct loop_info loopinfo;
        const char VIRT_BLOCK[] = "/sys/devices/virtual/block";
@@ -86,14 +86,15 @@ char *find_loop_by_file(const char *filename)
                if (fd < 0)
                        continue;
 
-               if (read(fd, dev, sizeof(dev)) <= 0) {
+               bytes_read = read(fd, dev, sizeof(dev) - 1);
+               if (bytes_read <= 0) {
                        close(fd);
                        continue;
                }
 
                close(fd);
 
-               dev[sizeof(dev)-1] = '\0';
+               dev[bytes_read] = '\0';
                p = strchr(dev, '\n');
                if (p != NULL)
                        *p = '\0';
index 01da379..8c1a971 100644 (file)
@@ -10,7 +10,7 @@
 
 struct solaris_x86_slice {
        unsigned short  s_tag;          /* ID tag of partition */
-       unsigned short  s_flag;         /* permision flags */
+       unsigned short  s_flag;         /* permission flags */
        long            s_start;        /* start sector no of partition */
        long            s_size;         /* # of blocks in partition */
 };
index 09d15a9..9cee20f 100755 (executable)
@@ -22,7 +22,7 @@
 # stale DM or loop devices may keep lurking around.
 
 # Set WORKDIR in environment to existing dir to for persistence
-# WARNING:  exisiting files will be truncated.
+# WARNING:  existing files will be truncated.
 # If empty, test will be done in temporary dir
 : ${WORKDIR:=}
 # Set this environment variable to test an alternative kpartx executable
index 220a9f4..3460cdf 100644 (file)
@@ -1,4 +1,4 @@
-== Planed features ==
+== Planned features ==
  * Expose all properties used by /usr/bin/multipath
 
 == Code style ==
old mode 100644 (file)
new mode 100755 (executable)
index 7bd52b8..fee8952
@@ -48,16 +48,12 @@ Read C language source or header FILEs, extract embedded documentation comments,
 and print formatted documentation to standard output.
 
 The documentation comments are identified by "/**" opening comment mark. See
-Documentation/kernel-doc-nano-HOWTO.txt for the documentation comment syntax.
+Documentation/doc-guide/kernel-doc.rst for the documentation comment syntax.
 
 Output format selection (mutually exclusive):
-  -docbook             Output DocBook format.
-  -html                        Output HTML format.
-  -html5               Output HTML5 format.
-  -list                        Output symbol list format. This is for use by docproc.
   -man                 Output troff manual page format. This is the default.
   -rst                 Output reStructuredText format.
-  -text                        Output plain text format.
+  -none                        Do not output documentation, only warnings.
 
 Output selection (mutually exclusive):
   -export              Only output documentation for symbols that have been
@@ -215,7 +211,7 @@ my $anon_struct_union = 0;
 my $type_constant = '\b``([^\`]+)``\b';
 my $type_constant2 = '\%([-_\w]+)';
 my $type_func = '(\w+)\(\)';
-my $type_param = '\@(\w+(\.\.\.)?)';
+my $type_param = '\@(\w*(\.\w+)*(\.\.\.)?)';
 my $type_fp_param = '\@(\w+)\(\)';  # Special RST handling for func ptr params
 my $type_env = '(\$\w+)';
 my $type_enum = '\&(enum\s*([_\w]+))';
@@ -224,84 +220,11 @@ my $type_typedef = '\&(typedef\s*([_\w]+))';
 my $type_union = '\&(union\s*([_\w]+))';
 my $type_member = '\&([_\w]+)(\.|->)([_\w]+)';
 my $type_fallback = '\&([_\w]+)';
-my $type_enum_xml = '\&amp;(enum\s*([_\w]+))';
-my $type_struct_xml = '\&amp;(struct\s*([_\w]+))';
-my $type_typedef_xml = '\&amp;(typedef\s*([_\w]+))';
-my $type_union_xml = '\&amp;(union\s*([_\w]+))';
-my $type_member_xml = '\&amp;([_\w]+)(\.|-\&gt;)([_\w]+)';
-my $type_fallback_xml = '\&amp([_\w]+)';
 my $type_member_func = $type_member . '\(\)';
 
 # Output conversion substitutions.
 #  One for each output format
 
-# these work fairly well
-my @highlights_html = (
-                       [$type_constant, "<i>\$1</i>"],
-                       [$type_constant2, "<i>\$1</i>"],
-                       [$type_func, "<b>\$1</b>"],
-                       [$type_enum_xml, "<i>\$1</i>"],
-                       [$type_struct_xml, "<i>\$1</i>"],
-                       [$type_typedef_xml, "<i>\$1</i>"],
-                       [$type_union_xml, "<i>\$1</i>"],
-                       [$type_env, "<b><i>\$1</i></b>"],
-                       [$type_param, "<tt><b>\$1</b></tt>"],
-                       [$type_member_xml, "<tt><i>\$1</i>\$2\$3</tt>"],
-                       [$type_fallback_xml, "<i>\$1</i>"]
-                      );
-my $local_lt = "\\\\\\\\lt:";
-my $local_gt = "\\\\\\\\gt:";
-my $blankline_html = $local_lt . "p" . $local_gt;      # was "<p>"
-
-# html version 5
-my @highlights_html5 = (
-                        [$type_constant, "<span class=\"const\">\$1</span>"],
-                        [$type_constant2, "<span class=\"const\">\$1</span>"],
-                        [$type_func, "<span class=\"func\">\$1</span>"],
-                        [$type_enum_xml, "<span class=\"enum\">\$1</span>"],
-                        [$type_struct_xml, "<span class=\"struct\">\$1</span>"],
-                        [$type_typedef_xml, "<span class=\"typedef\">\$1</span>"],
-                        [$type_union_xml, "<span class=\"union\">\$1</span>"],
-                        [$type_env, "<span class=\"env\">\$1</span>"],
-                        [$type_param, "<span class=\"param\">\$1</span>]"],
-                        [$type_member_xml, "<span class=\"literal\"><span class=\"struct\">\$1</span>\$2<span class=\"member\">\$3</span></span>"],
-                        [$type_fallback_xml, "<span class=\"struct\">\$1</span>"]
-                      );
-my $blankline_html5 = $local_lt . "br /" . $local_gt;
-
-# XML, docbook format
-my @highlights_xml = (
-                      ["([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>"],
-                      [$type_constant, "<constant>\$1</constant>"],
-                      [$type_constant2, "<constant>\$1</constant>"],
-                      [$type_enum_xml, "<type>\$1</type>"],
-                      [$type_struct_xml, "<structname>\$1</structname>"],
-                      [$type_typedef_xml, "<type>\$1</type>"],
-                      [$type_union_xml, "<structname>\$1</structname>"],
-                      [$type_param, "<parameter>\$1</parameter>"],
-                      [$type_func, "<function>\$1</function>"],
-                      [$type_env, "<envar>\$1</envar>"],
-                      [$type_member_xml, "<literal><structname>\$1</structname>\$2<structfield>\$3</structfield></literal>"],
-                      [$type_fallback_xml, "<structname>\$1</structname>"]
-                    );
-my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n";
-
-# gnome, docbook format
-my @highlights_gnome = (
-                        [$type_constant, "<replaceable class=\"option\">\$1</replaceable>"],
-                        [$type_constant2, "<replaceable class=\"option\">\$1</replaceable>"],
-                        [$type_func, "<function>\$1</function>"],
-                        [$type_enum, "<type>\$1</type>"],
-                        [$type_struct, "<structname>\$1</structname>"],
-                        [$type_typedef, "<type>\$1</type>"],
-                        [$type_union, "<structname>\$1</structname>"],
-                        [$type_env, "<envar>\$1</envar>"],
-                        [$type_param, "<parameter>\$1</parameter>" ],
-                        [$type_member, "<literal><structname>\$1</structname>\$2<structfield>\$3</structfield></literal>"],
-                        [$type_fallback, "<structname>\$1</structname>"]
-                      );
-my $blankline_gnome = "</para><para>\n";
-
 # these are pretty rough
 my @highlights_man = (
                       [$type_constant, "\$1"],
@@ -317,21 +240,6 @@ my @highlights_man = (
                     );
 my $blankline_man = "";
 
-# text-mode
-my @highlights_text = (
-                       [$type_constant, "\$1"],
-                       [$type_constant2, "\$1"],
-                       [$type_func, "\$1"],
-                       [$type_enum, "\$1"],
-                       [$type_struct, "\$1"],
-                       [$type_typedef, "\$1"],
-                       [$type_union, "\$1"],
-                       [$type_param, "\$1"],
-                       [$type_member, "\$1\$2\$3"],
-                       [$type_fallback, "\$1"]
-                     );
-my $blankline_text = "";
-
 # rst-mode
 my @highlights_rst = (
                        [$type_constant, "``\$1``"],
@@ -351,21 +259,6 @@ my @highlights_rst = (
                      );
 my $blankline_rst = "\n";
 
-# list mode
-my @highlights_list = (
-                       [$type_constant, "\$1"],
-                       [$type_constant2, "\$1"],
-                       [$type_func, "\$1"],
-                       [$type_enum, "\$1"],
-                       [$type_struct, "\$1"],
-                       [$type_typedef, "\$1"],
-                       [$type_union, "\$1"],
-                       [$type_param, "\$1"],
-                       [$type_member, "\$1"],
-                       [$type_fallback, "\$1"]
-                     );
-my $blankline_list = "";
-
 # read arguments
 if ($#ARGV == -1) {
     usage();
@@ -375,12 +268,12 @@ my $kernelversion;
 my $dohighlight = "";
 
 my $verbose = 0;
-my $output_mode = "man";
+my $output_mode = "rst";
 my $output_preformatted = 0;
 my $no_doc_sections = 0;
 my $enable_lineno = 0;
-my @highlights = @highlights_man;
-my $blankline = $blankline_man;
+my @highlights = @highlights_rst;
+my $blankline = $blankline_rst;
 my $modulename = "Kernel API";
 
 use constant {
@@ -498,69 +391,51 @@ my $undescribed = "-- undescribed --";
 
 reset_state();
 
-while ($ARGV[0] =~ m/^-(.*)/) {
-    my $cmd = shift @ARGV;
-    if ($cmd eq "-html") {
-       $output_mode = "html";
-       @highlights = @highlights_html;
-       $blankline = $blankline_html;
-    } elsif ($cmd eq "-html5") {
-       $output_mode = "html5";
-       @highlights = @highlights_html5;
-       $blankline = $blankline_html5;
-    } elsif ($cmd eq "-man") {
+while ($ARGV[0] =~ m/^--?(.*)/) {
+    my $cmd = $1;
+    shift @ARGV;
+    if ($cmd eq "man") {
        $output_mode = "man";
        @highlights = @highlights_man;
        $blankline = $blankline_man;
-    } elsif ($cmd eq "-text") {
-       $output_mode = "text";
-       @highlights = @highlights_text;
-       $blankline = $blankline_text;
-    } elsif ($cmd eq "-rst") {
+    } elsif ($cmd eq "rst") {
        $output_mode = "rst";
        @highlights = @highlights_rst;
        $blankline = $blankline_rst;
-    } elsif ($cmd eq "-docbook") {
-       $output_mode = "xml";
-       @highlights = @highlights_xml;
-       $blankline = $blankline_xml;
-    } elsif ($cmd eq "-list") {
-       $output_mode = "list";
-       @highlights = @highlights_list;
-       $blankline = $blankline_list;
-    } elsif ($cmd eq "-gnome") {
-       $output_mode = "gnome";
-       @highlights = @highlights_gnome;
-       $blankline = $blankline_gnome;
-    } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
+    } elsif ($cmd eq "none") {
+       $output_mode = "none";
+    } elsif ($cmd eq "module") { # not needed for XML, inherits from calling document
        $modulename = shift @ARGV;
-    } elsif ($cmd eq "-function") { # to only output specific functions
+    } elsif ($cmd eq "function") { # to only output specific functions
        $output_selection = OUTPUT_INCLUDE;
        $function = shift @ARGV;
        $function_table{$function} = 1;
-    } elsif ($cmd eq "-nofunction") { # output all except specific functions
+    } elsif ($cmd eq "nofunction") { # output all except specific functions
        $output_selection = OUTPUT_EXCLUDE;
        $function = shift @ARGV;
        $function_table{$function} = 1;
-    } elsif ($cmd eq "-export") { # only exported symbols
+    } elsif ($cmd eq "export") { # only exported symbols
        $output_selection = OUTPUT_EXPORTED;
        %function_table = ();
-    } elsif ($cmd eq "-internal") { # only non-exported symbols
+    } elsif ($cmd eq "internal") { # only non-exported symbols
        $output_selection = OUTPUT_INTERNAL;
        %function_table = ();
-    } elsif ($cmd eq "-export-file") {
+    } elsif ($cmd eq "export-file") {
        my $file = shift @ARGV;
        push(@export_file_list, $file);
-    } elsif ($cmd eq "-v") {
+    } elsif ($cmd eq "v") {
        $verbose = 1;
-    } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
+    } elsif (($cmd eq "h") || ($cmd eq "help")) {
        usage();
-    } elsif ($cmd eq '-no-doc-sections') {
+    } elsif ($cmd eq 'no-doc-sections') {
            $no_doc_sections = 1;
-    } elsif ($cmd eq '-enable-lineno') {
+    } elsif ($cmd eq 'enable-lineno') {
            $enable_lineno = 1;
-    } elsif ($cmd eq '-show-not-found') {
+    } elsif ($cmd eq 'show-not-found') {
        $show_not_found = 1;
+    } else {
+       # Unknown argument
+        usage();
     }
 }
 
@@ -667,22 +542,11 @@ sub output_highlight {
 #      confess "output_highlight got called with no args?\n";
 #   }
 
-    if ($output_mode eq "html" || $output_mode eq "html5" ||
-       $output_mode eq "xml") {
-       $contents = local_unescape($contents);
-       # convert data read & converted thru xml_escape() into &xyz; format:
-       $contents =~ s/\\\\\\/\&/g;
-    }
 #   print STDERR "contents b4:$contents\n";
     eval $dohighlight;
     die $@ if $@;
 #   print STDERR "contents af:$contents\n";
 
-#   strip whitespaces when generating html5
-    if ($output_mode eq "html5") {
-       $contents =~ s/^\s+//;
-       $contents =~ s/\s+$//;
-    }
     foreach $line (split "\n", $contents) {
        if (! $output_preformatted) {
            $line =~ s/^\s*//;
@@ -703,817 +567,6 @@ sub output_highlight {
     }
 }
 
-# output sections in html
-sub output_section_html(%) {
-    my %args = %{$_[0]};
-    my $section;
-
-    foreach $section (@{$args{'sectionlist'}}) {
-       print "<h3>$section</h3>\n";
-       print "<blockquote>\n";
-       output_highlight($args{'sections'}{$section});
-       print "</blockquote>\n";
-    }
-}
-
-# output enum in html
-sub output_enum_html(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-    my $count;
-    print "<h2>enum " . $args{'enum'} . "</h2>\n";
-
-    print "<b>enum " . $args{'enum'} . "</b> {<br>\n";
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print " <b>" . $parameter . "</b>";
-       if ($count != $#{$args{'parameterlist'}}) {
-           $count++;
-           print ",\n";
-       }
-       print "<br>";
-    }
-    print "};<br>\n";
-
-    print "<h3>Constants</h3>\n";
-    print "<dl>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "<dt><b>" . $parameter . "</b>\n";
-       print "<dd>";
-       output_highlight($args{'parameterdescs'}{$parameter});
-    }
-    print "</dl>\n";
-    output_section_html(@_);
-    print "<hr>\n";
-}
-
-# output typedef in html
-sub output_typedef_html(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-    my $count;
-    print "<h2>typedef " . $args{'typedef'} . "</h2>\n";
-
-    print "<b>typedef " . $args{'typedef'} . "</b>\n";
-    output_section_html(@_);
-    print "<hr>\n";
-}
-
-# output struct in html
-sub output_struct_html(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-
-    print "<h2>" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "</h2>\n";
-    print "<b>" . $args{'type'} . " " . $args{'struct'} . "</b> {<br>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       if ($parameter =~ /^#/) {
-               print "$parameter<br>\n";
-               next;
-       }
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "&nbsp; &nbsp; <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
-       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-           # bitfield
-           print "&nbsp; &nbsp; <i>$1</i> <b>$parameter</b>$2;<br>\n";
-       } else {
-           print "&nbsp; &nbsp; <i>$type</i> <b>$parameter</b>;<br>\n";
-       }
-    }
-    print "};<br>\n";
-
-    print "<h3>Members</h3>\n";
-    print "<dl>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       ($parameter =~ /^#/) && next;
-
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       print "<dt><b>" . $parameter . "</b>\n";
-       print "<dd>";
-       output_highlight($args{'parameterdescs'}{$parameter_name});
-    }
-    print "</dl>\n";
-    output_section_html(@_);
-    print "<hr>\n";
-}
-
-# output function in html
-sub output_function_html(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-
-    print "<h2>" . $args{'function'} . " - " . $args{'purpose'} . "</h2>\n";
-    print "<i>" . $args{'functiontype'} . "</i>\n";
-    print "<b>" . $args{'function'} . "</b>\n";
-    print "(";
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "<i>$1</i><b>$parameter</b>) <i>($2)</i>";
-       } else {
-           print "<i>" . $type . "</i> <b>" . $parameter . "</b>";
-       }
-       if ($count != $#{$args{'parameterlist'}}) {
-           $count++;
-           print ",\n";
-       }
-    }
-    print ")\n";
-
-    print "<h3>Arguments</h3>\n";
-    print "<dl>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       print "<dt><b>" . $parameter . "</b>\n";
-       print "<dd>";
-       output_highlight($args{'parameterdescs'}{$parameter_name});
-    }
-    print "</dl>\n";
-    output_section_html(@_);
-    print "<hr>\n";
-}
-
-# output DOC: block header in html
-sub output_blockhead_html(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-
-    foreach $section (@{$args{'sectionlist'}}) {
-       print "<h3>$section</h3>\n";
-       print "<ul>\n";
-       output_highlight($args{'sections'}{$section});
-       print "</ul>\n";
-    }
-    print "<hr>\n";
-}
-
-# output sections in html5
-sub output_section_html5(%) {
-    my %args = %{$_[0]};
-    my $section;
-
-    foreach $section (@{$args{'sectionlist'}}) {
-       print "<section>\n";
-       print "<h1>$section</h1>\n";
-       print "<p>\n";
-       output_highlight($args{'sections'}{$section});
-       print "</p>\n";
-       print "</section>\n";
-    }
-}
-
-# output enum in html5
-sub output_enum_html5(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-    my $count;
-    my $html5id;
-
-    $html5id = $args{'enum'};
-    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
-    print "<article class=\"enum\" id=\"enum:". $html5id . "\">";
-    print "<h1>enum " . $args{'enum'} . "</h1>\n";
-    print "<ol class=\"code\">\n";
-    print "<li>";
-    print "<span class=\"keyword\">enum</span> ";
-    print "<span class=\"identifier\">" . $args{'enum'} . "</span> {";
-    print "</li>\n";
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "<li class=\"indent\">";
-       print "<span class=\"param\">" . $parameter . "</span>";
-       if ($count != $#{$args{'parameterlist'}}) {
-           $count++;
-           print ",";
-       }
-       print "</li>\n";
-    }
-    print "<li>};</li>\n";
-    print "</ol>\n";
-
-    print "<section>\n";
-    print "<h1>Constants</h1>\n";
-    print "<dl>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "<dt>" . $parameter . "</dt>\n";
-       print "<dd>";
-       output_highlight($args{'parameterdescs'}{$parameter});
-       print "</dd>\n";
-    }
-    print "</dl>\n";
-    print "</section>\n";
-    output_section_html5(@_);
-    print "</article>\n";
-}
-
-# output typedef in html5
-sub output_typedef_html5(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-    my $count;
-    my $html5id;
-
-    $html5id = $args{'typedef'};
-    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
-    print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n";
-    print "<h1>typedef " . $args{'typedef'} . "</h1>\n";
-
-    print "<ol class=\"code\">\n";
-    print "<li>";
-    print "<span class=\"keyword\">typedef</span> ";
-    print "<span class=\"identifier\">" . $args{'typedef'} . "</span>";
-    print "</li>\n";
-    print "</ol>\n";
-    output_section_html5(@_);
-    print "</article>\n";
-}
-
-# output struct in html5
-sub output_struct_html5(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-    my $html5id;
-
-    $html5id = $args{'struct'};
-    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
-    print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n";
-    print "<hgroup>\n";
-    print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>";
-    print "<h2>". $args{'purpose'} . "</h2>\n";
-    print "</hgroup>\n";
-    print "<ol class=\"code\">\n";
-    print "<li>";
-    print "<span class=\"type\">" . $args{'type'} . "</span> ";
-    print "<span class=\"identifier\">" . $args{'struct'} . "</span> {";
-    print "</li>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "<li class=\"indent\">";
-       if ($parameter =~ /^#/) {
-               print "<span class=\"param\">" . $parameter ."</span>\n";
-               print "</li>\n";
-               next;
-       }
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "<span class=\"type\">$1</span> ";
-           print "<span class=\"param\">$parameter</span>";
-           print "<span class=\"type\">)</span> ";
-           print "(<span class=\"args\">$2</span>);";
-       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-           # bitfield
-           print "<span class=\"type\">$1</span> ";
-           print "<span class=\"param\">$parameter</span>";
-           print "<span class=\"bits\">$2</span>;";
-       } else {
-           print "<span class=\"type\">$type</span> ";
-           print "<span class=\"param\">$parameter</span>;";
-       }
-       print "</li>\n";
-    }
-    print "<li>};</li>\n";
-    print "</ol>\n";
-
-    print "<section>\n";
-    print "<h1>Members</h1>\n";
-    print "<dl>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       ($parameter =~ /^#/) && next;
-
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       print "<dt>" . $parameter . "</dt>\n";
-       print "<dd>";
-       output_highlight($args{'parameterdescs'}{$parameter_name});
-       print "</dd>\n";
-    }
-    print "</dl>\n";
-    print "</section>\n";
-    output_section_html5(@_);
-    print "</article>\n";
-}
-
-# output function in html5
-sub output_function_html5(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-    my $html5id;
-
-    $html5id = $args{'function'};
-    $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
-    print "<article class=\"function\" id=\"func:". $html5id . "\">\n";
-    print "<hgroup>\n";
-    print "<h1>" . $args{'function'} . "</h1>";
-    print "<h2>" . $args{'purpose'} . "</h2>\n";
-    print "</hgroup>\n";
-    print "<ol class=\"code\">\n";
-    print "<li>";
-    print "<span class=\"type\">" . $args{'functiontype'} . "</span> ";
-    print "<span class=\"identifier\">" . $args{'function'} . "</span> (";
-    print "</li>";
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "<li class=\"indent\">";
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "<span class=\"type\">$1</span> ";
-           print "<span class=\"param\">$parameter</span>";
-           print "<span class=\"type\">)</span> ";
-           print "(<span class=\"args\">$2</span>)";
-       } else {
-           print "<span class=\"type\">$type</span> ";
-           print "<span class=\"param\">$parameter</span>";
-       }
-       if ($count != $#{$args{'parameterlist'}}) {
-           $count++;
-           print ",";
-       }
-       print "</li>\n";
-    }
-    print "<li>)</li>\n";
-    print "</ol>\n";
-
-    print "<section>\n";
-    print "<h1>Arguments</h1>\n";
-    print "<p>\n";
-    print "<dl>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       print "<dt>" . $parameter . "</dt>\n";
-       print "<dd>";
-       output_highlight($args{'parameterdescs'}{$parameter_name});
-       print "</dd>\n";
-    }
-    print "</dl>\n";
-    print "</section>\n";
-    output_section_html5(@_);
-    print "</article>\n";
-}
-
-# output DOC: block header in html5
-sub output_blockhead_html5(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-    my $html5id;
-
-    foreach $section (@{$args{'sectionlist'}}) {
-       $html5id = $section;
-       $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
-       print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n";
-       print "<h1>$section</h1>\n";
-       print "<p>\n";
-       output_highlight($args{'sections'}{$section});
-       print "</p>\n";
-    }
-    print "</article>\n";
-}
-
-sub output_section_xml(%) {
-    my %args = %{$_[0]};
-    my $section;
-    # print out each section
-    $lineprefix="   ";
-    foreach $section (@{$args{'sectionlist'}}) {
-       print "<refsect1>\n";
-       print "<title>$section</title>\n";
-       if ($section =~ m/EXAMPLE/i) {
-           print "<informalexample><programlisting>\n";
-           $output_preformatted = 1;
-       } else {
-           print "<para>\n";
-       }
-       output_highlight($args{'sections'}{$section});
-       $output_preformatted = 0;
-       if ($section =~ m/EXAMPLE/i) {
-           print "</programlisting></informalexample>\n";
-       } else {
-           print "</para>\n";
-       }
-       print "</refsect1>\n";
-    }
-}
-
-# output function in XML DocBook
-sub output_function_xml(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-    my $id;
-
-    $id = "API-" . $args{'function'};
-    $id =~ s/[^A-Za-z0-9]/-/g;
-
-    print "<refentry id=\"$id\">\n";
-    print "<refentryinfo>\n";
-    print " <title>LINUX</title>\n";
-    print " <productname>Kernel Hackers Manual</productname>\n";
-    print " <date>$man_date</date>\n";
-    print "</refentryinfo>\n";
-    print "<refmeta>\n";
-    print " <refentrytitle><phrase>" . $args{'function'} . "</phrase></refentrytitle>\n";
-    print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
-    print "</refmeta>\n";
-    print "<refnamediv>\n";
-    print " <refname>" . $args{'function'} . "</refname>\n";
-    print " <refpurpose>\n";
-    print "  ";
-    output_highlight ($args{'purpose'});
-    print " </refpurpose>\n";
-    print "</refnamediv>\n";
-
-    print "<refsynopsisdiv>\n";
-    print " <title>Synopsis</title>\n";
-    print "  <funcsynopsis><funcprototype>\n";
-    print "   <funcdef>" . $args{'functiontype'} . " ";
-    print "<function>" . $args{'function'} . " </function></funcdef>\n";
-
-    $count = 0;
-    if ($#{$args{'parameterlist'}} >= 0) {
-       foreach $parameter (@{$args{'parameterlist'}}) {
-           $type = $args{'parametertypes'}{$parameter};
-           if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-               # pointer-to-function
-               print "   <paramdef>$1<parameter>$parameter</parameter>)\n";
-               print "     <funcparams>$2</funcparams></paramdef>\n";
-           } else {
-               print "   <paramdef>" . $type;
-               print " <parameter>$parameter</parameter></paramdef>\n";
-           }
-       }
-    } else {
-       print "  <void/>\n";
-    }
-    print "  </funcprototype></funcsynopsis>\n";
-    print "</refsynopsisdiv>\n";
-
-    # print parameters
-    print "<refsect1>\n <title>Arguments</title>\n";
-    if ($#{$args{'parameterlist'}} >= 0) {
-       print " <variablelist>\n";
-       foreach $parameter (@{$args{'parameterlist'}}) {
-           my $parameter_name = $parameter;
-           $parameter_name =~ s/\[.*//;
-           $type = $args{'parametertypes'}{$parameter};
-
-           print "  <varlistentry>\n   <term><parameter>$type $parameter</parameter></term>\n";
-           print "   <listitem>\n    <para>\n";
-           $lineprefix="     ";
-           output_highlight($args{'parameterdescs'}{$parameter_name});
-           print "    </para>\n   </listitem>\n  </varlistentry>\n";
-       }
-       print " </variablelist>\n";
-    } else {
-       print " <para>\n  None\n </para>\n";
-    }
-    print "</refsect1>\n";
-
-    output_section_xml(@_);
-    print "</refentry>\n\n";
-}
-
-# output struct in XML DocBook
-sub output_struct_xml(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $id;
-
-    $id = "API-struct-" . $args{'struct'};
-    $id =~ s/[^A-Za-z0-9]/-/g;
-
-    print "<refentry id=\"$id\">\n";
-    print "<refentryinfo>\n";
-    print " <title>LINUX</title>\n";
-    print " <productname>Kernel Hackers Manual</productname>\n";
-    print " <date>$man_date</date>\n";
-    print "</refentryinfo>\n";
-    print "<refmeta>\n";
-    print " <refentrytitle><phrase>" . $args{'type'} . " " . $args{'struct'} . "</phrase></refentrytitle>\n";
-    print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
-    print "</refmeta>\n";
-    print "<refnamediv>\n";
-    print " <refname>" . $args{'type'} . " " . $args{'struct'} . "</refname>\n";
-    print " <refpurpose>\n";
-    print "  ";
-    output_highlight ($args{'purpose'});
-    print " </refpurpose>\n";
-    print "</refnamediv>\n";
-
-    print "<refsynopsisdiv>\n";
-    print " <title>Synopsis</title>\n";
-    print "  <programlisting>\n";
-    print $args{'type'} . " " . $args{'struct'} . " {\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       if ($parameter =~ /^#/) {
-           my $prm = $parameter;
-           # convert data read & converted thru xml_escape() into &xyz; format:
-           # This allows us to have #define macros interspersed in a struct.
-           $prm =~ s/\\\\\\/\&/g;
-           print "$prm\n";
-           next;
-       }
-
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       defined($args{'parameterdescs'}{$parameter_name}) || next;
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "  $1 $parameter) ($2);\n";
-       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-           # bitfield
-           print "  $1 $parameter$2;\n";
-       } else {
-           print "  " . $type . " " . $parameter . ";\n";
-       }
-    }
-    print "};";
-    print "  </programlisting>\n";
-    print "</refsynopsisdiv>\n";
-
-    print " <refsect1>\n";
-    print "  <title>Members</title>\n";
-
-    if ($#{$args{'parameterlist'}} >= 0) {
-    print "  <variablelist>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-      ($parameter =~ /^#/) && next;
-
-      my $parameter_name = $parameter;
-      $parameter_name =~ s/\[.*//;
-
-      defined($args{'parameterdescs'}{$parameter_name}) || next;
-      ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-      $type = $args{'parametertypes'}{$parameter};
-      print "    <varlistentry>";
-      print "      <term><literal>$type $parameter</literal></term>\n";
-      print "      <listitem><para>\n";
-      output_highlight($args{'parameterdescs'}{$parameter_name});
-      print "      </para></listitem>\n";
-      print "    </varlistentry>\n";
-    }
-    print "  </variablelist>\n";
-    } else {
-       print " <para>\n  None\n </para>\n";
-    }
-    print " </refsect1>\n";
-
-    output_section_xml(@_);
-
-    print "</refentry>\n\n";
-}
-
-# output enum in XML DocBook
-sub output_enum_xml(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-    my $id;
-
-    $id = "API-enum-" . $args{'enum'};
-    $id =~ s/[^A-Za-z0-9]/-/g;
-
-    print "<refentry id=\"$id\">\n";
-    print "<refentryinfo>\n";
-    print " <title>LINUX</title>\n";
-    print " <productname>Kernel Hackers Manual</productname>\n";
-    print " <date>$man_date</date>\n";
-    print "</refentryinfo>\n";
-    print "<refmeta>\n";
-    print " <refentrytitle><phrase>enum " . $args{'enum'} . "</phrase></refentrytitle>\n";
-    print " <manvolnum>9</manvolnum>\n";
-    print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
-    print "</refmeta>\n";
-    print "<refnamediv>\n";
-    print " <refname>enum " . $args{'enum'} . "</refname>\n";
-    print " <refpurpose>\n";
-    print "  ";
-    output_highlight ($args{'purpose'});
-    print " </refpurpose>\n";
-    print "</refnamediv>\n";
-
-    print "<refsynopsisdiv>\n";
-    print " <title>Synopsis</title>\n";
-    print "  <programlisting>\n";
-    print "enum " . $args{'enum'} . " {\n";
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "  $parameter";
-       if ($count != $#{$args{'parameterlist'}}) {
-           $count++;
-           print ",";
-       }
-       print "\n";
-    }
-    print "};";
-    print "  </programlisting>\n";
-    print "</refsynopsisdiv>\n";
-
-    print "<refsect1>\n";
-    print " <title>Constants</title>\n";
-    print "  <variablelist>\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-      my $parameter_name = $parameter;
-      $parameter_name =~ s/\[.*//;
-
-      print "    <varlistentry>";
-      print "      <term>$parameter</term>\n";
-      print "      <listitem><para>\n";
-      output_highlight($args{'parameterdescs'}{$parameter_name});
-      print "      </para></listitem>\n";
-      print "    </varlistentry>\n";
-    }
-    print "  </variablelist>\n";
-    print "</refsect1>\n";
-
-    output_section_xml(@_);
-
-    print "</refentry>\n\n";
-}
-
-# output typedef in XML DocBook
-sub output_typedef_xml(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $id;
-
-    $id = "API-typedef-" . $args{'typedef'};
-    $id =~ s/[^A-Za-z0-9]/-/g;
-
-    print "<refentry id=\"$id\">\n";
-    print "<refentryinfo>\n";
-    print " <title>LINUX</title>\n";
-    print " <productname>Kernel Hackers Manual</productname>\n";
-    print " <date>$man_date</date>\n";
-    print "</refentryinfo>\n";
-    print "<refmeta>\n";
-    print " <refentrytitle><phrase>typedef " . $args{'typedef'} . "</phrase></refentrytitle>\n";
-    print " <manvolnum>9</manvolnum>\n";
-    print "</refmeta>\n";
-    print "<refnamediv>\n";
-    print " <refname>typedef " . $args{'typedef'} . "</refname>\n";
-    print " <refpurpose>\n";
-    print "  ";
-    output_highlight ($args{'purpose'});
-    print " </refpurpose>\n";
-    print "</refnamediv>\n";
-
-    print "<refsynopsisdiv>\n";
-    print " <title>Synopsis</title>\n";
-    print "  <synopsis>typedef " . $args{'typedef'} . ";</synopsis>\n";
-    print "</refsynopsisdiv>\n";
-
-    output_section_xml(@_);
-
-    print "</refentry>\n\n";
-}
-
-# output in XML DocBook
-sub output_blockhead_xml(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-
-    my $id = $args{'module'};
-    $id =~ s/[^A-Za-z0-9]/-/g;
-
-    # print out each section
-    $lineprefix="   ";
-    foreach $section (@{$args{'sectionlist'}}) {
-       if (!$args{'content-only'}) {
-               print "<refsect1>\n <title>$section</title>\n";
-       }
-       if ($section =~ m/EXAMPLE/i) {
-           print "<example><para>\n";
-           $output_preformatted = 1;
-       } else {
-           print "<para>\n";
-       }
-       output_highlight($args{'sections'}{$section});
-       $output_preformatted = 0;
-       if ($section =~ m/EXAMPLE/i) {
-           print "</para></example>\n";
-       } else {
-           print "</para>";
-       }
-       if (!$args{'content-only'}) {
-               print "\n</refsect1>\n";
-       }
-    }
-
-    print "\n\n";
-}
-
-# output in XML DocBook
-sub output_function_gnome {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $count;
-    my $id;
-
-    $id = $args{'module'} . "-" . $args{'function'};
-    $id =~ s/[^A-Za-z0-9]/-/g;
-
-    print "<sect2>\n";
-    print " <title id=\"$id\">" . $args{'function'} . "</title>\n";
-
-    print "  <funcsynopsis>\n";
-    print "   <funcdef>" . $args{'functiontype'} . " ";
-    print "<function>" . $args{'function'} . " ";
-    print "</function></funcdef>\n";
-
-    $count = 0;
-    if ($#{$args{'parameterlist'}} >= 0) {
-       foreach $parameter (@{$args{'parameterlist'}}) {
-           $type = $args{'parametertypes'}{$parameter};
-           if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-               # pointer-to-function
-               print "   <paramdef>$1 <parameter>$parameter</parameter>)\n";
-               print "     <funcparams>$2</funcparams></paramdef>\n";
-           } else {
-               print "   <paramdef>" . $type;
-               print " <parameter>$parameter</parameter></paramdef>\n";
-           }
-       }
-    } else {
-       print "  <void>\n";
-    }
-    print "  </funcsynopsis>\n";
-    if ($#{$args{'parameterlist'}} >= 0) {
-       print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n";
-       print "<tgroup cols=\"2\">\n";
-       print "<colspec colwidth=\"2*\">\n";
-       print "<colspec colwidth=\"8*\">\n";
-       print "<tbody>\n";
-       foreach $parameter (@{$args{'parameterlist'}}) {
-           my $parameter_name = $parameter;
-           $parameter_name =~ s/\[.*//;
-
-           print "  <row><entry align=\"right\"><parameter>$parameter</parameter></entry>\n";
-           print "   <entry>\n";
-           $lineprefix="     ";
-           output_highlight($args{'parameterdescs'}{$parameter_name});
-           print "    </entry></row>\n";
-       }
-       print " </tbody></tgroup></informaltable>\n";
-    } else {
-       print " <para>\n  None\n </para>\n";
-    }
-
-    # print out each section
-    $lineprefix="   ";
-    foreach $section (@{$args{'sectionlist'}}) {
-       print "<simplesect>\n <title>$section</title>\n";
-       if ($section =~ m/EXAMPLE/i) {
-           print "<example><programlisting>\n";
-           $output_preformatted = 1;
-       } else {
-       }
-       print "<para>\n";
-       output_highlight($args{'sections'}{$section});
-       $output_preformatted = 0;
-       print "</para>\n";
-       if ($section =~ m/EXAMPLE/i) {
-           print "</programlisting></example>\n";
-       } else {
-       }
-       print " </simplesect>\n";
-    }
-
-    print "</sect2>\n\n";
-}
-
 ##
 # output function in man
 sub output_function_man(%) {
@@ -1617,32 +670,12 @@ sub output_struct_man(%) {
     print ".SH NAME\n";
     print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n";
 
+    my $declaration = $args{'definition'};
+    $declaration =~ s/\t/  /g;
+    $declaration =~ s/\n/"\n.br\n.BI \"/g;
     print ".SH SYNOPSIS\n";
     print $args{'type'} . " " . $args{'struct'} . " {\n.br\n";
-
-    foreach my $parameter (@{$args{'parameterlist'}}) {
-       if ($parameter =~ /^#/) {
-           print ".BI \"$parameter\"\n.br\n";
-           next;
-       }
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print ".BI \"    " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n";
-       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-           # bitfield
-           print ".BI \"    " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n";
-       } else {
-           $type =~ s/([^\*])$/$1 /;
-           print ".BI \"    " . $type . "\" " . $parameter . " \"" . "\"\n;\n";
-       }
-       print "\n.br\n";
-    }
-    print "};\n.br\n";
+    print ".BI \"$declaration\n};\n.br\n\n";
 
     print ".SH Members\n";
     foreach $parameter (@{$args{'parameterlist'}}) {
@@ -1692,161 +725,6 @@ sub output_blockhead_man(%) {
 }
 
 ##
-# output in text
-sub output_function_text(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-    my $start;
-
-    print "Name:\n\n";
-    print $args{'function'} . " - " . $args{'purpose'} . "\n";
-
-    print "\nSynopsis:\n\n";
-    if ($args{'functiontype'} ne "") {
-       $start = $args{'functiontype'} . " " . $args{'function'} . " (";
-    } else {
-       $start = $args{'function'} . " (";
-    }
-    print $start;
-
-    my $count = 0;
-    foreach my $parameter (@{$args{'parameterlist'}}) {
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print $1 . $parameter . ") (" . $2;
-       } else {
-           print $type . " " . $parameter;
-       }
-       if ($count != $#{$args{'parameterlist'}}) {
-           $count++;
-           print ",\n";
-           print " " x length($start);
-       } else {
-           print ");\n\n";
-       }
-    }
-
-    print "Arguments:\n\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n";
-    }
-    output_section_text(@_);
-}
-
-#output sections in text
-sub output_section_text(%) {
-    my %args = %{$_[0]};
-    my $section;
-
-    print "\n";
-    foreach $section (@{$args{'sectionlist'}}) {
-       print "$section:\n\n";
-       output_highlight($args{'sections'}{$section});
-    }
-    print "\n\n";
-}
-
-# output enum in text
-sub output_enum_text(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-    my $count;
-    print "Enum:\n\n";
-
-    print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n";
-    print "enum " . $args{'enum'} . " {\n";
-    $count = 0;
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "\t$parameter";
-       if ($count != $#{$args{'parameterlist'}}) {
-           $count++;
-           print ",";
-       }
-       print "\n";
-    }
-    print "};\n\n";
-
-    print "Constants:\n\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       print "$parameter\n\t";
-       print $args{'parameterdescs'}{$parameter} . "\n";
-    }
-
-    output_section_text(@_);
-}
-
-# output typedef in text
-sub output_typedef_text(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-    my $count;
-    print "Typedef:\n\n";
-
-    print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n";
-    output_section_text(@_);
-}
-
-# output struct as text
-sub output_struct_text(%) {
-    my %args = %{$_[0]};
-    my ($parameter);
-
-    print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n";
-    print $args{'type'} . " " . $args{'struct'} . " {\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       if ($parameter =~ /^#/) {
-           print "$parameter\n";
-           next;
-       }
-
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "\t$1 $parameter) ($2);\n";
-       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-           # bitfield
-           print "\t$1 $parameter$2;\n";
-       } else {
-           print "\t" . $type . " " . $parameter . ";\n";
-       }
-    }
-    print "};\n\n";
-
-    print "Members:\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";
-    }
-    print "\n";
-    output_section_text(@_);
-}
-
-sub output_blockhead_text(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-
-    foreach $section (@{$args{'sectionlist'}}) {
-       print " $section:\n";
-       print "    -> ";
-       output_highlight($args{'sections'}{$section});
-    }
-}
-
-##
 # output in restructured text
 #
 
@@ -2035,29 +913,9 @@ sub output_struct_rst(%) {
 
     print "**Definition**\n\n";
     print "::\n\n";
-    print "  " . $args{'type'} . " " . $args{'struct'} . " {\n";
-    foreach $parameter (@{$args{'parameterlist'}}) {
-       if ($parameter =~ /^#/) {
-           print "  " . "$parameter\n";
-           next;
-       }
-
-       my $parameter_name = $parameter;
-       $parameter_name =~ s/\[.*//;
-
-       ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
-       $type = $args{'parametertypes'}{$parameter};
-       if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
-           # pointer-to-function
-           print "    $1 $parameter) ($2);\n";
-       } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
-           # bitfield
-           print "    $1 $parameter$2;\n";
-       } else {
-           print "    " . $type . " " . $parameter . ";\n";
-       }
-    }
-    print "  };\n\n";
+    my $declaration = $args{'definition'};
+    $declaration =~ s/\t/  /g;
+    print "  " . $args{'type'} . " " . $args{'struct'} . " {\n$declaration  };\n\n";
 
     print "**Members**\n\n";
     $lineprefix = "  ";
@@ -2080,41 +938,21 @@ sub output_struct_rst(%) {
     output_section_rst(@_);
 }
 
+## none mode output functions
 
-## list mode output functions
-
-sub output_function_list(%) {
-    my %args = %{$_[0]};
-
-    print $args{'function'} . "\n";
+sub output_function_none(%) {
 }
 
-# output enum in list
-sub output_enum_list(%) {
-    my %args = %{$_[0]};
-    print $args{'enum'} . "\n";
+sub output_enum_none(%) {
 }
 
-# output typedef in list
-sub output_typedef_list(%) {
-    my %args = %{$_[0]};
-    print $args{'typedef'} . "\n";
+sub output_typedef_none(%) {
 }
 
-# output struct as list
-sub output_struct_list(%) {
-    my %args = %{$_[0]};
-
-    print $args{'struct'} . "\n";
+sub output_struct_none(%) {
 }
 
-sub output_blockhead_list(%) {
-    my %args = %{$_[0]};
-    my ($parameter, $section);
-
-    foreach $section (@{$args{'sectionlist'}}) {
-       print "DOC: $section\n";
-    }
+sub output_blockhead_none(%) {
 }
 
 ##
@@ -2165,39 +1003,128 @@ sub dump_union($$) {
 sub dump_struct($$) {
     my $x = shift;
     my $file = shift;
-    my $nested;
 
     if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
        my $decl_type = $1;
        $declaration_name = $2;
        my $members = $3;
 
-       # ignore embedded structs or unions
-       $members =~ s/({.*})//g;
-       $nested = $1;
-
        # ignore members marked private:
        $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gosi;
        $members =~ s/\/\*\s*private:.*//gosi;
        # strip comments:
        $members =~ s/\/\*.*?\*\///gos;
-       $nested =~ s/\/\*.*?\*\///gos;
        # strip attributes
        $members =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
        $members =~ s/__aligned\s*\([^;]*\)//gos;
        $members =~ s/\s*CRYPTO_MINALIGN_ATTR//gos;
        # replace DECLARE_BITMAP
-       $members =~ s/DECLARE_BITMAP\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
+       $members =~ s/DECLARE_BITMAP\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[BITS_TO_LONGS($2)\]/gos;
        # replace DECLARE_HASHTABLE
-       $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+), ([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
-
-       create_parameterlist($members, ';', $file);
-       check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual, $nested);
-
+       $members =~ s/DECLARE_HASHTABLE\s*\(([^,)]+),\s*([^,)]+)\)/unsigned long $1\[1 << (($2) - 1)\]/gos;
+       # replace DECLARE_KFIFO
+       $members =~ s/DECLARE_KFIFO\s*\(([^,)]+),\s*([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos;
+       # replace DECLARE_KFIFO_PTR
+       $members =~ s/DECLARE_KFIFO_PTR\s*\(([^,)]+),\s*([^,)]+)\)/$2 \*$1/gos;
+
+       my $declaration = $members;
+
+       # Split nested struct/union elements as newer ones
+       while ($members =~ m/(struct|union)([^\{\};]+)\{([^\{\}]*)\}([^\{\}\;]*)\;/) {
+               my $newmember;
+               my $maintype = $1;
+               my $ids = $4;
+               my $content = $3;
+               foreach my $id(split /,/, $ids) {
+                       $newmember .= "$maintype $id; ";
+
+                       $id =~ s/[:\[].*//;
+                       $id =~ s/^\s*\**(\S+)\s*/$1/;
+                       foreach my $arg (split /;/, $content) {
+                               next if ($arg =~ m/^\s*$/);
+                               if ($arg =~ m/^([^\(]+\(\*?\s*)([\w\.]*)(\s*\).*)/) {
+                                       # pointer-to-function
+                                       my $type = $1;
+                                       my $name = $2;
+                                       my $extra = $3;
+                                       next if (!$name);
+                                       if ($id =~ m/^\s*$/) {
+                                               # anonymous struct/union
+                                               $newmember .= "$type$name$extra; ";
+                                       } else {
+                                               $newmember .= "$type$id.$name$extra; ";
+                                       }
+                               } else {
+                                       my $type;
+                                       my $names;
+                                       $arg =~ s/^\s+//;
+                                       $arg =~ s/\s+$//;
+                                       # Handle bitmaps
+                                       $arg =~ s/:\s*\d+\s*//g;
+                                       # Handle arrays
+                                       $arg =~ s/\[\S+\]//g;
+                                       # The type may have multiple words,
+                                       # and multiple IDs can be defined, like:
+                                       #       const struct foo, *bar, foobar
+                                       # So, we remove spaces when parsing the
+                                       # names, in order to match just names
+                                       # and commas for the names
+                                       $arg =~ s/\s*,\s*/,/g;
+                                       if ($arg =~ m/(.*)\s+([\S+,]+)/) {
+                                               $type = $1;
+                                               $names = $2;
+                                       } else {
+                                               $newmember .= "$arg; ";
+                                               next;
+                                       }
+                                       foreach my $name (split /,/, $names) {
+                                               $name =~ s/^\s*\**(\S+)\s*/$1/;
+                                               next if (($name =~ m/^\s*$/));
+                                               if ($id =~ m/^\s*$/) {
+                                                       # anonymous struct/union
+                                                       $newmember .= "$type $name; ";
+                                               } else {
+                                                       $newmember .= "$type $id.$name; ";
+                                               }
+                                       }
+                               }
+                       }
+               }
+               $members =~ s/(struct|union)([^\{\};]+)\{([^\{\}]*)}([^\{\}\;]*)\;/$newmember/;
+       }
+
+       # Ignore other nested elements, like enums
+       $members =~ s/({[^\{\}]*})//g;
+
+       create_parameterlist($members, ';', $file, $declaration_name);
+       check_sections($file, $declaration_name, $decl_type, $sectcheck, $struct_actual);
+
+       # Adjust declaration for better display
+       $declaration =~ s/([{;])/$1\n/g;
+       $declaration =~ s/}\s+;/};/g;
+       # Better handle inlined enums
+       do {} while ($declaration =~ s/(enum\s+{[^}]+),([^\n])/$1,\n$2/);
+
+       my @def_args = split /\n/, $declaration;
+       my $level = 1;
+       $declaration = "";
+       foreach my $clause (@def_args) {
+               $clause =~ s/^\s+//;
+               $clause =~ s/\s+$//;
+               $clause =~ s/\s+/ /;
+               next if (!$clause);
+               $level-- if ($clause =~ m/(})/ && $level > 1);
+               if (!($clause =~ m/^\s*#/)) {
+                       $declaration .= "\t" x $level;
+               }
+               $declaration .= "\t" . $clause . "\n";
+               $level++ if ($clause =~ m/({)/ && !($clause =~m/}/));
+       }
        output_declaration($declaration_name,
                           'struct',
                           {'struct' => $declaration_name,
                            'module' => $modulename,
+                           'definition' => $declaration,
                            'parameterlist' => \@parameterlist,
                            'parameterdescs' => \%parameterdescs,
                            'parametertypes' => \%parametertypes,
@@ -2213,6 +1140,44 @@ sub dump_struct($$) {
     }
 }
 
+
+sub show_warnings($$) {
+       my $functype = shift;
+       my $name = shift;
+
+       return 1 if ($output_selection == OUTPUT_ALL);
+
+       if ($output_selection == OUTPUT_EXPORTED) {
+               if (defined($function_table{$name})) {
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+        if ($output_selection == OUTPUT_INTERNAL) {
+               if (!($functype eq "function" && defined($function_table{$name}))) {
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+       if ($output_selection == OUTPUT_INCLUDE) {
+               if (defined($function_table{$name})) {
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+       if ($output_selection == OUTPUT_EXCLUDE) {
+               if (!defined($function_table{$name})) {
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+       die("Please add the new output type at show_warnings()");
+}
+
 sub dump_enum($$) {
     my $x = shift;
     my $file = shift;
@@ -2233,16 +1198,18 @@ sub dump_enum($$) {
            push @parameterlist, $arg;
            if (!$parameterdescs{$arg}) {
                $parameterdescs{$arg} = $undescribed;
-               print STDERR "${file}:$.: warning: Enum value '$arg' ".
-                   "not described in enum '$declaration_name'\n";
+               if (show_warnings("enum", $declaration_name)) {
+                       print STDERR "${file}:$.: warning: Enum value '$arg' not described in enum '$declaration_name'\n";
+               }
            }
            $_members{$arg} = 1;
        }
 
        while (my ($k, $v) = each %parameterdescs) {
            if (!exists($_members{$k})) {
-            print STDERR "${file}:$.: warning: Excess enum value " .
-                         "'$k' description in '$declaration_name'\n";
+               if (show_warnings("enum", $declaration_name)) {
+                    print STDERR "${file}:$.: warning: Excess enum value '$k' description in '$declaration_name'\n";
+               }
            }
         }
 
@@ -2278,7 +1245,7 @@ sub dump_typedef($$) {
        $declaration_name = $2;
        my $args = $3;
 
-       create_parameterlist($args, ',', $file);
+       create_parameterlist($args, ',', $file, $declaration_name);
 
        output_declaration($declaration_name,
                           'function',
@@ -2327,10 +1294,11 @@ sub save_struct_actual($) {
     $struct_actual = $struct_actual . $actual . " ";
 }
 
-sub create_parameterlist($$$) {
+sub create_parameterlist($$$$) {
     my $args = shift;
     my $splitter = shift;
     my $file = shift;
+    my $declaration_name = shift;
     my $type;
     my $param;
 
@@ -2355,12 +1323,12 @@ sub create_parameterlist($$$) {
        } elsif ($arg =~ m/\(.+\)\s*\(/) {
            # pointer-to-function
            $arg =~ tr/#/,/;
-           $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/;
+           $arg =~ m/[^\(]+\(\*?\s*([\w\.]*)\s*\)/;
            $param = $1;
            $type = $arg;
            $type =~ s/([^\(]+\(\*?)\s*$param/$1/;
            save_struct_actual($param);
-           push_parameter($param, $type, $file);
+           push_parameter($param, $type, $file, $declaration_name);
        } elsif ($arg) {
            $arg =~ s/\s*:\s*/:/g;
            $arg =~ s/\s*\[/\[/g;
@@ -2385,27 +1353,28 @@ sub create_parameterlist($$$) {
            foreach $param (@args) {
                if ($param =~ m/^(\*+)\s*(.*)/) {
                    save_struct_actual($2);
-                   push_parameter($2, "$type $1", $file);
+                   push_parameter($2, "$type $1", $file, $declaration_name);
                }
                elsif ($param =~ m/(.*?):(\d+)/) {
                    if ($type ne "") { # skip unnamed bit-fields
                        save_struct_actual($1);
-                       push_parameter($1, "$type:$2", $file)
+                       push_parameter($1, "$type:$2", $file, $declaration_name)
                    }
                }
                else {
                    save_struct_actual($param);
-                   push_parameter($param, $type, $file);
+                   push_parameter($param, $type, $file, $declaration_name);
                }
            }
        }
     }
 }
 
-sub push_parameter($$$) {
+sub push_parameter($$$$) {
        my $param = shift;
        my $type = shift;
        my $file = shift;
+       my $declaration_name = shift;
 
        if (($anon_struct_union == 1) && ($type eq "") &&
            ($param eq "}")) {
@@ -2442,21 +1411,15 @@ sub push_parameter($$$) {
        # warn if parameter has no description
        # (but ignore ones starting with # as these are not parameters
        # but inline preprocessor statements);
-       # also ignore unnamed structs/unions;
-       if (!$anon_struct_union) {
+       # Note: It will also ignore void params and unnamed structs/unions
        if (!defined $parameterdescs{$param} && $param !~ /^#/) {
+               $parameterdescs{$param} = $undescribed;
 
-           $parameterdescs{$param} = $undescribed;
-
-           if (($type eq 'function') || ($type eq 'enum')) {
-               print STDERR "${file}:$.: warning: Function parameter ".
-                   "or member '$param' not " .
-                   "described in '$declaration_name'\n";
-           }
-           print STDERR "${file}:$.: warning:" .
-                        " No description found for parameter '$param'\n";
-           ++$warnings;
-       }
+               if (show_warnings($type, $declaration_name)) {
+                       print STDERR
+                             "${file}:$.: warning: Function parameter or member '$param' not described in '$declaration_name'\n";
+                       ++$warnings;
+               }
        }
 
        $param = xml_escape($param);
@@ -2475,8 +1438,8 @@ sub push_parameter($$$) {
        $parametertypes{$param} = $type;
 }
 
-sub check_sections($$$$$$) {
-       my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_;
+sub check_sections($$$$$) {
+       my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck) = @_;
        my @sects = split ' ', $sectcheck;
        my @prms = split ' ', $prmscheck;
        my $err;
@@ -2510,14 +1473,6 @@ sub check_sections($$$$$$) {
                                        "'$sects[$sx]' " .
                                        "description in '$decl_name'\n";
                                ++$warnings;
-                       } else {
-                               if ($nested !~ m/\Q$sects[$sx]\E/) {
-                                   print STDERR "${file}:$.: warning: " .
-                                       "Excess $decl_type member " .
-                                       "'$sects[$sx]' " .
-                                       "description in '$decl_name'\n";
-                                   ++$warnings;
-                               }
                        }
                }
        }
@@ -2621,14 +1576,14 @@ sub dump_function($$) {
        $declaration_name = $2;
        my $args = $3;
 
-       create_parameterlist($args, ',', $file);
+       create_parameterlist($args, ',', $file, $declaration_name);
     } else {
        print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n";
        return;
     }
 
        my $prms = join " ", @parameterlist;
-       check_sections($file, $declaration_name, "function", $sectcheck, $prms, "");
+       check_sections($file, $declaration_name, "function", $sectcheck, $prms);
 
         # This check emits a lot of warnings at the moment, because many
         # functions don't have a 'Return' doc section. So until the number
@@ -2697,7 +1652,7 @@ sub tracepoint_munge($) {
 sub syscall_munge() {
        my $void = 0;
 
-       $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs
+       $prototype =~ s@[\r\n]+@ @gos; # strip newlines/CR's
 ##     if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) {
        if ($prototype =~ m/SYSCALL_DEFINE0/) {
                $void = 1;
@@ -2802,7 +1757,7 @@ sub process_proto_type($$) {
 # just before actual output; (this is done by local_unescape())
 sub xml_escape($) {
        my $text = shift;
-       if (($output_mode eq "text") || ($output_mode eq "man")) {
+       if ($output_mode eq "man") {
                return $text;
        }
        $text =~ s/\&/\\\\\\amp;/g;
@@ -2814,7 +1769,7 @@ sub xml_escape($) {
 # xml_unescape: reverse the effects of xml_escape
 sub xml_unescape($) {
        my $text = shift;
-       if (($output_mode eq "text") || ($output_mode eq "man")) {
+       if ($output_mode eq "man") {
                return $text;
        }
        $text =~ s/\\\\\\amp;/\&/g;
@@ -2827,7 +1782,7 @@ sub xml_unescape($) {
 # local escape strings look like:  '\\\\menmonic:' (that's 4 backslashes)
 sub local_unescape($) {
        my $text = shift;
-       if (($output_mode eq "text") || ($output_mode eq "man")) {
+       if ($output_mode eq "man") {
                return $text;
        }
        $text =~ s/\\\\\\\\lt:/</g;
@@ -2896,6 +1851,8 @@ sub process_file($) {
        while (s/\\\s*$//) {
            $_ .= <IN>;
        }
+       # Replace tabs by spaces
+        while ($_ =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {};
        if ($state == STATE_NORMAL) {
            if (/$doc_start/o) {
                $state = STATE_NAME;    # next line is always the function name
@@ -2995,8 +1952,7 @@ sub process_file($) {
                $in_purpose = 0;
                $contents = $newcontents;
                 $new_start_line = $.;
-               while ((substr($contents, 0, 1) eq " ") ||
-                      substr($contents, 0, 1) eq "\t") {
+               while (substr($contents, 0, 1) eq " ") {
                    $contents = substr($contents, 1);
                }
                if ($contents ne "") {
@@ -3065,8 +2021,7 @@ sub process_file($) {
                $contents = $2;
                 $new_start_line = $.;
                if ($contents ne "") {
-                   while ((substr($contents, 0, 1) eq " ") ||
-                          substr($contents, 0, 1) eq "\t") {
+                   while (substr($contents, 0, 1) eq " ") {
                        $contents = substr($contents, 1);
                    }
                    $contents .= "\n";
@@ -3143,38 +2098,12 @@ sub process_file($) {
        }
     }
     if ($initial_section_counter == $section_counter) {
-       print STDERR "${file}:1: warning: no structured comments found\n";
+       if ($output_mode ne "none") {
+           print STDERR "${file}:1: warning: no structured comments found\n";
+       }
        if (($output_selection == OUTPUT_INCLUDE) && ($show_not_found == 1)) {
            print STDERR "    Was looking for '$_'.\n" for keys %function_table;
        }
-       if ($output_mode eq "xml") {
-           # The template wants at least one RefEntry here; make one.
-           print "<refentry>\n";
-           print " <refnamediv>\n";
-           print "  <refname>\n";
-           print "   ${orig_file}\n";
-           print "  </refname>\n";
-           print "  <refpurpose>\n";
-           print "   Document generation inconsistency\n";
-           print "  </refpurpose>\n";
-           print " </refnamediv>\n";
-           print " <refsect1>\n";
-           print "  <title>\n";
-           print "   Oops\n";
-           print "  </title>\n";
-           print "  <warning>\n";
-           print "   <para>\n";
-           print "    The template for this document tried to insert\n";
-           print "    the structured comment from the file\n";
-           print "    <filename>${orig_file}</filename> at this point,\n";
-           print "    but none was found.\n";
-           print "    This dummy section is inserted to allow\n";
-           print "    generation to continue.\n";
-           print "   </para>\n";
-           print "  </warning>\n";
-           print " </refsect1>\n";
-           print "</refentry>\n";
-       }
     }
 }
 
@@ -3225,4 +2154,4 @@ if ($verbose && $warnings) {
   print STDERR "$warnings warnings\n";
 }
 
-exit($errors);
+exit($output_mode eq "none" ? 0 : $errors);
index 944cecd..aafd509 100644 (file)
@@ -304,7 +304,7 @@ static int _process_cmd(struct dmmp_context *ctx, int fd, const char *cmd,
                ipc_tmo = _DEFAULT_UXSOCK_TIMEOUT;
 
 invoke:
-       _debug(ctx, "Invoking IPC command '%s' with IPC tmo %u miliseconds",
+       _debug(ctx, "Invoking IPC command '%s' with IPC tmo %u milliseconds",
               cmd, ipc_tmo);
        flag_check_tmo = false;
        if (mpath_process_cmd(fd, cmd, output, ipc_tmo) != 0) {
index 84ab293..5199e42 100644 (file)
@@ -493,7 +493,7 @@ int mpath_prout_reg(struct multipath *mpp,int rq_servact, int rq_scope,
                thread[i].param.noisy = noisy;
                thread[i].param.status = MPATH_PR_SKIP;
 
-               condlog (3, "THRED ID [%d] INFO]", i);
+               condlog (3, "THREAD ID [%d] INFO]", i);
                condlog (3, "rq_servact=%d ", thread[i].param.rq_servact);
                condlog (3, "rq_scope=%d ", thread[i].param.rq_scope);
                condlog (3, "rq_type=%d ", thread[i].param.rq_type);
index 29df8c6..dbed4ca 100644 (file)
@@ -13,6 +13,7 @@
 #include <libudev.h>
 #include "mpath_pr_ioctl.h"
 #include "mpath_persist.h"
+#include "unaligned.h"
 
 #include "debug.h"
 
@@ -243,10 +244,9 @@ void mpath_format_readfullstatus(struct prin_resp *pr_buff, int len, int noisy)
                memcpy(&fdesc.key, p, 8 );
                fdesc.flag = p[12];
                fdesc.scope_type =  p[13];
-               fdesc.rtpi = ((p[18] << 8) | p[19]);
+               fdesc.rtpi = get_unaligned_be16(&p[18]);
 
-               tid_len_len = ((p[20] << 24) | (p[21] << 16) |
-                               (p[22] << 8) | p[23]);
+               tid_len_len = get_unaligned_be32(&p[20]);
 
                if (tid_len_len > 0)
                        decode_transport_id( &fdesc, &p[24], tid_len_len);
@@ -277,7 +277,7 @@ decode_transport_id(struct prin_fulldescr *fdesc, unsigned char * p, int length)
                        jump = 24;
                        break;
                case MPATH_PROTOCOL_ID_ISCSI:
-                       num = ((p[2] << 8) | p[3]);
+                       num = get_unaligned_be16(&p[2]);
                        memcpy(&fdesc->trnptid.iscsi_name, &p[4], num);
                        jump = (((num + 4) < 24) ? 24 : num + 4);
                        break;
index 9559038..87c15bd 100644 (file)
@@ -40,6 +40,8 @@ clean: dep_clean
        $(RM) core *.a *.o *.gz *.so
 
 OBJS := $(LIBS:libcheck%.so=%.o) libsg.o directio.o
+.SECONDARY: $(OBJS)
+
 include $(wildcard $(OBJS:.o=.d))
 
 dep_clean:
index 6019c9d..cee9aab 100644 (file)
@@ -14,6 +14,7 @@
 #include "checkers.h"
 
 #include "../libmultipath/sg_include.h"
+#include "../libmultipath/unaligned.h"
 
 #define TUR_CMD_LEN            6
 #define INQUIRY_CMDLEN         6
@@ -63,8 +64,7 @@ do_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
        if (evpd)
                inqCmdBlk[1] |= 1;
        inqCmdBlk[2] = (unsigned char) pg_op;
-       inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
-       inqCmdBlk[4] = (unsigned char) (mx_resp_len & 0xff);
+       put_unaligned_be16(mx_resp_len, &inqCmdBlk[3]);
        memset(&io_hdr, 0, sizeof (struct sg_io_hdr));
        memset(sense_b, 0, SENSE_BUFF_LEN);
        io_hdr.interface_id = 'S';
index c9e3411..2b270ca 100644 (file)
@@ -38,7 +38,7 @@
 #define DEFAULT_FORCE_SYNC     0
 #define DEFAULT_PARTITION_DELIM        NULL
 #define DEFAULT_SKIP_KPARTX SKIP_KPARTX_OFF
-#define DEFAULT_DISABLE_CHANGED_WWIDS 0
+#define DEFAULT_DISABLE_CHANGED_WWIDS 1
 #define DEFAULT_MAX_SECTORS_KB MAX_SECTORS_KB_UNDEF
 #define DEFAULT_GHOST_DELAY GHOST_DELAY_OFF
 
index 607aea8..767d87c 100644 (file)
@@ -27,7 +27,6 @@
 #include <sys/types.h>
 #include <time.h>
 
-#define FREE_CONST(p) do { free((void*)(unsigned long)p); p = NULL; } while(0)
 #define MAX_WAIT 5
 #define LOOPS_PER_SEC 5
 
@@ -1415,8 +1414,8 @@ out:
 
 void dm_reassign_deps(char *table, const char *dep, const char *newdep)
 {
-       char *n;
-       const char *p, *newtable;
+       char *n, *newtable;
+       const char *p;
 
        newtable = strdup(table);
        if (!newtable)
@@ -1427,7 +1426,7 @@ void dm_reassign_deps(char *table, const char *dep, const char *newdep)
        n += strlen(newdep);
        p += strlen(dep);
        strcat(n, p);
-       FREE_CONST(newtable);
+       FREE(newtable);
 }
 
 int dm_reassign_table(const char *name, char *old, char *new)
index 47dc2a3..ea273dd 100644 (file)
@@ -340,7 +340,7 @@ declare_def_handler(checker_timeout, set_int)
 declare_def_snprint(checker_timeout, print_nonzero)
 
 declare_def_handler(flush_on_last_del, set_yes_no_undef)
-declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef, YNU_NO)
+declare_def_snprint_defint(flush_on_last_del, print_yes_no_undef, DEFAULT_FLUSH)
 declare_ovr_handler(flush_on_last_del, set_yes_no_undef)
 declare_ovr_snprint(flush_on_last_del, print_yes_no_undef)
 declare_hw_handler(flush_on_last_del, set_yes_no_undef)
@@ -349,7 +349,8 @@ declare_mp_handler(flush_on_last_del, set_yes_no_undef)
 declare_mp_snprint(flush_on_last_del, print_yes_no_undef)
 
 declare_def_handler(user_friendly_names, set_yes_no_undef)
-declare_def_snprint_defint(user_friendly_names, print_yes_no_undef, YNU_NO)
+declare_def_snprint_defint(user_friendly_names, print_yes_no_undef,
+                          DEFAULT_USER_FRIENDLY_NAMES)
 declare_ovr_handler(user_friendly_names, set_yes_no_undef)
 declare_ovr_snprint(user_friendly_names, print_yes_no_undef)
 declare_hw_handler(user_friendly_names, set_yes_no_undef)
@@ -367,21 +368,24 @@ declare_def_handler(prkeys_file, set_str)
 declare_def_snprint(prkeys_file, print_str)
 
 declare_def_handler(retain_hwhandler, set_yes_no_undef)
-declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef, YNU_NO)
+declare_def_snprint_defint(retain_hwhandler, print_yes_no_undef,
+                          DEFAULT_RETAIN_HWHANDLER)
 declare_ovr_handler(retain_hwhandler, set_yes_no_undef)
 declare_ovr_snprint(retain_hwhandler, print_yes_no_undef)
 declare_hw_handler(retain_hwhandler, set_yes_no_undef)
 declare_hw_snprint(retain_hwhandler, print_yes_no_undef)
 
 declare_def_handler(detect_prio, set_yes_no_undef)
-declare_def_snprint_defint(detect_prio, print_yes_no_undef, YNU_NO)
+declare_def_snprint_defint(detect_prio, print_yes_no_undef,
+                          DEFAULT_DETECT_PRIO)
 declare_ovr_handler(detect_prio, set_yes_no_undef)
 declare_ovr_snprint(detect_prio, print_yes_no_undef)
 declare_hw_handler(detect_prio, set_yes_no_undef)
 declare_hw_snprint(detect_prio, print_yes_no_undef)
 
 declare_def_handler(detect_checker, set_yes_no_undef)
-declare_def_snprint_defint(detect_checker, print_yes_no_undef, YNU_NO)
+declare_def_snprint_defint(detect_checker, print_yes_no_undef,
+                          DEFAULT_DETECT_CHECKER)
 declare_ovr_handler(detect_checker, set_yes_no_undef)
 declare_ovr_snprint(detect_checker, print_yes_no_undef)
 declare_hw_handler(detect_checker, set_yes_no_undef)
@@ -391,7 +395,8 @@ declare_def_handler(force_sync, set_yes_no)
 declare_def_snprint(force_sync, print_yes_no)
 
 declare_def_handler(deferred_remove, set_yes_no_undef)
-declare_def_snprint_defint(deferred_remove, print_yes_no_undef, YNU_NO)
+declare_def_snprint_defint(deferred_remove, print_yes_no_undef,
+                          DEFAULT_DEFERRED_REMOVE)
 declare_ovr_handler(deferred_remove, set_yes_no_undef)
 declare_ovr_snprint(deferred_remove, print_yes_no_undef)
 declare_hw_handler(deferred_remove, set_yes_no_undef)
@@ -412,7 +417,8 @@ declare_def_handler(strict_timing, set_yes_no)
 declare_def_snprint(strict_timing, print_yes_no)
 
 declare_def_handler(skip_kpartx, set_yes_no_undef)
-declare_def_snprint_defint(skip_kpartx, print_yes_no_undef, YNU_NO)
+declare_def_snprint_defint(skip_kpartx, print_yes_no_undef,
+                          DEFAULT_SKIP_KPARTX)
 declare_ovr_handler(skip_kpartx, set_yes_no_undef)
 declare_ovr_snprint(skip_kpartx, print_yes_no_undef)
 declare_hw_handler(skip_kpartx, set_yes_no_undef)
@@ -629,7 +635,8 @@ print_fast_io_fail(char * buff, int len, long v)
 }
 
 declare_def_handler(fast_io_fail, set_fast_io_fail)
-declare_def_snprint_defint(fast_io_fail, print_fast_io_fail, DEFAULT_FAST_IO_FAIL)
+declare_def_snprint_defint(fast_io_fail, print_fast_io_fail,
+                          DEFAULT_FAST_IO_FAIL)
 declare_ovr_handler(fast_io_fail, set_fast_io_fail)
 declare_ovr_snprint(fast_io_fail, print_fast_io_fail)
 declare_hw_handler(fast_io_fail, set_fast_io_fail)
@@ -816,7 +823,7 @@ print_rr_weight (char * buff, int len, long v)
 }
 
 declare_def_handler(rr_weight, set_rr_weight)
-declare_def_snprint_defint(rr_weight, print_rr_weight, RR_WEIGHT_NONE)
+declare_def_snprint_defint(rr_weight, print_rr_weight, DEFAULT_RR_WEIGHT)
 declare_ovr_handler(rr_weight, set_rr_weight)
 declare_ovr_snprint(rr_weight, print_rr_weight)
 declare_hw_handler(rr_weight, set_rr_weight)
index 9efcaac..9f2a9c9 100644 (file)
@@ -30,6 +30,7 @@
 #include "discovery.h"
 #include "prio.h"
 #include "defaults.h"
+#include "unaligned.h"
 #include "prioritizers/alua_rtpg.h"
 #include "foreign.h"
 
@@ -53,8 +54,8 @@ alloc_path_with_pathinfo (struct config *conf, struct udev_device *udevice,
        if (!pp)
                return PATHINFO_FAILED;
 
-       if(wwid)
-               strncpy(pp->wwid, wwid, sizeof(pp->wwid));
+       if (wwid)
+               strlcpy(pp->wwid, wwid, sizeof(pp->wwid));
 
        if (safe_sprintf(pp->dev, "%s", devname)) {
                condlog(0, "pp->dev too small");
@@ -837,6 +838,8 @@ detect_alua(struct path * pp, struct config *conf)
 
 #define DEFAULT_SGIO_LEN 254
 
+/* Query VPD page @pg. Returns number of INQUIRY bytes
+   upon success and -1 upon failure. */
 static int
 sgio_get_vpd (unsigned char * buff, int maxlen, int fd, int pg)
 {
@@ -848,7 +851,7 @@ sgio_get_vpd (unsigned char * buff, int maxlen, int fd, int pg)
        }
 retry:
        if (0 == do_inq(fd, 0, 1, pg, buff, len)) {
-               len = buff[3] + (buff[2] << 8);
+               len = get_unaligned_be16(&buff[2]) + 4;
                if (len >= maxlen)
                        return len;
                if (len > DEFAULT_SGIO_LEN)
@@ -879,7 +882,7 @@ static int
 parse_vpd_pg80(const unsigned char *in, char *out, size_t out_len)
 {
        char *p = NULL;
-       int len = in[3] + (in[2] << 8);
+       int len = get_unaligned_be16(&in[2]);
 
        if (len >= out_len) {
                condlog(2, "vpd pg80 overflow, %d/%d bytes required",
@@ -1079,7 +1082,7 @@ get_vpd_sysfs (struct udev_device *parent, int pg, char * str, int maxlen)
                        pg, buff[1]);
                return -ENODATA;
        }
-       buff_len = (buff[2] << 8) + buff[3] + 4;
+       buff_len = get_unaligned_be16(&buff[2]) + 4;
        if (buff_len > 4096)
                condlog(3, "vpd pg%02x page truncated", pg);
 
@@ -1100,7 +1103,7 @@ get_vpd_sgio (int fd, int pg, char * str, int maxlen)
        unsigned char buff[4096];
 
        memset(buff, 0x0, 4096);
-       if (sgio_get_vpd(buff, 4096, fd, pg) <= 0) {
+       if (sgio_get_vpd(buff, 4096, fd, pg) < 0) {
                condlog(3, "failed to issue vpd inquiry for pg%02x",
                        pg);
                return -errno;
@@ -1111,7 +1114,7 @@ get_vpd_sgio (int fd, int pg, char * str, int maxlen)
                        pg, buff[1]);
                return -ENODATA;
        }
-       buff_len = (buff[2] << 8) + buff[3] + 4;
+       buff_len = get_unaligned_be16(&buff[2]) + 4;
        if (buff_len > 4096)
                condlog(3, "vpd pg%02x page truncated", pg);
 
@@ -1804,9 +1807,38 @@ get_vpd_uid(struct path * pp)
                parent = udev_device_get_parent(parent);
        }
 
+       if (!parent)
+               return -EINVAL;
+
        return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE);
 }
 
+static ssize_t scsi_uid_fallback(struct path *pp, int path_state,
+                            const char **origin)
+{
+       ssize_t len = 0;
+       int retrigger;
+       struct config *conf;
+
+       conf = get_multipath_config();
+       retrigger = conf->retrigger_tries;
+       put_multipath_config(conf);
+       if (pp->retriggers >= retrigger &&
+           !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) {
+               len = get_vpd_uid(pp);
+               *origin = "sysfs";
+               pp->uid_attribute = NULL;
+               if (len < 0 && path_state == PATH_UP) {
+                       condlog(1, "%s: failed to get sysfs uid: %s",
+                               pp->dev, strerror(-len));
+                       len = get_vpd_sgio(pp->fd, 0x83, pp->wwid,
+                                          WWID_SIZE);
+                       *origin = "sgio";
+               }
+       }
+       return len;
+}
+
 int
 get_uid (struct path * pp, int path_state, struct udev_device *udev)
 {
@@ -1821,11 +1853,6 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev)
                put_multipath_config(conf);
        }
 
-       if (!udev) {
-               condlog(1, "%s: no udev information", pp->dev);
-               return 1;
-       }
-
        memset(pp->wwid, 0, WWID_SIZE);
        if (pp->getuid) {
                char buff[CALLOUT_MAX_SIZE];
@@ -1848,9 +1875,8 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev)
                len = get_rbd_uid(pp);
                origin = "sysfs";
        } else {
-               int retrigger;
 
-               if (pp->uid_attribute) {
+               if (udev && pp->uid_attribute) {
                        len = get_udev_uid(pp, pp->uid_attribute, udev);
                        origin = "udev";
                        if (len <= 0)
@@ -1858,31 +1884,18 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev)
                                        "%s: failed to get udev uid: %s",
                                        pp->dev, strerror(-len));
 
-               } else {
+               } else if (pp->bus == SYSFS_BUS_SCSI) {
                        len = get_vpd_uid(pp);
                        origin = "sysfs";
                }
-               conf = get_multipath_config();
-               retrigger = conf->retrigger_tries;
-               put_multipath_config(conf);
-               if (len <= 0 && pp->retriggers >= retrigger &&
-                   !strcmp(pp->uid_attribute, DEFAULT_UID_ATTRIBUTE)) {
-                       len = get_vpd_uid(pp);
-                       origin = "sysfs";
-                       pp->uid_attribute = NULL;
-                       if (len < 0 && path_state == PATH_UP) {
-                               condlog(1, "%s: failed to get sysfs uid: %s",
-                                       pp->dev, strerror(-len));
-                               len = get_vpd_sgio(pp->fd, 0x83, pp->wwid,
-                                                  WWID_SIZE);
-                               origin = "sgio";
-                       }
-               }
+               if (len <= 0 && pp->bus == SYSFS_BUS_SCSI)
+                       len = scsi_uid_fallback(pp, path_state, &origin);
        }
        if ( len < 0 ) {
                condlog(1, "%s: failed to get %s uid: %s",
                        pp->dev, origin, strerror(-len));
                memset(pp->wwid, 0x0, WWID_SIZE);
+               return 1;
        } else {
                /* Strip any trailing blanks */
                c = strchr(pp->wwid, '\0');
index 0ade2d7..973f368 100644 (file)
@@ -74,7 +74,7 @@ struct foreign {
         * @retval FOREIGN_CLAIMED: device newly claimed
         * @retval FOREIGN_OK: device already registered, no action taken
         * @retval FOREIGN_IGNORED: device is ignored, no action taken
-        * @retval FOREIGN_ERR: an error occured (e.g. out-of-memory)
+        * @retval FOREIGN_ERR: an error occurred (e.g. out-of-memory)
         */
        int (*add)(struct context *, struct udev_device *);
 
@@ -87,7 +87,7 @@ struct foreign {
         * @returns status code
         * @retval FOREIGN_OK: event processed
         * @retval FOREIGN_IGNORED: the device is ignored
-        * @retval FOREIGN_ERR: an error occured (e.g. out-of-memory)
+        * @retval FOREIGN_ERR: an error occurred (e.g. out-of-memory)
         *
         * Note: theoretically it can happen that the status of a foreign device
         * (claimed vs. not claimed) changes in a change event.
@@ -107,7 +107,7 @@ struct foreign {
         * @returns status code
         * @retval FOREIGN_OK: processed correctly (device deleted)
         * @retval FOREIGN_IGNORED: device wasn't registered internally
-        * @retval FOREIGN_ERR: error occured.
+        * @retval FOREIGN_ERR: error occurred.
         */
        int (*delete)(struct context *, struct udev_device *);
 
@@ -120,7 +120,7 @@ struct foreign {
         * @returns status code
         * @retval FOREIGN_OK: processed correctly
         * @retval FOREIGN_IGNORED: nothing to delete
-        * @retval FOREIGN_ERR: error occured
+        * @retval FOREIGN_ERR: error occurred
         */
        int (*delete_all)(struct context*);
 
@@ -135,13 +135,13 @@ struct foreign {
        void (*check)(struct context *);
 
        /**
-        * lock internal data stuctures.
+        * lock internal data structures.
         * @param[in] ctx: foreign context
         */
        void (*lock)(struct context *ctx);
 
        /**
-        * unlock internal data stuctures.
+        * unlock internal data structures.
         * @param[in] ctx: foreign context (void* in order to use the function
         *      as argument to pthread_cleanup_push())
         */
@@ -217,7 +217,7 @@ void cleanup_foreign(void);
  * @retval FOREIGN_CLAIMED: newly claimed by a foreign lib
  * @retval FOREIGN_OK: already claimed by a foreign lib
  * @retval FOREIGN_IGNORED: ignored by all foreign libs
- * @retval FOREIGN_ERR: an error occured
+ * @retval FOREIGN_ERR: an error occurred
  */
 int add_foreign(struct udev_device *);
 
@@ -309,7 +309,7 @@ void print_foreign_topology(int verbosity);
 /**
  * is_claimed_by_foreign(ud)
  * @param udev: udev device
- * @returns: true iff device is (newly or already) claimed by a foreign lib
+ * @returns: true if device is (newly or already) claimed by a foreign lib
  */
 static inline bool
 is_claimed_by_foreign(struct udev_device *ud)
index dfba11e..fe98ddf 100644 (file)
@@ -24,6 +24,8 @@ clean: dep_clean
        $(RM) core *.a *.o *.gz *.so
 
 OBJS := $(LIBS:libforeign-%.so=%.o)
+.SECONDARY: $(OBJS)
+
 include $(wildcard $(OBJS:.o=.d))
 
 dep_clean:
index 6ba70c8..fe71d14 100644 (file)
                .delay_wait_checks = DELAY_CHECKS_OFF,
                .skip_kpartx   = SKIP_KPARTX_OFF,
                .max_sectors_kb = MAX_SECTORS_KB_UNDEF,
-               .ghost_delay = GHOST_DELAY_OFF
+               .ghost_delay   = GHOST_DELAY_OFF,
        },
 #endif
 
 static struct hwentry default_hw[] = {
        /*
-       * Generic NVMe devices
+       * Generic NVMe
        *
        * Due to the parsing logic in find_hwe(), generic entries
        * have to be put on top of this list, and more specific ones
@@ -178,7 +178,7 @@ static struct hwentry default_hw[] = {
                .prio_name     = PRIO_ALUA,
        },
        {
-               /* MSA 1040, 2040 and 2050 families */
+               /* MSA 1040, 1050, 2040 and 2050 families */
                .vendor        = "HP",
                .product       = "MSA [12]0[45]0 SA[NS]",
                .pgpolicy      = GROUP_BY_PRIO,
@@ -221,6 +221,57 @@ static struct hwentry default_hw[] = {
                .no_path_retry = 18,
                .prio_name     = PRIO_ALUA,
        },
+       {
+               /* Nimble Storage */
+               .vendor        = "Nimble",
+               .product       = "Server",
+               .hwhandler     = "1 alua",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .prio_name     = PRIO_ALUA,
+               .no_path_retry = NO_PATH_RETRY_QUEUE,
+       },
+               /* SGI */
+       {
+               .vendor        = "SGI",
+               .product       = "TP9100",
+               .pgpolicy      = MULTIBUS,
+       },
+       {
+               /* Total Performance family */
+               .vendor        = "SGI",
+               .product       = "TP9[3457]00",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
+       },
+       {
+               /* InfiniteStorage family */
+               .vendor        = "SGI",
+               .product       = "IS",
+               .bl_product    = "Universal Xport",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .checker_name  = RDAC,
+               .features      = "2 pg_init_retries 50",
+               .hwhandler     = "1 rdac",
+               .prio_name     = PRIO_RDAC,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .no_path_retry = 30,
+       },
+       {
+               /* (DDN) */
+               .vendor        = "SGI",
+               .product       = "^DD[46]A-",
+               .pgpolicy      = GROUP_BY_PRIO,
+               .pgfailback    = -FAILBACK_IMMEDIATE,
+               .prio_name     = PRIO_ALUA,
+               .no_path_retry = 30,
+       },
        /*
         * DataDirect Networks
         */
@@ -346,7 +397,7 @@ static struct hwentry default_hw[] = {
         * Mail : matthias.rudolph@hds.com
         */
        {
-               /* USP-V, HUS VM, VSP, VSP G1000 and VSP GX00 families */
+               /* USP-V, HUS VM, VSP, VSP G1X00 and VSP GX00 families */
                .vendor        = "(HITACHI|HP)",
                .product       = "^OPEN-",
                .pgpolicy      = MULTIBUS,
@@ -595,7 +646,7 @@ static struct hwentry default_hw[] = {
                .pgpolicy      = MULTIBUS,
        },
        {
-               /* DDN */
+               /* (DDN) DCS9900, SONAS 2851-DR1 */
                .vendor        = "IBM",
                .product       = "^(DCS9900|2851)",
                .pgpolicy      = GROUP_BY_PRIO,
@@ -680,12 +731,12 @@ static struct hwentry default_hw[] = {
                .pgpolicy      = MULTIBUS,
                .no_path_retry = 24,
        },
-       /*
-        * NetApp NVMe-FC namespace devices: MULTIBUS, queueing preferred
-        *
-        * The table is searched backwards, so place this after generic NVMe
-        */
        {
+               /*
+                * NVMe-FC namespace devices: MULTIBUS, queueing preferred
+                *
+                * The hwtable is searched backwards, so place this after "Generic NVMe"
+                */
                .vendor        = "NVME",
                .product       = "^NetApp ONTAP Controller",
                .uid_attribute = "ID_WWN",
@@ -707,49 +758,6 @@ static struct hwentry default_hw[] = {
                .no_path_retry = 30,
        },
        /*
-        * SGI
-        */
-       {
-               .vendor        = "SGI",
-               .product       = "TP9100",
-               .pgpolicy      = MULTIBUS,
-       },
-       {
-               /* Total Performance family */
-               .vendor        = "SGI",
-               .product       = "TP9[3457]00",
-               .bl_product    = "Universal Xport",
-               .pgpolicy      = GROUP_BY_PRIO,
-               .checker_name  = RDAC,
-               .features      = "2 pg_init_retries 50",
-               .hwhandler     = "1 rdac",
-               .prio_name     = PRIO_RDAC,
-               .pgfailback    = -FAILBACK_IMMEDIATE,
-               .no_path_retry = 30,
-       },
-       {
-               /* InfiniteStorage family */
-               .vendor        = "SGI",
-               .product       = "IS",
-               .bl_product    = "Universal Xport",
-               .pgpolicy      = GROUP_BY_PRIO,
-               .checker_name  = RDAC,
-               .features      = "2 pg_init_retries 50",
-               .hwhandler     = "1 rdac",
-               .prio_name     = PRIO_RDAC,
-               .pgfailback    = -FAILBACK_IMMEDIATE,
-               .no_path_retry = 30,
-       },
-       {
-               /* DDN */
-               .vendor        = "SGI",
-               .product       = "^DD[46]A-",
-               .pgpolicy      = GROUP_BY_PRIO,
-               .pgfailback    = -FAILBACK_IMMEDIATE,
-               .prio_name     = PRIO_ALUA,
-               .no_path_retry = 30,
-       },
-       /*
         * NEC
         */
        {
@@ -1014,18 +1022,6 @@ static struct hwentry default_hw[] = {
                .dev_loss      = 15,
        },
        /*
-        * Nimble Storage
-        */
-       {
-               .vendor        = "Nimble",
-               .product       = "Server",
-               .hwhandler     = "1 alua",
-               .pgpolicy      = GROUP_BY_PRIO,
-               .pgfailback    = -FAILBACK_IMMEDIATE,
-               .prio_name     = PRIO_ALUA,
-               .no_path_retry = NO_PATH_RETRY_QUEUE,
-       },
-       /*
         * Kaminario
         */
        {
@@ -1162,7 +1158,7 @@ static struct hwentry default_hw[] = {
                .no_path_retry = 30,
        },
        /*
-        * Dot Hill Systems - Seagate Technology
+        * Seagate Technology (Dot Hill Systems)
         */
        {
                /* SANnet family */
index ac81b4b..02b1453 100644 (file)
@@ -793,6 +793,9 @@ destroy_ctx:
 
 void stop_io_err_stat_thread(void)
 {
+       if (io_err_stat_thr == (pthread_t)0)
+               return;
+
        if (uatomic_read(&io_err_thread_running) == 1)
                pthread_cancel(io_err_stat_thr);
 
index ff5a030..7514642 100644 (file)
@@ -38,7 +38,7 @@
  * ! 9  ! Allocated             !
  * +----+-----------------------+
  *
- * global variabel debug bit 9 ( 512 ) used to
+ * global variable debug bit 9 ( 512 ) used to
  * flag some memory error.
  *
  */
index 63f59d8..a3c478e 100644 (file)
@@ -43,7 +43,6 @@ int debug;
                      (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
 #define STRDUP(n)    ( dbg_strdup((n), \
                      (__FILE__), (char *)(__FUNCTION__), (__LINE__)) )
-#define FREE_CONST(p) do { FREE((void*)(unsigned long)p); } while(0)
 
 /* Memory debug prototypes defs */
 extern void *dbg_malloc(unsigned long, char *, char *, int);
@@ -56,11 +55,6 @@ extern void dbg_free_final(char *);
 
 #define MALLOC(n)    (calloc(1,(n)))
 #define FREE(p)      do { free(p); p = NULL; } while(0)
-/*
- * Double cast to avoid warnings with -Wcast-qual
- * use this for valid free() operations on const pointers
- */
-#define FREE_CONST(p) do { free((void*)(unsigned long)p); p = NULL; } while(0)
 #define REALLOC(p,n) (realloc((p),(n)))
 #define STRDUP(n)    (strdup(n))
 
index 5caa201..2f9ab6e 100644 (file)
@@ -186,6 +186,12 @@ snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
        return fwd;
 }
 
+static const char quote_marker[] = { '\0', '"', '\0' };
+bool is_quote(const char* token)
+{
+       return !memcmp(token, quote_marker, sizeof(quote_marker));
+}
+
 vector
 alloc_strvec(char *string)
 {
@@ -219,19 +225,20 @@ alloc_strvec(char *string)
 
        in_string = 0;
        while (1) {
+               int two_quotes = 0;
+
                if (!vector_alloc_slot(strvec))
                        goto out;
 
                start = cp;
-               if (*cp == '"') {
+               if (*cp == '"' && !(in_string && *(cp + 1) == '"')) {
                        cp++;
-                       token = MALLOC(2);
+                       token = MALLOC(sizeof(quote_marker));
 
                        if (!token)
                                goto out;
 
-                       *(token) = '"';
-                       *(token + 1) = '\0';
+                       memcpy(token, quote_marker, sizeof(quote_marker));
                        if (in_string)
                                in_string = 0;
                        else
@@ -246,11 +253,23 @@ alloc_strvec(char *string)
                        *(token + 1) = '\0';
                        cp++;
                } else {
+
+               move_on:
                        while ((in_string ||
                                (!isspace((int) *cp) && isascii((int) *cp) &&
                                 *cp != '!' && *cp != '#' && *cp != '{' &&
                                 *cp != '}')) && *cp != '\0' && *cp != '"')
                                cp++;
+
+                       /* Two consecutive double quotes - don't end string */
+                       if (in_string && *cp == '"') {
+                               if (*(cp + 1) == '"') {
+                                       two_quotes = 1;
+                                       cp += 2;
+                                       goto move_on;
+                               }
+                       }
+
                        strlen = cp - start;
                        token = MALLOC(strlen + 1);
 
@@ -259,10 +278,21 @@ alloc_strvec(char *string)
 
                        memcpy(token, start, strlen);
                        *(token + strlen) = '\0';
+
+                       /* Replace "" by " */
+                       if (two_quotes) {
+                               char *qq = strstr(token, "\"\"");
+                               while (qq != NULL) {
+                                       memmove(qq + 1, qq + 2,
+                                               strlen + 1 - (qq + 2 - token));
+                                       qq = strstr(qq + 1, "\"\"");
+                               }
+                       }
                }
                vector_set_slot(strvec, token);
 
-               while ((isspace((int) *cp) || !isascii((int) *cp))
+               while ((!in_string &&
+                       (isspace((int) *cp) || !isascii((int) *cp)))
                       && *cp != '\0')
                        cp++;
                if (*cp == '\0' || *cp == '!' || *cp == '#')
@@ -299,13 +329,13 @@ set_value(vector strvec)
                        (char *)VECTOR_SLOT(strvec, 0));
                return NULL;
        }
-       size = strlen(str);
-       if (size == 0) {
-               condlog(0, "option '%s' has empty value",
-                       (char *)VECTOR_SLOT(strvec, 0));
-               return NULL;
-       }
-       if (*str != '"') {
+       if (!is_quote(str)) {
+               size = strlen(str);
+               if (size == 0) {
+                       condlog(0, "option '%s' has empty value",
+                               (char *)VECTOR_SLOT(strvec, 0));
+                       return NULL;
+               }
                alloc = MALLOC(sizeof (char) * (size + 1));
                if (alloc)
                        memcpy(alloc, str, size);
@@ -329,7 +359,7 @@ set_value(vector strvec)
                                (char *)VECTOR_SLOT(strvec, 0));
                        return NULL;
                }
-               if (*str == '"')
+               if (is_quote(str))
                        break;
                tmp = alloc;
                /* The first +1 is for the NULL byte. The rest are for the
@@ -435,7 +465,7 @@ validate_config_strvec(vector strvec, char *file)
                        (char *)VECTOR_SLOT(strvec, 0), line_nr, file);
                return -1;
        }
-       if (*str != '"') {
+       if (!is_quote(str)) {
                if (VECTOR_SIZE(strvec) > 2)
                        condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, 2), line_nr, file);
                return 0;
@@ -447,7 +477,7 @@ validate_config_strvec(vector strvec, char *file)
                                line_nr, file);
                        return -1;
                }
-               if (*str == '"') {
+               if (is_quote(str)) {
                        if (VECTOR_SIZE(strvec) > i + 1)
                                condlog(0, "ignoring extra data starting with '%s' on line %d of %s", (char *)VECTOR_SLOT(strvec, (i + 1)), line_nr, file);
                        return 0;
@@ -550,7 +580,7 @@ process_file(struct config *conf, char *file)
        FILE *stream;
 
        if (!conf->keywords) {
-               condlog(0, "No keywords alocated");
+               condlog(0, "No keywords allocated");
                return 1;
        }
        stream = fopen(file, "r");
index 0a74750..62906e9 100644 (file)
@@ -81,5 +81,6 @@ extern int process_file(struct config *conf, char *conf_file);
 extern struct keyword * find_keyword(vector keywords, vector v, char * name);
 int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
                    const void *data);
+bool is_quote(const char* token);
 
 #endif
index b3cc944..ab7bc07 100644 (file)
@@ -42,6 +42,8 @@ clean: dep_clean
        $(RM) core *.a *.o *.gz *.so
 
 OBJS = $(LIBS:libprio%.so=%.o) alua_rtpg.o
+.SECONDARY: $(OBJS)
+
 include $(wildcard $(OBJS:.o=.d))
 
 dep_clean:
index e9d8328..e431502 100644 (file)
@@ -26,6 +26,7 @@
 #include "../structs.h"
 #include "../prio.h"
 #include "../discovery.h"
+#include "../unaligned.h"
 #include "alua_rtpg.h"
 
 #define SENSE_BUFF_LEN  32
@@ -128,7 +129,7 @@ do_inquiry(int fd, int evpd, unsigned int codepage,
                inquiry_command_set_evpd(&cmd);
                cmd.page = codepage;
        }
-       set_uint16(cmd.length, resplen);
+       put_unaligned_be16(resplen, cmd.length);
        PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
 
        memset(&hdr, 0, sizeof(hdr));
@@ -220,7 +221,7 @@ get_target_port_group(struct path * pp, unsigned int timeout)
                if (rc < 0)
                        goto out;
 
-               scsi_buflen = (buf[2] << 8 | buf[3]) + 4;
+               scsi_buflen = get_unaligned_be16(&buf[2]) + 4;
                /* Paranoia */
                if (scsi_buflen >= USHRT_MAX)
                        scsi_buflen = USHRT_MAX;
@@ -251,7 +252,7 @@ get_target_port_group(struct path * pp, unsigned int timeout)
                                continue;
                        }
                        p  = (struct vpd83_tpg_dscr *)dscr->data;
-                       rc = get_uint16(p->tpg);
+                       rc = get_unaligned_be16(p->tpg);
                }
        }
 
@@ -274,7 +275,7 @@ do_rtpg(int fd, void* resp, long resplen, unsigned int timeout)
        memset(&cmd, 0, sizeof(cmd));
        cmd.op                  = OPERATION_CODE_RTPG;
        rtpg_command_set_service_action(&cmd);
-       set_uint32(cmd.length, resplen);
+       put_unaligned_be32(resplen, cmd.length);
        PRINT_HEX((unsigned char *) &cmd, sizeof(cmd));
 
        memset(&hdr, 0, sizeof(hdr));
@@ -321,7 +322,7 @@ get_asymmetric_access_state(int fd, unsigned int tpg, unsigned int timeout)
        rc = do_rtpg(fd, buf, buflen, timeout);
        if (rc < 0)
                goto out;
-       scsi_buflen = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]) + 4;
+       scsi_buflen = get_unaligned_be32(&buf[0]) + 4;
        if (scsi_buflen > UINT_MAX)
                scsi_buflen = UINT_MAX;
        if (buflen < scsi_buflen) {
@@ -342,7 +343,7 @@ get_asymmetric_access_state(int fd, unsigned int tpg, unsigned int timeout)
        tpgd = (struct rtpg_data *) buf;
        rc   = -RTPG_TPG_NOT_FOUND;
        RTPG_FOR_EACH_PORT_GROUP(tpgd, dscr) {
-               if (get_uint16(dscr->tpg) == tpg) {
+               if (get_unaligned_be16(dscr->tpg) == tpg) {
                        if (rc != -RTPG_TPG_NOT_FOUND) {
                                PRINT_DEBUG("get_asymmetric_access_state: "
                                        "more than one entry with same port "
index 13a0924..18b495e 100644 (file)
  */
 #ifndef __SPC3_H__
 #define __SPC3_H__
-/*=============================================================================
- * Some helper functions for getting and setting 16 and 32 bit values.
- *=============================================================================
- */
-static inline unsigned short
-get_uint16(unsigned char *p)
-{
-       return (p[0] << 8) + p[1];
-}
-
-static inline void
-set_uint16(unsigned char *p, unsigned short v)
-{
-       p[0] = (v >> 8) & 0xff;
-       p[1] = v & 0xff;
-}
-
-static inline unsigned int
-get_uint32(unsigned char *p)
-{
-       return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
-}
-
-static inline void
-set_uint32(unsigned char *p, unsigned int v)
-{
-       p[0] = (v >> 24) & 0xff;
-       p[1] = (v >> 16) & 0xff;
-       p[2] = (v >>  8) & 0xff;
-       p[3] = v & 0xff;
-}
 
 /*=============================================================================
  * Definitions to support the standard inquiry command as defined in SPC-3.
@@ -119,7 +88,7 @@ struct inquiry_data {
        unsigned char   b0;             /* xxx..... = peripheral_qualifier   */
                                        /* ...xxxxx = peripheral_device_type */
        unsigned char   b1;             /* x....... = removable medium       */
-                                       /* .xxxxxxx = reserverd              */
+                                       /* .xxxxxxx = reserved              */
        unsigned char   version;
        unsigned char   b3;             /* xx...... = obsolete               */
                                        /* ..x..... = normal aca supported   */
@@ -232,13 +201,13 @@ struct vpd83_data {
                for( \
                        d = p->data; \
                        (((char *) d) - ((char *) p)) < \
-                       get_uint16(p->length); \
+                       get_unaligned_be16(p->length); \
                        d = (struct vpd83_dscr *) \
                                ((char *) d + d->length + 4) \
                )
 
 /*=============================================================================
- * The following stuctures and macros are used to call the report target port
+ * The following structures and macros are used to call the report target port
  * groups command defined in SPC-3.
  * This command is used to get information about the target port groups (which
  * states are supported, which ports belong to this group, and so on) and the
@@ -315,7 +284,7 @@ struct rtpg_data {
 #define RTPG_FOR_EACH_PORT_GROUP(p, g) \
                for( \
                        g = &(p->data[0]); \
-                       (((char *) g) - ((char *) p)) < get_uint32(p->length); \
+                       (((char *) g) - ((char *) p)) < get_unaligned_be32(p->length); \
                        g = (struct rtpg_tpg_dscr *) ( \
                                ((char *) g) + \
                                sizeof(struct rtpg_tpg_dscr) + \
index ca06d6c..6505033 100644 (file)
@@ -22,6 +22,7 @@
 #include "debug.h"
 #include "prio.h"
 #include "structs.h"
+#include "unaligned.h"
 
 #define INQUIRY_CMD    0x12
 #define INQUIRY_CMDLEN 6
@@ -197,8 +198,7 @@ static int ontap_prio(const char *dev, int fd, unsigned int timeout)
        memset(&results, 0, sizeof (results));
        rc = send_gva(dev, fd, 0x41, results, &results_size, timeout);
        if (rc >= 0) {
-               tot_len = results[0] << 24 | results[1] << 16 |
-                         results[2] << 8 | results[3];
+               tot_len = get_unaligned_be32(&results[0]);
                if (tot_len <= 8) {
                        goto try_fcp_proxy;
                }
index 685ef33..c6a9e8b 100644 (file)
@@ -157,7 +157,7 @@ static int uevent_get_env_positive_int(const struct uevent *uev,
 void
 uevent_get_wwid(struct uevent *uev)
 {
-       const char *uid_attribute;
+       char *uid_attribute;
        const char *val;
        struct config * conf;
 
@@ -168,7 +168,7 @@ uevent_get_wwid(struct uevent *uev)
        val = uevent_get_env_var(uev, uid_attribute);
        if (val)
                uev->wwid = val;
-       FREE_CONST(uid_attribute);
+       FREE(uid_attribute);
 }
 
 bool
@@ -259,7 +259,7 @@ merge_need_stop(struct uevent *earlier, struct uevent *later)
        if (!earlier->wwid || !later->wwid)
                return true;
        /*
-        * uevents merging stoped
+        * uevents merging stopped
         * when we meet an opposite action uevent from the same LUN to AVOID
         * "add path1 |remove path1 |add path2 |remove path2 |add path3"
         * to merge as "remove path1, path2" and "add path1, path2, path3"
@@ -907,7 +907,7 @@ int uevent_get_disk_ro(const struct uevent *uev)
        return uevent_get_env_positive_int(uev, "DISK_RO");
 }
 
-static const char *uevent_get_dm_str(const struct uevent *uev, char *attr)
+static char *uevent_get_dm_str(const struct uevent *uev, char *attr)
 {
        const char *tmp = uevent_get_env_var(uev, attr);
 
@@ -916,17 +916,17 @@ static const char *uevent_get_dm_str(const struct uevent *uev, char *attr)
        return strdup(tmp);
 }
 
-const char *uevent_get_dm_name(const struct uevent *uev)
+char *uevent_get_dm_name(const struct uevent *uev)
 {
        return uevent_get_dm_str(uev, "DM_NAME");
 }
 
-const char *uevent_get_dm_path(const struct uevent *uev)
+char *uevent_get_dm_path(const struct uevent *uev)
 {
        return uevent_get_dm_str(uev, "DM_PATH");
 }
 
-const char *uevent_get_dm_action(const struct uevent *uev)
+char *uevent_get_dm_action(const struct uevent *uev)
 {
        return uevent_get_dm_str(uev, "DM_ACTION");
 }
index cb5347e..0aa8675 100644 (file)
@@ -36,9 +36,9 @@ int uevent_dispatch(int (*store_uev)(struct uevent *, void * trigger_data),
 int uevent_get_major(const struct uevent *uev);
 int uevent_get_minor(const struct uevent *uev);
 int uevent_get_disk_ro(const struct uevent *uev);
-const char *uevent_get_dm_name(const struct uevent *uev);
-const char *uevent_get_dm_path(const struct uevent *uev);
-const char *uevent_get_dm_action(const struct uevent *uev);
+char *uevent_get_dm_name(const struct uevent *uev);
+char *uevent_get_dm_path(const struct uevent *uev);
+char *uevent_get_dm_action(const struct uevent *uev);
 bool uevent_is_mpath(const struct uevent *uev);
 
 #endif /* _UEVENT_H */
diff --git a/libmultipath/unaligned.h b/libmultipath/unaligned.h
new file mode 100644 (file)
index 0000000..14ec8b2
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef _UNALIGNED_H_
+#define _UNALIGNED_H_
+
+#include <stdint.h>
+
+static inline uint16_t get_unaligned_be16(const void *ptr)
+{
+       const uint8_t *p = ptr;
+
+       return p[0] << 8 | p[1];
+}
+
+static inline uint32_t get_unaligned_be32(void *ptr)
+{
+       const uint8_t *p = ptr;
+
+       return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+static inline void put_unaligned_be16(uint16_t val, void *ptr)
+{
+       uint8_t *p = ptr;
+
+       p[0] = val >> 8;
+       p[1] = val;
+}
+
+static inline void put_unaligned_be32(uint32_t val, void *ptr)
+{
+       uint8_t *p = ptr;
+
+       p[0] = val >> 24;
+       p[1] = val >> 16;
+       p[2] = val >> 8;
+       p[3] = val;
+}
+
+#endif /* _UNALIGNED_H_ */
index 6b028ee..f25df1c 100644 (file)
@@ -20,8 +20,8 @@
 #ifndef _VERSION_H
 #define _VERSION_H
 
-#define VERSION_CODE 0x000705
-#define DATE_CODE    0x030712
+#define VERSION_CODE 0x000706
+#define DATE_CODE    0x030a12
 
 #define PROG    "multipath-tools"
 
index 8732cf8..716203e 100644 (file)
@@ -606,7 +606,7 @@ int delegate_to_multipathd(enum mpath_cmds cmd, const char *dev,
                           enum devtypes dev_type, const struct config *conf)
 {
        int fd;
-       char command[1024], *p, *reply;
+       char command[1024], *p, *reply = NULL;
        int n, r = 0;
 
        fd = mpath_connect();
index ab151e7..c4d0789 100644 (file)
@@ -67,6 +67,23 @@ recognized keywords for attributes or subsections depend on the
 section in which they occur.
 .LP
 .
+\fB<attribute>\fR and \fB<value>\fR must be on a single line.
+\fB<attribute>\fR is one of the keywords listed in this man page.
+\fB<value>\fR is either a simple word (containing no whitespace and none of the
+characters '\(dq', '#', and '!') or \fIone\fR string enclosed in double
+quotes ("..."). Outside a quoted string, text starting with '#', and '!' is
+regarded as a comment and ignored until the end of the line. Inside a quoted
+string, '#' and '!' are normal characters, and whitespace is preserved.
+To represent a double quote character inside a double quoted string, use two
+consecutive double quotes ('""'). Thus '2.5\(dq SSD' can be written as "2.5"" SSD".
+.LP
+.
+Opening braces ('{') must follow the (sub)section name on the same line. Closing
+braces ('}') that mark the end of a (sub)section must be the only non-whitespace
+character on the line. Whitespace is ignored except inside double quotes, thus
+the indentation shown in the above example is helpful for human readers but
+not mandatory.
+.LP
 .
 The following \fIsection\fP keywords are recognized:
 .TP 17
index f10f862..d5ee4ff 100644 (file)
@@ -279,7 +279,7 @@ get_cmdvec (char * cmd, vector *v)
        }
 
        vector_foreach_slot(strvec, buff, i) {
-               if (*buff == '"')
+               if (is_quote(buff))
                        continue;
                if (get_param) {
                        get_param = 0;
@@ -621,7 +621,7 @@ key_generator (const char * str, int state)
                len = strlen(str);
                int r = get_cmdvec(rl_line_buffer, &v);
                /*
-                * If a word completion is in progess, we don't want
+                * If a word completion is in progress, we don't want
                 * to take an exact keyword match in the fingerprint.
                 * For ex "show map[tab]" would validate "map" and discard
                 * "maps" as a valid candidate.
index 327cc19..a03ba20 100644 (file)
@@ -392,7 +392,7 @@ flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths)
 static int
 uev_add_map (struct uevent * uev, struct vectors * vecs)
 {
-       const char *alias;
+       char *alias;
        int major = -1, minor = -1, rc;
 
        condlog(3, "%s: add map (uevent)", uev->kernel);
@@ -413,7 +413,7 @@ uev_add_map (struct uevent * uev, struct vectors * vecs)
        pthread_testcancel();
        rc = ev_add_map(uev->kernel, alias, vecs);
        lock_cleanup_pop(vecs->lock);
-       FREE_CONST(alias);
+       FREE(alias);
        return rc;
 }
 
@@ -487,7 +487,7 @@ ev_add_map (char * dev, const char * alias, struct vectors * vecs)
 static int
 uev_remove_map (struct uevent * uev, struct vectors * vecs)
 {
-       const char *alias;
+       char *alias;
        int minor;
        struct multipath *mpp;
 
@@ -519,7 +519,7 @@ uev_remove_map (struct uevent * uev, struct vectors * vecs)
        remove_map_and_stop_waiter(mpp, vecs, 1);
 out:
        lock_cleanup_pop(vecs->lock);
-       FREE_CONST(alias);
+       FREE(alias);
        return 0;
 }
 
@@ -826,7 +826,7 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map)
                        vector_del_slot(mpp->paths, i);
 
                /*
-                * remove the map IFF removing the last path
+                * remove the map IF removing the last path
                 */
                if (VECTOR_SIZE(mpp->paths) == 0) {
                        char alias[WWID_SIZE];
@@ -940,15 +940,18 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
        pp = find_path_by_dev(vecs->pathvec, uev->kernel);
        if (pp) {
                struct multipath *mpp = pp->mpp;
-
-               if (disable_changed_wwids &&
-                   (strlen(pp->wwid) || pp->wwid_changed)) {
-                       char wwid[WWID_SIZE];
-
-                       strcpy(wwid, pp->wwid);
-                       get_uid(pp, pp->state, uev->udev);
-                       if (strcmp(wwid, pp->wwid) != 0) {
-                               condlog(0, "%s: path wwid changed from '%s' to '%s'. disallowing", uev->kernel, wwid, pp->wwid);
+               char wwid[WWID_SIZE];
+
+               strcpy(wwid, pp->wwid);
+               get_uid(pp, pp->state, uev->udev);
+
+               if (strncmp(wwid, pp->wwid, WWID_SIZE) != 0) {
+                       condlog(0, "%s: path wwid changed from '%s' to '%s'. %s",
+                               uev->kernel, wwid, pp->wwid,
+                               (disable_changed_wwids ? "disallowing" :
+                                "continuing"));
+                       if (disable_changed_wwids &&
+                           (strlen(wwid) || pp->wwid_changed)) {
                                strcpy(pp->wwid, wwid);
                                if (!pp->wwid_changed) {
                                        pp->wwid_changed = 1;
@@ -957,8 +960,18 @@ uev_update_path (struct uevent *uev, struct vectors * vecs)
                                                dm_fail_path(pp->mpp->alias, pp->dev_t);
                                }
                                goto out;
-                       } else
+                       } else if (!disable_changed_wwids)
+                               strcpy(pp->wwid, wwid);
+                       else
                                pp->wwid_changed = 0;
+               } else {
+                       udev_device_unref(pp->udev);
+                       pp->udev = udev_device_ref(uev->udev);
+                       conf = get_multipath_config();
+                       if (pathinfo(pp, conf, DI_SYSFS|DI_NOIO) != PATHINFO_OK)
+                               condlog(1, "%s: pathinfo failed after change uevent",
+                                       uev->kernel);
+                       put_multipath_config(conf);
                }
 
                if (pp->initialized == INIT_REQUESTED_UDEV)
@@ -1005,7 +1018,7 @@ out:
 static int
 uev_pathfail_check(struct uevent *uev, struct vectors *vecs)
 {
-       const char *action = NULL, *devt = NULL;
+       char *action = NULL, *devt = NULL;
        struct path *pp;
        int r = 1;
 
@@ -1032,11 +1045,11 @@ uev_pathfail_check(struct uevent *uev, struct vectors *vecs)
                                pp->dev);
 out_lock:
        lock_cleanup_pop(vecs->lock);
-       FREE_CONST(devt);
-       FREE_CONST(action);
+       FREE(devt);
+       FREE(action);
        return r;
 out:
-       FREE_CONST(action);
+       FREE(action);
        return 1;
 }
 
@@ -1212,7 +1225,7 @@ uxlsnrloop (void * ap)
        set_handler_callback(LIST+PATHS+RAW+FMT, cli_list_paths_raw);
        set_handler_callback(LIST+PATH, cli_list_path);
        set_handler_callback(LIST+MAPS, cli_list_maps);
-       set_unlocked_handler_callback(LIST+STATUS, cli_list_status);
+       set_handler_callback(LIST+STATUS, cli_list_status);
        set_unlocked_handler_callback(LIST+DAEMON, cli_list_daemon);
        set_handler_callback(LIST+MAPS+STATUS, cli_list_maps_status);
        set_handler_callback(LIST+MAPS+STATS, cli_list_maps_stats);
@@ -1435,7 +1448,7 @@ defered_failback_tick (vector mpvec)
 
        vector_foreach_slot (mpvec, mpp, i) {
                /*
-                * defered failback getting sooner
+                * deferred failback getting sooner
                 */
                if (mpp->pgfailback > 0 && mpp->failback_tick > 0) {
                        mpp->failback_tick--;
index 0531061..cdafd82 100644 (file)
@@ -148,7 +148,7 @@ void uxsock_cleanup(void *arg)
 {
        struct client *client_loop;
        struct client *client_tmp;
-       int ux_sock = (int)arg;
+       long ux_sock = (long)arg;
 
        close(ux_sock);
 
@@ -167,7 +167,7 @@ void uxsock_cleanup(void *arg)
  */
 void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, void * trigger_data)
 {
-       int ux_sock;
+       long ux_sock;
        int rlen;
        char *inbuf;
        char *reply;
index f6b5583..81f5518 100644 (file)
@@ -3,7 +3,7 @@ include ../Makefile.inc
 CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir)
 LIBDEPS += -L$(multipathdir) -lmultipath -lcmocka
 
-TESTS := uevent
+TESTS := uevent parser
 
 .SILENT: $(TESTS:%=%.o)
 .PRECIOUS: $(TESTS:%=%-test)
@@ -21,10 +21,9 @@ clean: dep_clean
        rm -f $(TESTS:%=%-test) $(TESTS:%=%.out) $(TESTS:%=%.o)
 
 OBJS = $(TESTS:%=%.o)
-include $(wildcard $(OBJS:.o=.d))
-
-
+.SECONDARY: $(OBJS)
 
+include $(wildcard $(OBJS:.o=.d))
 
 dep_clean:
        $(RM) $(OBJS:.o=.d)
index 96a5651..80f57bd 100644 (file)
@@ -6,6 +6,7 @@ struct udev *udev;
 int logsink = 0;
 struct config conf = {
        .uid_attrs = "sd:ID_BOGUS",
+       .verbosity = 4,
 };
 
 struct config *get_multipath_config(void)
diff --git a/tests/parser.c b/tests/parser.c
new file mode 100644 (file)
index 0000000..a7e7598
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ * Copyright (c) 2018 SUSE Linux GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ *
+ */
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <cmocka.h>
+// #include "list.h"
+#include "parser.h"
+#include "vector.h"
+
+#include "globals.c"
+
+/* Set these to 1 to get success for current broken behavior */
+/* Strip leading whitespace between quotes */
+#define LSTRIP_QUOTED_WSP 0
+/* Stop parsing at 2nd quote */
+#define TWO_QUOTES_ONLY 0
+
+static char *test_file = "test.conf";
+
+/* Missing declaration */
+int validate_config_strvec(vector strvec, char *file);
+
+/* Stringify helpers */
+#define _str_(x) #x
+#define str(x) _str_(x)
+
+static int setup(void **state)
+{
+       return 0;
+}
+
+static int teardown(void **state)
+{
+       return 0;
+}
+
+static void test01(void **state)
+{
+       vector v = alloc_strvec("keyword value");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 2);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_string_equal(VECTOR_SLOT(v, 1), "value");
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test02(void **state)
+{
+       vector v = alloc_strvec("keyword \"value\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), "value");
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test03(void **state)
+{
+       vector v = alloc_strvec("keyword value\n");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 2);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_string_equal(VECTOR_SLOT(v, 1), "value");
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test04(void **state)
+{
+       vector v = alloc_strvec("keyword \t   value   \t \n   ");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 2);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_string_equal(VECTOR_SLOT(v, 1), "value");
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test05(void **state)
+{
+       vector v = alloc_strvec("keyword \t   value   \t ! comment  ");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 2);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_string_equal(VECTOR_SLOT(v, 1), "value");
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test06(void **state)
+{
+       vector v = alloc_strvec("keyword \t   value   # \n comment  ");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 2);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_string_equal(VECTOR_SLOT(v, 1), "value");
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test07(void **state)
+{
+       vector v = alloc_strvec("keyword \t   value   more  ");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 3);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_string_equal(VECTOR_SLOT(v, 1), "value");
+       assert_string_equal(VECTOR_SLOT(v, 2), "more");
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test08(void **state)
+{
+#define QUOTED08 "  value   more  "
+#define QUOTED08B "value   more  "
+       vector v = alloc_strvec("keyword \t \"" QUOTED08 "\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+#if LSTRIP_QUOTED_WSP
+       assert_string_equal(VECTOR_SLOT(v, 2), QUOTED08B);
+#else
+       assert_string_equal(VECTOR_SLOT(v, 2), QUOTED08);
+#endif
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+#if LSTRIP_QUOTED_WSP
+       assert_string_equal(val, QUOTED08B);
+#else
+       assert_string_equal(val, QUOTED08);
+#endif
+       free(val);
+       free_strvec(v);
+}
+
+static void test09(void **state)
+{
+#define QUOTED09 "value # more"
+       vector v = alloc_strvec("keyword \"" QUOTED09 "\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), QUOTED09);
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, QUOTED09);
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test10(void **state)
+{
+#define QUOTED10 "value ! more"
+       vector v = alloc_strvec("keyword \"" QUOTED10 "\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), QUOTED10);
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, QUOTED10);
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test11(void **state)
+{
+#define QUOTED11 "value comment"
+       vector v = alloc_strvec("keyword\"" QUOTED11 "\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), QUOTED11);
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, QUOTED11);
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test12(void **state)
+{
+       vector v = alloc_strvec("key\"word\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "key");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), "word");
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "word");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test13(void **state)
+{
+       vector v = alloc_strvec("keyword value \"quoted\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 5);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_string_equal(VECTOR_SLOT(v, 1), "value");
+       assert_true(is_quote(VECTOR_SLOT(v, 2)));;
+       assert_string_equal(VECTOR_SLOT(v, 3), "quoted");
+       assert_true(is_quote(VECTOR_SLOT(v, 4)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "value");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test14(void **state)
+{
+       vector v = alloc_strvec("keyword \"value \"  comment\"\"");
+       char *val;
+
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 7);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), "value ");
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+       assert_string_equal(VECTOR_SLOT(v, 4), "comment");
+       assert_true(is_quote(VECTOR_SLOT(v, 5)));;
+       assert_true(is_quote(VECTOR_SLOT(v, 6)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "value ");
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test15(void **state)
+{
+#define QUOTED15 "word  value\n  comment"
+       vector v = alloc_strvec("key\"" QUOTED15 "\"");
+       char *val;
+
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "key");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), QUOTED15);
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+
+       val = set_value(v);
+       assert_string_equal(val, QUOTED15);
+
+       free(val);
+       free_strvec(v);
+}
+
+static void test16(void **state)
+{
+       vector v = alloc_strvec("keyword \"2.5\"\" SSD\"");
+       char *val;
+
+#if TWO_QUOTES_ONLY
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 6);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), "2.5");
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+       assert_string_equal(VECTOR_SLOT(v, 4), "SSD");
+       assert_true(is_quote(VECTOR_SLOT(v, 5)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "2.5");
+#else
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), "2.5\" SSD");
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "2.5\" SSD");
+#endif
+       free(val);
+       free_strvec(v);
+}
+
+static void test17(void **state)
+{
+       vector v = alloc_strvec("keyword \"\"\"\"\" is empty\"");
+       char *val;
+#if TWO_QUOTES_ONLY
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 6);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_true(is_quote(VECTOR_SLOT(v, 2)));;
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+#if LSTRIP_QUOTED_WSP
+       assert_string_equal(VECTOR_SLOT(v, 4), "is empty");
+#else
+       assert_string_equal(VECTOR_SLOT(v, 4), " is empty");
+#endif
+       assert_true(is_quote(VECTOR_SLOT(v, 5)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "");
+#else
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), "\"\" is empty");
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "\"\" is empty");
+#endif
+       free(val);
+       free_strvec(v);
+}
+
+static void test18(void **state)
+{
+       vector v = alloc_strvec("keyword \"\"\"\"");
+       char *val;
+#if TWO_QUOTES_ONLY
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 5);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_true(is_quote(VECTOR_SLOT(v, 2)));;
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+       assert_true(is_quote(VECTOR_SLOT(v, 4)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "");
+#else
+       assert_int_equal(validate_config_strvec(v, test_file), 0);
+       assert_int_equal(VECTOR_SIZE(v), 4);
+       assert_string_equal(VECTOR_SLOT(v, 0), "keyword");
+       assert_true(is_quote(VECTOR_SLOT(v, 1)));;
+       assert_string_equal(VECTOR_SLOT(v, 2), "\"");
+       assert_true(is_quote(VECTOR_SLOT(v, 3)));;
+
+       val = set_value(v);
+       assert_string_equal(val, "\"");
+#endif
+       free(val);
+       free_strvec(v);
+}
+
+int test_config_parser(void)
+{
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test(test01),
+               cmocka_unit_test(test02),
+               cmocka_unit_test(test03),
+               cmocka_unit_test(test04),
+               cmocka_unit_test(test05),
+               cmocka_unit_test(test06),
+               cmocka_unit_test(test07),
+               cmocka_unit_test(test08),
+               cmocka_unit_test(test09),
+               cmocka_unit_test(test10),
+               cmocka_unit_test(test11),
+               cmocka_unit_test(test12),
+               cmocka_unit_test(test13),
+               cmocka_unit_test(test14),
+               cmocka_unit_test(test15),
+               cmocka_unit_test(test16),
+               cmocka_unit_test(test17),
+               cmocka_unit_test(test18),
+       };
+       return cmocka_run_group_tests(tests, setup, teardown);
+}
+
+int main(void)
+{
+       int ret = 0;
+
+       ret += test_config_parser();
+       return ret;
+}
index b7d6458..acfcb14 100644 (file)
@@ -169,44 +169,44 @@ static void test_major_bad_8(void **state)
 static void test_dm_name_good(void **state)
 {
        struct uevent *uev = *state;
-       const char *name = uevent_get_dm_name(uev);
+       char *name = uevent_get_dm_name(uev);
 
        assert_string_equal(name, DM_NAME);
-       free((void*)name);
+       FREE(name);
 }
 
 static void test_dm_name_bad_0(void **state)
 {
        struct uevent *uev = *state;
-       const char *name;
+       char *name;
 
        uev->envp[3] = "DM_NAME" DM_NAME;
        name = uevent_get_dm_name(uev);
        assert_ptr_equal(name, NULL);
-       free((void*)name);
+       FREE(name);
 }
 
 static void test_dm_name_bad_1(void **state)
 {
        struct uevent *uev = *state;
-       const char *name;
+       char *name;
 
        uev->envp[3] = "DM_NAMES=" DM_NAME;
        name = uevent_get_dm_name(uev);
        assert_ptr_equal(name, NULL);
-       free((void*)name);
+       FREE(name);
 }
 
 static void test_dm_name_good_1(void **state)
 {
        struct uevent *uev = *state;
-       const char *name;
+       char *name;
 
        /* Note we change index 2 here */
        uev->envp[2] = "DM_NAME=" DM_NAME;
        name = uevent_get_dm_name(uev);
        assert_string_equal(name, DM_NAME);
-       free((void*)name);
+       FREE(name);
 }
 
 static void test_dm_uuid_false_0(void **state)