From 814f4a07a4e8351eee3f129c1963f479c66a44d5 Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Fri, 14 Jan 2022 13:50:18 +0900 Subject: [PATCH] Imported Upstream version 0.7.6 --- Makefile.inc | 1 + README | 3 +- kpartx/devmapper.c | 2 +- kpartx/lopart.c | 7 +- kpartx/solaris.c | 2 +- kpartx/test-kpartx | 2 +- libdmmp/DEV_NOTES | 2 +- libdmmp/docs/kernel-doc | 1507 +++++---------------------------- libdmmp/libdmmp.c | 2 +- libmpathpersist/mpath_persist.c | 2 +- libmpathpersist/mpath_pr_ioctl.c | 8 +- libmultipath/checkers/Makefile | 2 + libmultipath/checkers/hp_sw.c | 4 +- libmultipath/defaults.h | 2 +- libmultipath/devmapper.c | 7 +- libmultipath/dict.c | 25 +- libmultipath/discovery.c | 75 +- libmultipath/foreign.h | 16 +- libmultipath/foreign/Makefile | 2 + libmultipath/hwtable.c | 128 ++- libmultipath/io_err_stat.c | 3 + libmultipath/memory.c | 2 +- libmultipath/memory.h | 6 - libmultipath/parser.c | 62 +- libmultipath/parser.h | 1 + libmultipath/prioritizers/Makefile | 2 + libmultipath/prioritizers/alua_rtpg.c | 13 +- libmultipath/prioritizers/alua_spc3.h | 39 +- libmultipath/prioritizers/ontap.c | 4 +- libmultipath/uevent.c | 14 +- libmultipath/uevent.h | 6 +- libmultipath/unaligned.h | 38 + libmultipath/version.h | 4 +- multipath/main.c | 2 +- multipath/multipath.conf.5 | 17 + multipathd/cli.c | 4 +- multipathd/main.c | 55 +- multipathd/uxlsnr.c | 4 +- tests/Makefile | 7 +- tests/globals.c | 1 + tests/parser.c | 474 +++++++++++ tests/uevent.c | 16 +- 42 files changed, 1033 insertions(+), 1540 deletions(-) mode change 100644 => 100755 libdmmp/docs/kernel-doc create mode 100644 libmultipath/unaligned.h create mode 100644 tests/parser.c diff --git a/Makefile.inc b/Makefile.inc index a5b9d4e..5d6123d 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -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 --- 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 diff --git a/kpartx/devmapper.c b/kpartx/devmapper.c index eb9dac6..8f68a24 100644 --- a/kpartx/devmapper.c +++ b/kpartx/devmapper.c @@ -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) diff --git a/kpartx/lopart.c b/kpartx/lopart.c index 02b29e8..69c1eda 100644 --- a/kpartx/lopart.c +++ b/kpartx/lopart.c @@ -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'; diff --git a/kpartx/solaris.c b/kpartx/solaris.c index 01da379..8c1a971 100644 --- a/kpartx/solaris.c +++ b/kpartx/solaris.c @@ -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 */ }; diff --git a/kpartx/test-kpartx b/kpartx/test-kpartx index 09d15a9..9cee20f 100755 --- a/kpartx/test-kpartx +++ b/kpartx/test-kpartx @@ -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 diff --git a/libdmmp/DEV_NOTES b/libdmmp/DEV_NOTES index 220a9f4..3460cdf 100644 --- a/libdmmp/DEV_NOTES +++ b/libdmmp/DEV_NOTES @@ -1,4 +1,4 @@ -== Planed features == +== Planned features == * Expose all properties used by /usr/bin/multipath == Code style == diff --git a/libdmmp/docs/kernel-doc b/libdmmp/docs/kernel-doc old mode 100644 new mode 100755 index 7bd52b8..fee8952 --- a/libdmmp/docs/kernel-doc +++ b/libdmmp/docs/kernel-doc @@ -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 = '\&(enum\s*([_\w]+))'; -my $type_struct_xml = '\&(struct\s*([_\w]+))'; -my $type_typedef_xml = '\&(typedef\s*([_\w]+))'; -my $type_union_xml = '\&(union\s*([_\w]+))'; -my $type_member_xml = '\&([_\w]+)(\.|-\>)([_\w]+)'; -my $type_fallback_xml = '\&([_\w]+)'; my $type_member_func = $type_member . '\(\)'; # Output conversion substitutions. # One for each output format -# these work fairly well -my @highlights_html = ( - [$type_constant, "\$1"], - [$type_constant2, "\$1"], - [$type_func, "\$1"], - [$type_enum_xml, "\$1"], - [$type_struct_xml, "\$1"], - [$type_typedef_xml, "\$1"], - [$type_union_xml, "\$1"], - [$type_env, "\$1"], - [$type_param, "\$1"], - [$type_member_xml, "\$1\$2\$3"], - [$type_fallback_xml, "\$1"] - ); -my $local_lt = "\\\\\\\\lt:"; -my $local_gt = "\\\\\\\\gt:"; -my $blankline_html = $local_lt . "p" . $local_gt; # was "

" - -# html version 5 -my @highlights_html5 = ( - [$type_constant, "\$1"], - [$type_constant2, "\$1"], - [$type_func, "\$1"], - [$type_enum_xml, "\$1"], - [$type_struct_xml, "\$1"], - [$type_typedef_xml, "\$1"], - [$type_union_xml, "\$1"], - [$type_env, "\$1"], - [$type_param, "\$1]"], - [$type_member_xml, "\$1\$2\$3"], - [$type_fallback_xml, "\$1"] - ); -my $blankline_html5 = $local_lt . "br /" . $local_gt; - -# XML, docbook format -my @highlights_xml = ( - ["([^=])\\\"([^\\\"<]+)\\\"", "\$1\$2"], - [$type_constant, "\$1"], - [$type_constant2, "\$1"], - [$type_enum_xml, "\$1"], - [$type_struct_xml, "\$1"], - [$type_typedef_xml, "\$1"], - [$type_union_xml, "\$1"], - [$type_param, "\$1"], - [$type_func, "\$1"], - [$type_env, "\$1"], - [$type_member_xml, "\$1\$2\$3"], - [$type_fallback_xml, "\$1"] - ); -my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n"; - -# gnome, docbook format -my @highlights_gnome = ( - [$type_constant, "\$1"], - [$type_constant2, "\$1"], - [$type_func, "\$1"], - [$type_enum, "\$1"], - [$type_struct, "\$1"], - [$type_typedef, "\$1"], - [$type_union, "\$1"], - [$type_env, "\$1"], - [$type_param, "\$1" ], - [$type_member, "\$1\$2\$3"], - [$type_fallback, "\$1"] - ); -my $blankline_gnome = "\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 "

$section

\n"; - print "
\n"; - output_highlight($args{'sections'}{$section}); - print "
\n"; - } -} - -# output enum in html -sub output_enum_html(%) { - my %args = %{$_[0]}; - my ($parameter); - my $count; - print "

enum " . $args{'enum'} . "

\n"; - - print "enum " . $args{'enum'} . " {
\n"; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print " " . $parameter . ""; - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ",\n"; - } - print "
"; - } - print "};
\n"; - - print "

Constants

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
" . $parameter . "\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter}); - } - print "
\n"; - output_section_html(@_); - print "
\n"; -} - -# output typedef in html -sub output_typedef_html(%) { - my %args = %{$_[0]}; - my ($parameter); - my $count; - print "

typedef " . $args{'typedef'} . "

\n"; - - print "typedef " . $args{'typedef'} . "\n"; - output_section_html(@_); - print "
\n"; -} - -# output struct in html -sub output_struct_html(%) { - my %args = %{$_[0]}; - my ($parameter); - - print "

" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "

\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"; - - print "

Members

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; - - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - } - print "
\n"; - output_section_html(@_); - print "
\n"; -} - -# output function in html -sub output_function_html(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - - print "

" . $args{'function'} . " - " . $args{'purpose'} . "

\n"; - print "" . $args{'functiontype'} . "\n"; - print "" . $args{'function'} . "\n"; - print "("; - $count = 0; - foreach $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 ")\n"; - - print "

Arguments

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - } - print "
\n"; - output_section_html(@_); - print "
\n"; -} - -# output DOC: block header in html -sub output_blockhead_html(%) { - my %args = %{$_[0]}; - my ($parameter, $section); - my $count; - - foreach $section (@{$args{'sectionlist'}}) { - print "

$section

\n"; - print "\n"; - } - print "
\n"; -} - -# output sections in html5 -sub output_section_html5(%) { - my %args = %{$_[0]}; - my $section; - - foreach $section (@{$args{'sectionlist'}}) { - print "
\n"; - print "

$section

\n"; - print "

\n"; - output_highlight($args{'sections'}{$section}); - print "

\n"; - print "
\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 "
"; - print "

enum " . $args{'enum'} . "

\n"; - print "
    \n"; - print "
  1. "; - print "enum "; - print "" . $args{'enum'} . " {"; - print "
  2. \n"; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
  3. "; - print "" . $parameter . ""; - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ","; - } - print "
  4. \n"; - } - print "
  5. };
  6. \n"; - print "
\n"; - - print "
\n"; - print "

Constants

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
" . $parameter . "
\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter}); - print "
\n"; - } - print "
\n"; - print "
\n"; - output_section_html5(@_); - print "
\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 "
\n"; - print "

typedef " . $args{'typedef'} . "

\n"; - - print "
    \n"; - print "
  1. "; - print "typedef "; - print "" . $args{'typedef'} . ""; - print "
  2. \n"; - print "
\n"; - output_section_html5(@_); - print "
\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 "
\n"; - print "
\n"; - print "

" . $args{'type'} . " " . $args{'struct'} . "

"; - print "

". $args{'purpose'} . "

\n"; - print "
\n"; - print "
    \n"; - print "
  1. "; - print "" . $args{'type'} . " "; - print "" . $args{'struct'} . " {"; - print "
  2. \n"; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
  3. "; - if ($parameter =~ /^#/) { - print "" . $parameter ."\n"; - print "
  4. \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 "; - print "$parameter"; - print ") "; - print "($2);"; - } elsif ($type =~ m/^(.*?)\s*(:.*)/) { - # bitfield - print "$1 "; - print "$parameter"; - print "$2;"; - } else { - print "$type "; - print "$parameter;"; - } - print "\n"; - } - print "
  5. };
  6. \n"; - print "
\n"; - - print "
\n"; - print "

Members

\n"; - print "
\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - ($parameter =~ /^#/) && next; - - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "
\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print "
\n"; - } - print "
\n"; - print "
\n"; - output_section_html5(@_); - print "
\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 "
\n"; - print "
\n"; - print "

" . $args{'function'} . "

"; - print "

" . $args{'purpose'} . "

\n"; - print "
\n"; - print "
    \n"; - print "
  1. "; - print "" . $args{'functiontype'} . " "; - print "" . $args{'function'} . " ("; - print "
  2. "; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print "
  3. "; - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print "$1 "; - print "$parameter"; - print ") "; - print "($2)"; - } else { - print "$type "; - print "$parameter"; - } - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ","; - } - print "
  4. \n"; - } - print "
  5. )
  6. \n"; - print "
\n"; - - print "
\n"; - print "

Arguments

\n"; - print "

\n"; - print "

\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next; - print "
" . $parameter . "
\n"; - print "
"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print "
\n"; - } - print "
\n"; - print "
\n"; - output_section_html5(@_); - print "
\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 "
\n"; - print "

$section

\n"; - print "

\n"; - output_highlight($args{'sections'}{$section}); - print "

\n"; - } - print "
\n"; -} - -sub output_section_xml(%) { - my %args = %{$_[0]}; - my $section; - # print out each section - $lineprefix=" "; - foreach $section (@{$args{'sectionlist'}}) { - print "\n"; - print "$section\n"; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - $output_preformatted = 1; - } else { - print "\n"; - } - output_highlight($args{'sections'}{$section}); - $output_preformatted = 0; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - } else { - print "\n"; - } - print "\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 "\n"; - print "\n"; - print " LINUX\n"; - print " Kernel Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " " . $args{'function'} . "\n"; - print " 9\n"; - print " " . $kernelversion . "\n"; - print "\n"; - print "\n"; - print " " . $args{'function'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " \n"; - print " " . $args{'functiontype'} . " "; - print "" . $args{'function'} . " \n"; - - $count = 0; - if ($#{$args{'parameterlist'}} >= 0) { - foreach $parameter (@{$args{'parameterlist'}}) { - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print " $1$parameter)\n"; - print " $2\n"; - } else { - print " " . $type; - print " $parameter\n"; - } - } - } else { - print " \n"; - } - print " \n"; - print "\n"; - - # print parameters - print "\n Arguments\n"; - if ($#{$args{'parameterlist'}} >= 0) { - print " \n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - $type = $args{'parametertypes'}{$parameter}; - - print " \n $type $parameter\n"; - print " \n \n"; - $lineprefix=" "; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n \n \n"; - } - print " \n"; - } else { - print " \n None\n \n"; - } - print "\n"; - - output_section_xml(@_); - print "\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 "\n"; - print "\n"; - print " LINUX\n"; - print " Kernel Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " " . $args{'type'} . " " . $args{'struct'} . "\n"; - print " 9\n"; - print " " . $kernelversion . "\n"; - print "\n"; - print "\n"; - print " " . $args{'type'} . " " . $args{'struct'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " \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 " \n"; - print "\n"; - - print " \n"; - print " Members\n"; - - if ($#{$args{'parameterlist'}} >= 0) { - print " \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 " "; - print " $type $parameter\n"; - print " \n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n"; - print " \n"; - } - print " \n"; - } else { - print " \n None\n \n"; - } - print " \n"; - - output_section_xml(@_); - - print "\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 "\n"; - print "\n"; - print " LINUX\n"; - print " Kernel Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " enum " . $args{'enum'} . "\n"; - print " 9\n"; - print " " . $kernelversion . "\n"; - print "\n"; - print "\n"; - print " enum " . $args{'enum'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " \n"; - print "enum " . $args{'enum'} . " {\n"; - $count = 0; - foreach $parameter (@{$args{'parameterlist'}}) { - print " $parameter"; - if ($count != $#{$args{'parameterlist'}}) { - $count++; - print ","; - } - print "\n"; - } - print "};"; - print " \n"; - print "\n"; - - print "\n"; - print " Constants\n"; - print " \n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - print " "; - print " $parameter\n"; - print " \n"; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n"; - print " \n"; - } - print " \n"; - print "\n"; - - output_section_xml(@_); - - print "\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 "\n"; - print "\n"; - print " LINUX\n"; - print " Kernel Hackers Manual\n"; - print " $man_date\n"; - print "\n"; - print "\n"; - print " typedef " . $args{'typedef'} . "\n"; - print " 9\n"; - print "\n"; - print "\n"; - print " typedef " . $args{'typedef'} . "\n"; - print " \n"; - print " "; - output_highlight ($args{'purpose'}); - print " \n"; - print "\n"; - - print "\n"; - print " Synopsis\n"; - print " typedef " . $args{'typedef'} . ";\n"; - print "\n"; - - output_section_xml(@_); - - print "\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 "\n $section\n"; - } - if ($section =~ m/EXAMPLE/i) { - print "\n"; - $output_preformatted = 1; - } else { - print "\n"; - } - output_highlight($args{'sections'}{$section}); - $output_preformatted = 0; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - } else { - print ""; - } - if (!$args{'content-only'}) { - print "\n\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 "\n"; - print " " . $args{'function'} . "\n"; - - print " \n"; - print " " . $args{'functiontype'} . " "; - print "" . $args{'function'} . " "; - print "\n"; - - $count = 0; - if ($#{$args{'parameterlist'}} >= 0) { - foreach $parameter (@{$args{'parameterlist'}}) { - $type = $args{'parametertypes'}{$parameter}; - if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) { - # pointer-to-function - print " $1 $parameter)\n"; - print " $2\n"; - } else { - print " " . $type; - print " $parameter\n"; - } - } - } else { - print " \n"; - } - print " \n"; - if ($#{$args{'parameterlist'}} >= 0) { - print " \n"; - print "\n"; - print "\n"; - print "\n"; - print "\n"; - foreach $parameter (@{$args{'parameterlist'}}) { - my $parameter_name = $parameter; - $parameter_name =~ s/\[.*//; - - print " $parameter\n"; - print " \n"; - $lineprefix=" "; - output_highlight($args{'parameterdescs'}{$parameter_name}); - print " \n"; - } - print " \n"; - } else { - print " \n None\n \n"; - } - - # print out each section - $lineprefix=" "; - foreach $section (@{$args{'sectionlist'}}) { - print "\n $section\n"; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - $output_preformatted = 1; - } else { - } - print "\n"; - output_highlight($args{'sections'}{$section}); - $output_preformatted = 0; - print "\n"; - if ($section =~ m/EXAMPLE/i) { - print "\n"; - } else { - } - print " \n"; - } - - print "\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:/; } + # 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 "\n"; - print " \n"; - print " \n"; - print " ${orig_file}\n"; - print " \n"; - print " \n"; - print " Document generation inconsistency\n"; - print " \n"; - print " \n"; - print " \n"; - print " \n"; - print " Oops\n"; - print " \n"; - print " \n"; - print " \n"; - print " The template for this document tried to insert\n"; - print " the structured comment from the file\n"; - print " ${orig_file} 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 " \n"; - print " \n"; - print " \n"; - print "\n"; - } } } @@ -3225,4 +2154,4 @@ if ($verbose && $warnings) { print STDERR "$warnings warnings\n"; } -exit($errors); +exit($output_mode eq "none" ? 0 : $errors); diff --git a/libdmmp/libdmmp.c b/libdmmp/libdmmp.c index 944cecd..aafd509 100644 --- a/libdmmp/libdmmp.c +++ b/libdmmp/libdmmp.c @@ -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) { diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c index 84ab293..5199e42 100644 --- a/libmpathpersist/mpath_persist.c +++ b/libmpathpersist/mpath_persist.c @@ -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); diff --git a/libmpathpersist/mpath_pr_ioctl.c b/libmpathpersist/mpath_pr_ioctl.c index 29df8c6..dbed4ca 100644 --- a/libmpathpersist/mpath_pr_ioctl.c +++ b/libmpathpersist/mpath_pr_ioctl.c @@ -13,6 +13,7 @@ #include #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; diff --git a/libmultipath/checkers/Makefile b/libmultipath/checkers/Makefile index 9559038..87c15bd 100644 --- a/libmultipath/checkers/Makefile +++ b/libmultipath/checkers/Makefile @@ -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: diff --git a/libmultipath/checkers/hp_sw.c b/libmultipath/checkers/hp_sw.c index 6019c9d..cee9aab 100644 --- a/libmultipath/checkers/hp_sw.c +++ b/libmultipath/checkers/hp_sw.c @@ -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'; diff --git a/libmultipath/defaults.h b/libmultipath/defaults.h index c9e3411..2b270ca 100644 --- a/libmultipath/defaults.h +++ b/libmultipath/defaults.h @@ -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 diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c index 607aea8..767d87c 100644 --- a/libmultipath/devmapper.c +++ b/libmultipath/devmapper.c @@ -27,7 +27,6 @@ #include #include -#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) diff --git a/libmultipath/dict.c b/libmultipath/dict.c index 47dc2a3..ea273dd 100644 --- a/libmultipath/dict.c +++ b/libmultipath/dict.c @@ -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) diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 9efcaac..9f2a9c9 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -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'); diff --git a/libmultipath/foreign.h b/libmultipath/foreign.h index 0ade2d7..973f368 100644 --- a/libmultipath/foreign.h +++ b/libmultipath/foreign.h @@ -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) diff --git a/libmultipath/foreign/Makefile b/libmultipath/foreign/Makefile index dfba11e..fe98ddf 100644 --- a/libmultipath/foreign/Makefile +++ b/libmultipath/foreign/Makefile @@ -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: diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index 6ba70c8..fe71d14 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -72,13 +72,13 @@ .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 */ diff --git a/libmultipath/io_err_stat.c b/libmultipath/io_err_stat.c index ac81b4b..02b1453 100644 --- a/libmultipath/io_err_stat.c +++ b/libmultipath/io_err_stat.c @@ -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); diff --git a/libmultipath/memory.c b/libmultipath/memory.c index ff5a030..7514642 100644 --- a/libmultipath/memory.c +++ b/libmultipath/memory.c @@ -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. * */ diff --git a/libmultipath/memory.h b/libmultipath/memory.h index 63f59d8..a3c478e 100644 --- a/libmultipath/memory.h +++ b/libmultipath/memory.h @@ -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)) diff --git a/libmultipath/parser.c b/libmultipath/parser.c index 5caa201..2f9ab6e 100644 --- a/libmultipath/parser.c +++ b/libmultipath/parser.c @@ -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"); diff --git a/libmultipath/parser.h b/libmultipath/parser.h index 0a74750..62906e9 100644 --- a/libmultipath/parser.h +++ b/libmultipath/parser.h @@ -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 diff --git a/libmultipath/prioritizers/Makefile b/libmultipath/prioritizers/Makefile index b3cc944..ab7bc07 100644 --- a/libmultipath/prioritizers/Makefile +++ b/libmultipath/prioritizers/Makefile @@ -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: diff --git a/libmultipath/prioritizers/alua_rtpg.c b/libmultipath/prioritizers/alua_rtpg.c index e9d8328..e431502 100644 --- a/libmultipath/prioritizers/alua_rtpg.c +++ b/libmultipath/prioritizers/alua_rtpg.c @@ -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 " diff --git a/libmultipath/prioritizers/alua_spc3.h b/libmultipath/prioritizers/alua_spc3.h index 13a0924..18b495e 100644 --- a/libmultipath/prioritizers/alua_spc3.h +++ b/libmultipath/prioritizers/alua_spc3.h @@ -14,37 +14,6 @@ */ #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) + \ diff --git a/libmultipath/prioritizers/ontap.c b/libmultipath/prioritizers/ontap.c index ca06d6c..6505033 100644 --- a/libmultipath/prioritizers/ontap.c +++ b/libmultipath/prioritizers/ontap.c @@ -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; } diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c index 685ef33..c6a9e8b 100644 --- a/libmultipath/uevent.c +++ b/libmultipath/uevent.c @@ -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"); } diff --git a/libmultipath/uevent.h b/libmultipath/uevent.h index cb5347e..0aa8675 100644 --- a/libmultipath/uevent.h +++ b/libmultipath/uevent.h @@ -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 index 0000000..14ec8b2 --- /dev/null +++ b/libmultipath/unaligned.h @@ -0,0 +1,38 @@ +#ifndef _UNALIGNED_H_ +#define _UNALIGNED_H_ + +#include + +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_ */ diff --git a/libmultipath/version.h b/libmultipath/version.h index 6b028ee..f25df1c 100644 --- a/libmultipath/version.h +++ b/libmultipath/version.h @@ -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" diff --git a/multipath/main.c b/multipath/main.c index 8732cf8..716203e 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -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(); diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 index ab151e7..c4d0789 100644 --- a/multipath/multipath.conf.5 +++ b/multipath/multipath.conf.5 @@ -67,6 +67,23 @@ recognized keywords for attributes or subsections depend on the section in which they occur. .LP . +\fB\fR and \fB\fR must be on a single line. +\fB\fR is one of the keywords listed in this man page. +\fB\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 diff --git a/multipathd/cli.c b/multipathd/cli.c index f10f862..d5ee4ff 100644 --- a/multipathd/cli.c +++ b/multipathd/cli.c @@ -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. diff --git a/multipathd/main.c b/multipathd/main.c index 327cc19..a03ba20 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -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--; diff --git a/multipathd/uxlsnr.c b/multipathd/uxlsnr.c index 0531061..cdafd82 100644 --- a/multipathd/uxlsnr.c +++ b/multipathd/uxlsnr.c @@ -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; diff --git a/tests/Makefile b/tests/Makefile index f6b5583..81f5518 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -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) diff --git a/tests/globals.c b/tests/globals.c index 96a5651..80f57bd 100644 --- a/tests/globals.c +++ b/tests/globals.c @@ -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 index 0000000..a7e7598 --- /dev/null +++ b/tests/parser.c @@ -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 +#include +#include +#include +#include +#include +// #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; +} diff --git a/tests/uevent.c b/tests/uevent.c index b7d6458..acfcb14 100644 --- a/tests/uevent.c +++ b/tests/uevent.c @@ -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) -- 2.7.4