X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=nokia-lintian%2Fchecks%2Fmenus;fp=nokia-lintian%2Fchecks%2Fmenus;h=0000000000000000000000000000000000000000;hb=bf47c4c43f1f5f4986e85b74fc82b32048aeb846;hp=6674d33e2c2bdbef1944095102f84a877e183941;hpb=19fdce4b743853cee27edb892096cf64295c2874;p=maemian diff --git a/nokia-lintian/checks/menus b/nokia-lintian/checks/menus deleted file mode 100644 index 6674d33..0000000 --- a/nokia-lintian/checks/menus +++ /dev/null @@ -1,688 +0,0 @@ -# menus -- lintian check script -*- perl -*- - -# somewhat of a misnomer -- it doesn't only check menus - -# Copyright (C) 1998 Christian Schwarz -# -# 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, you can find it on the World Wide -# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free -# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, -# MA 02110-1301, USA. - -package Lintian::menus; -use strict; -use lib "$ENV{'LINTIAN_ROOT'}/checks/"; -use common_data; - -use Lintian::Data; -use Spelling; -use Tags; -use Util; - -my $pkg; -my %all_files = (); -my %all_links = (); - -# Known fields for doc-base files. The value is 1 for required fields and 0 -# for optional fields. -my %known_docbase_main_fields = ( - 'document' => 1, - 'title' => 1, - 'section' => 1, - 'abstract' => 0, - 'author' => 0 -); -my %known_docbase_format_fields = ( - 'format' => 1, - 'files' => 1, - 'index' => 0 -); - -sub run { - -$pkg = shift; -my $type = shift; - -my %preinst; -my %postinst; -my %prerm; -my %postrm; - -my $docbase_file; -my $menu_file; -my $menumethod_file; -my $anymenu_file; - -# check preinst script -if ( -f "control/preinst" ) { - # parse script... - check_script("preinst",\%preinst); -} - -# check postinst script -if ( -f "control/postinst" ) { - # parse script... - check_script("postinst",\%postinst); -} - -# check prerm script -if ( -f "control/prerm" ) { - # parse script... - check_script("prerm",\%prerm); -} - -# check postrm script -if ( -f "control/postrm" ) { - # parse script... - check_script("postrm",\%postrm); -} - -# read package contents -open(IN, '<', "index") or fail("cannot open index file index: $!"); -while () { - chomp; - my ($perm,$owner,$size,$date,$time,$file) = split(' ', $_, 6); - $file =~ s,^(\./),,; - add_file_link_info ($file); - $file =~ s/ link to .*//; - $file =~ s/ -> .*//; - - my $operm = perm2oct($perm); - - if ($perm =~ m,^-,o) { # file checks - # menu file? - if ($file =~ m,^usr/(lib|share)/menu/\S,o) { # correct permissions? - if ($perm =~ m,x,o) { - tag "executable-menu-file", sprintf("$file %04o",$operm); - } - - next if $file =~ m,^usr/(lib|share)/menu/README$,; - - if ($file =~ m,^usr/lib/,o) { - tag "menu-file-in-usr-lib", $file; - } - - $menu_file = $file; - - if ($file =~ m,usr/(lib|share)/menu/menu$,o and $pkg ne 'menu') { - tag "bad-menu-file-name", $file; - } - } - # doc-base file? - elsif ($file =~ m,^usr/share/doc-base/\S,o) { # correct permissions? - if ($perm =~ m,x,o) { - tag "executable-in-usr-share-docbase", $file, sprintf("%04o",$operm); - } - $docbase_file = $file; - } - #menu-methods file? - elsif ( $file =~ m,^etc/menu-methods/\S,o ) { - #TODO: we should test if the menu-methods file - # is made executable in the postinst as recommended by - # the menu manual - - my $menumethod_includes_menu_h = 0; - $menumethod_file = $file; - - open(MM, '<', "unpacked/$file") or fail("cannot open menu-method file $file: $!"); - while () { - chomp; - if (m,^!include menu.h,o) { - $menumethod_includes_menu_h = 1; - last; - } - } - close MM; - tag "menu-method-should-include-menu-h", "$file" - unless $menumethod_includes_menu_h or $pkg eq 'menu'; - } - } -} -close IN; - -# prerm scripts should not call update-menus -if ($prerm{'calls-updatemenus'}) { - tag "prerm-calls-updatemenus", ""; -} - -# postrm scripts should not call install-docs -if ($postrm{'calls-installdocs'} or $postrm{'calls-installdocs-r'}) { - tag "postrm-calls-installdocs", ""; -} - -# preinst scripts should not call either update-menus nor installdocs -if ($preinst{'calls-updatemenus'}) { - tag "preinst-calls-updatemenus", ""; -} - -if ($preinst{'calls-installdocs'}) { - tag "preinst-calls-installdocs", ""; -} - -# don't set the /usr/doc link, the FHS transition is over (2002-10-08) -if (defined $postinst{'sets-link'} && $postinst{'sets-link'} == 1) { - tag "postinst-should-not-set-usr-doc-link", ""; -} - -$anymenu_file = $menu_file || $menumethod_file; - -# check consistency -# docbase file? -if ($docbase_file) { # postinst has to call install-docs - if (not $postinst{'calls-installdocs'}) { - tag "postinst-does-not-call-installdocs", "$docbase_file"; - } - # prerm has to call install-docs -r - if (not $prerm{'calls-installdocs-r'}) { - tag "prerm-does-not-call-installdocs", "$docbase_file"; - } - - # check the contents of the doc-base file(s) - opendir DOCBASEDIR, "doc-base" or fail("cannot read doc-base directory."); - my $dbfile; - while (defined ($dbfile = readdir DOCBASEDIR)) { - # don't try to parse executables, plus we already warned about it - next if -x "doc-base/$dbfile"; - check_doc_base_file($dbfile, $pkg, $type); - } - closedir DOCBASEDIR; -} else { - # postinst and postrm should not need to call install-docs - if ($postinst{'calls-installdocs'} or $postinst{'calls-installdocs-r'}) { - tag "postinst-has-useless-call-to-install-docs", ""; - } - if ($prerm{'calls-installdocs'} or $prerm{'calls-installdocs-r'}) { - tag "prerm-has-useless-call-to-install-docs", ""; - } -} - -if ($anymenu_file) { - # postinst has to call update-menus - if (not $postinst{'calls-updatemenus'}) { - tag "postinst-does-not-call-updatemenus", "$anymenu_file"; - } - # postrm has to call update-menus - if (not $postrm{'calls-updatemenus'}) { - tag "postrm-does-not-call-updatemenus", "$anymenu_file" unless $pkg eq 'menu'; - } -} else { - # postinst and postrm should not need to call update-menus - if ($postinst{'calls-updatemenus'}) { - tag "postinst-has-useless-call-to-update-menus", ""; - } - if ($postrm{'calls-updatemenus'}) { - tag "postrm-has-useless-call-to-update-menus", ""; - } -} - -} - -# ----------------------------------- - -sub check_doc_base_file { - my ($dbfile, $pkg, $type) = @_; - - my $line = file_is_encoded_in_non_utf8("doc-base/$dbfile", $type, $pkg); - if ($line) { - tag 'doc-base-file-uses-obsolete-national-encoding', "$dbfile:$line"; - } - - open (IN, '<', "doc-base/$dbfile") - or fail("cannot open doc-base file $dbfile for reading."); - - my (@files, $field, @vals); - my $knownfields = \%known_docbase_main_fields; - $line = 0; # global - my %sawfields = (); # local for each section of control file - my %sawformats = (); # global for control file - - while () { - chomp; - - # New field. check previous field, if we have any. - if (/^(\S+)\s*:\s*(.*)$/) { - my (@new) = ($1, $2); - if ($field) { - check_doc_base_field($dbfile, $line, $field, \@vals, - \%sawfields, \%sawformats, $knownfields); - } - $field = lc $new[0]; - @vals = ($new[1]); - $line = $.; - - # Continuation of previously defined field. - } elsif ($field && /^\s+\S/) { - push (@vals, $_); - - # All tags will be reported on the last continuation line of the - # doc-base field. - $line = $.; - - # Sections' separator. - } elsif (/^(\s*)$/) { - tag "doc-base-file-separator-extra-whitespaces", "$dbfile:$." - if $1; - next unless $field; # skip successive empty lines - - # Check previously defined field and section. - check_doc_base_field($dbfile, $line, $field, \@vals, \%sawfields, - \%sawformats, $knownfields); - check_doc_base_file_section($dbfile, $line + 1, \%sawfields, - \%sawformats, $knownfields); - - # Intialize variables for new section. - undef $field; - undef $line; - @vals = (); - %sawfields = (); - - # Each section except the first one is format section. - $knownfields = \%known_docbase_format_fields; - - # Everything else is a syntax error. - } else { - tag "doc-base-file-syntax-error", "$dbfile:$."; - } - } - - # Check the last field/section of the control file. - if ($field) { - check_doc_base_field($dbfile, $line, $field, \@vals, \%sawfields, - \%sawformats, $knownfields); - check_doc_base_file_section($dbfile, $line, \%sawfields, \%sawformats, - $knownfields); - } - - # Make sure we saw at least one format. - tag "doc-base-file-no-format-section", "$dbfile:$." unless %sawformats; - - close IN; -} - -# Checks one field of a doc-base control file. $vals is array ref containing -# all lines of the field. Modifies $sawfields and $sawformats. -sub check_doc_base_field { - my ($dbfile, $line, $field, $vals, $sawfields, $sawformats, - $knownfields) = @_; - - tag "doc-base-file-unknown-field", "$dbfile:$line", "$field" - unless defined $knownfields->{$field}; - tag "doc-base-file-duplicated-field", "$dbfile:$line", "$field" - if $sawfields->{$field}; - $sawfields->{$field} = 1; - - # Index/Files field. - # - # Check if files referenced by doc-base are included in the package. The - # Index field should refer to only one file without wildcards. The Files - # field is a whitespace-separated list of files and may contain wildcards. - # We skip without validating wildcard patterns containing character - # classes since otherwise we'd need to deal with wildcards inside - # character classes and aren't there yet. - if ($field eq 'index' or $field eq 'files') { - my @files = map { split ('\s+', $_) } @$vals; - - if ($field eq 'index' && @files > 1) { - tag "doc-base-index-references-multiple-files", "$dbfile:$line"; - } - for my $file (@files) { - if ($file =~ m%^/usr/doc%) { - tag "doc-base-file-references-usr-doc", "$dbfile:$line"; - } - my $realfile = delink ($file); - - # openoffice.org-dev-doc has thousands of files listed so try to - # use the hash if possible. - my $found; - if ($realfile =~ /[*?]/) { - my $regex = quotemeta ($realfile); - unless ($field eq 'index') { - next if $regex =~ /\[/; - $regex =~ s%\\\*%[^/]*%g; - $regex =~ s%\\\?%[^/]%g; - $regex .= '/?'; - } - $found = grep { /^$regex\z/ } keys %all_files; - } else { - $found = $all_files{$realfile} || $all_files{"$realfile/"}; - } - unless ($found) { - tag "doc-base-file-references-missing-file", "$dbfile:$line", - $file; - } - } - undef @files; - - # Format field. - } elsif ($field eq 'format') { - my $format = join (' ', @$vals); - $format =~ s/^\s+//o; - $format =~ s/\s+$//o; - $format = lc $format; - tag "doc-base-file-unknown-format", "$dbfile:$line", $format - unless $known_doc_base_formats{$format}; - tag "doc-base-file-duplicated-format", "$dbfile:$line", $format - if $sawformats->{$format}; - $sawformats->{$format} = 1; - - # Save the current format for the later section check. - $sawformats->{' *current* '} = $format; - - # Document field. - } elsif ($field eq 'document') { - $_ = join (' ', @$vals); - - tag "doc-base-invalid-document-field", "$dbfile:$line", "$_" - unless /^[a-z0-9+.-]+$/; - tag "doc-base-document-field-ends-in-whitespace", "$dbfile:$line" - if /[ \t]$/; - tag "doc-base-document-field-not-in-first-line", "$dbfile:$line" - unless $line == 1; - - # Title field. - } elsif ($field eq 'title') { - if (@$vals) { - spelling_check("spelling-error-in-doc-base-title-field", - join (' ', @$vals), "$dbfile:$line"); - spelling_check_picky("spelling-error-in-doc-base-title-field", - join (' ', @$vals), "$dbfile:$line"); - } - - # Section field. - } elsif ($field eq 'section') { - my $sections = Lintian::Data->new('doc-base/sections'); - $_ = join (' ', @$vals); - tag "doc-base-unknown-section", "$dbfile:$line", $_ - unless $sections->known($_); - - # Abstract field. - } elsif ($field eq 'abstract') { - # The three following variables are used for checking if the field is - # correctly phrased. We detect if each line (except for the first - # line and lines containing single dot) of the field starts with the - # same number of spaces, not followed by the same non-space character, - # and the number of spaces is > 1. - # - # We try to match fields like this: - # ||Abstract: The Boost web site provides free peer-reviewed portable - # || C++ source libraries. The emphasis is on libraries which work - # || well with the C++ Standard Library. One goal is to establish - # - # but not like this: - # ||Abstract: This is "Ding" - # || * a dictionary lookup program for Unix, - # || * DIctionary Nice Grep, - my $leadsp = undef; # string with leading spaces from second line - my $charafter = undef; # first non-whitespace char of second line - my $leadsp_ok = 1; # are spaces OK? - - # Intentionally skipping the first line. - for my $idx (1 .. $#{$vals}) { - $_ = $vals->[$idx]; - if (/manage\s+online\s+manuals\s.*Debian/o) { - tag "doc-base-abstract-field-is-template", "$dbfile:$line" - unless $pkg eq "doc-base"; - } elsif (/^(\s+)\.(\s*)$/o and ($1 ne " " or $2)) { - tag "doc-base-abstract-field-separator-extra-whitespaces", - "$dbfile:" . ($line - $#{$vals} + $idx); - } elsif (!$leadsp && /^(\s+)(\S)/o) { - # The regexp should always match. - ($leadsp, $charafter) = ($1, $2); - $leadsp_ok = $leadsp eq " "; - } elsif (!$leadsp_ok && /^(\s+)(\S)/o) { - # The regexp should always match. - undef $charafter if $charafter && $charafter ne $2; - $leadsp_ok = 1 - if ($1 ne $leadsp) || ($1 eq $leadsp && $charafter); - } - } - unless ($leadsp_ok) { - tag "doc-base-abstract-might-contain-extra-leading-whitespaces", - "$dbfile:$line"; - } - - # Check spelling. - if (@$vals) { - spelling_check("spelling-error-in-doc-base-abstract-field", - join (' ', @$vals), "$dbfile:$line"); - spelling_check_picky("spelling-error-in-doc-base-abstract-field", - join (' ', @$vals), "$dbfile:$line"); - } - } -} - -# Checks the section of the doc-base control file. Tries to find required -# fields missing in the section. -sub check_doc_base_file_section { - my ($dbfile, $line, $sawfields, $sawformats, $knownfields) = @_; - - tag "doc-base-file-no-format", "$dbfile:$line" - if ((defined $sawfields->{'files'} || defined $sawfields->{'index'}) - && !(defined $sawfields->{'format'})); - - # The current format is set by check_doc_base_field. - if ($sawfields->{'format'}) { - my $format = $sawformats->{' *current* '}; - tag "doc-base-file-no-index", "$dbfile:$line" - if ($format && ($format eq 'html' || $format eq 'info') - && !$sawfields->{'index'}); - } - for my $field (sort keys %$knownfields) { - tag "doc-base-file-lacks-required-field", "$dbfile:$line", "$field" - if ($knownfields->{$field} == 1 && !$sawfields->{$field}); - } -} - -# Add file and link to %all_files and %all_links. Note that both files and -# links have to include a leading /. -sub add_file_link_info { - my $file = shift; - my $link = undef; - - $file = "/" . $file if (not $file =~ m%^/%); # make file absolute - $file =~ s%/+%/%g; # remove duplicated `/' - my $ishard = ($file =~ / link to /); - ($file, $link) = split(/ (?:->|link to) /, $file); - - $all_files{$file} = 1; - - if (defined $link) { - if ($ishard) { - $link =~ s,^\./,/,; - } elsif (not $link =~ m,^/,) { # not absolute link - $link = "/" . $link; # make sure link starts with '/' - $link =~ s,/+\./+,/,g; # remove all /./ parts - my $dcount = 1; - while ($link =~ s,^/+\.\./+,/,) { #\ count & remove - $dcount++; #/ any leading /../ parts - } - my $f = $file; - while ($dcount--) { #\ remove last $dcount - $f =~ s,/[^/]*$,,; #/ path components from $file - } - $link = $f . $link; # now we should have absolute link - } - $all_links{$file} = $link unless ($link eq $file); - } -} - - -# Dereference all symlinks in file. Uses %all_links. -sub delink { - my $file = shift; - - $file =~ s%/+%/%g; # remove duplicated '/' - return $file unless %all_links; # package doesn't symlinks - - my $p1 = ""; - my $p2 = $file; - my %used_links = (); - - # In the loop below we split $file into two parts on each '/' until - # there's no remaining slashes. We try substituting the first part with - # corresponding symlink and if it succeedes, we start the procedure from - # beginning. - # - # Example: - # Let $all_links{"/a/b"} == "/d", and $file == "/a/b/c" - # Then 0) $p1 == "", $p2 == "/a/b/c" - # 1) $p1 == "/a", $p2 == "/b/c" - # 2) $p1 == "/a/b", $p2 == "/c" ; substitute "/d" for "/a/b" - # 3) $p1 == "", $p2 == "/d/c" - # 4) $p1 == "/d", $p2 == "/c" - # 5) $p1 == "/d/c", $p2 == "" - # - # Note that the algorithm supposes, that - # i) $all_links{$X} != $X for each $X - # ii) both keys and values of %all_links start with '/' - - while (($p2 =~ s%^(/[^/]*)%%g) > 0) { - $p1 .= $1; - if (defined $all_links{$p1}) { - return '!!! SYMLINK LOOP !!!' if defined $used_links{$p1}; - $p2 = $all_links{$p1} . $p2; - $p1 = ""; - $used_links{$p1} = 1; - } - } - - # After the loop $p2 should be empty and $p1 should contain the target - # file. In some rare cases when $file contains no slashes, $p1 will be - # empty and $p2 will contain the result (which will be equal to $file). - return $p1 ne "" ? $p1 : $p2; -} - -sub check_script { - my ($script,$pres) = @_; - my ($no_check_menu,$no_check_installdocs,$no_check_wmmenu,$calls_wmmenu); - my $interp; - - open(IN, '<', "control/$script") or - fail("cannot open maintainer script control/$script for reading: $!"); - $interp = ; - $interp = '' unless defined $interp; - if ($interp =~ m,^\#\!\s*/bin/(a|ba|k|pdk)?sh,) { - $interp = 'sh'; - } elsif ($interp =~ m,^\#\!\s*/usr/bin/perl,) { - $interp = 'perl'; - } else { - if ($interp =~ m,^\#\!\s*(.+),) { - $interp = $1; - } - else { # hmm, doesn't seem to start with #! - # is it a binary? look for ELF header - if ($interp =~ m/^\177ELF/) { - return; # nothing to do here - } - $interp = 'unknown'; - } - } - - while () { - # skip comments - s/\#.*$//o; - - ## - # either update-menus or wm-menu-config will satisfy - # the checks that the menu file installed is properly used - ## - - # does the script check whether update-menus exists? - if (/-x\s+\S*update-menus/o or /(which|command)(\s+\S+)?\s+update-menus/o) { - # yes, it does. - $pres->{'checks-for-updatemenus'} = 1; - } - - # does the script call update-menus? - # TODO this regex-magic should be moved to some lib for checking - # whether a certain word is likely called as command... --Jeroen - if (/(?:^\s*|[;&|]\s*|(?:then|do)\s+)(?:\/usr\/bin\/)?update-menus(?:\s|[;&|<>]|$)/) { - # yes, it does. - $pres->{'calls-updatemenus'} = 1; - - # checked first? - if (not $pres->{'checks-for-updatemenus'} and $pkg ne 'menu') { - tag "maintainer-script-does-not-check-for-existence-of-updatemenus", "$script:$." unless $no_check_menu++; - } - } - - # does the script check whether wm-menu-config exists? - if (s/-x\s+\S*wm-menu-config//o or /which\s+wm-menu-config/o - or s/command\s+.*?wm-menu-config//o) { - # yes, it does. - $pres->{'checks-for-wmmenuconfig'} = 1; - } - - # does the script call wm-menu-config? - if (m/(?:^\s*|[;&|]\s*|(?:then|do)\s+)(?:\/usr\/sbin\/)?wm-menu-config(?:\s|[;&|<>]|$)/) { - # yes, it does. - $pres->{'calls-wmmenuconfig'} = 1; - tag "maintainer-script-calls-deprecated-wm-menu-config", "$script:$." unless $calls_wmmenu++; - - # checked first? - if (not $pres->{'checks-for-wmmenuconfig'} and $pkg ne 'menu') { - tag "maintainer-script-does-not-check-for-existence-of-wm-menu-config", "$script:$." unless $no_check_wmmenu++; - } - } - - # does the script set a link in /usr/doc? - # does the script remove a link in /usr/doc? - if ($interp eq 'sh') { - if (m,ln\s+(-\w+)?\s+\"?\.\./share/doc/\S+, ) { - $pres->{'sets-link'} = 1; - } - if (m,rm\s+(-\w+\s+)?\"?/usr/doc/\S+, ) { - $pres->{'removes-link'} = 1; - } - } elsif ($interp eq 'perl') { - if (m|symlink\s*\(?\s*[\"\']\.\./share/doc/\.+?[\"\']\s*,|) { - $pres->{'sets-link'} = 1; - } elsif (m,ln\s+(-\w+)?\s+\"?\.\./share/doc/\S+, ) { - $pres->{'sets-link'} = 1; - } - } else { - # just fall through for now - } - - # does the script check whether install-docs exists? - if (s/-x\s+\S*install-docs//o or /which\s+install-docs/o - or s/command\s+.*?install-docs//o) { - # yes, it does. - $pres->{'checks-for-installdocs'} = 1; - } - - # does the script call install-docs? - if (m/(?:^\s*|[;&|]\s*|(?:then|do)\s+)(?:\/usr\/sbin\/)?install-docs(?:\s|[;&|<>]|$)/) { - # yes, it does. Does it remove or add a doc? - if (m/install-docs\s+(-r|--remove)\s/) { - $pres->{'calls-installdocs-r'} = 1; - } else { - $pres->{'calls-installdocs'} = 1; - } - # checked first? - if (not $pres->{'checks-for-installdocs'}) { - tag "maintainer-script-does-not-check-for-existence-of-installdocs", "$script" unless $no_check_installdocs++; - } - } - } - close IN; -} - -1; - -# Local Variables: -# indent-tabs-mode: t -# cperl-indent-level: 4 -# End: -# vim: syntax=perl