/usr/share/lintian/checks/control-file is in lintian 2.5.6.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | # control-file -- lintian check script -*- perl -*-
#
# Copyright (C) 2004 Marc Brockschmidt
#
# 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::control_file;
use strict;
use warnings;
use Lintian::Data ();
use Lintian::Relation ();
use Lintian::Tags qw(tag);
use Util;
# The list of libc packages, used for checking for a hard-coded dependency
# rather than using ${shlibs:Depends}.
our @LIBCS = qw(libc6 libc6.1 libc0.1 libc0.3);
my $src_fields = Lintian::Data->new('common/source-fields');
sub run {
my $pkg = shift;
my $type = shift;
my $info = shift;
my $dcontrol = $info->debfiles('control');
if (-l $dcontrol) {
tag 'debian-control-file-is-a-symlink';
}
# check that control is UTF-8 encoded
my $line = file_is_encoded_in_non_utf8($dcontrol, $type, $pkg);
if ($line) {
tag 'debian-control-file-uses-obsolete-national-encoding', "at line $line"
}
# Check that each field is only used once:
my $seen_fields = {};
my $seen_vcs_comment = 0;
open (CONTROL, '<', $dcontrol)
or fail "Couldn't read debfiles/control: $!";
while (<CONTROL>) {
s/\s*\n$//;
if (m,^\# \s* Vcs-(?:Git|Browser): \s* (?:git|http)://git\.debian\.org/(?:\?p=)?collab-maint/<pkg>\.git,ox) {
# Emit it only once per package
tag 'control-file-contains-dh_make-vcs-comment'
unless $seen_vcs_comment++;
next;
}
next if /^\#/;
#Reset seen_fields if we enter a new section:
$seen_fields = {} if $_ eq '';
#line with field:
if (/^(\S+):/) {
my $field = lc ($1);
if ($seen_fields->{$field}) {
tag 'debian-control-with-duplicate-fields', "$field: $$seen_fields{$field}, $.";
}
$seen_fields->{$field} = $.;
if ($field =~ /^xs-vcs-/) {
my $base = $field;
$base =~ s/^xs-//;
tag 'xs-vcs-header-in-debian-control', $field
if $src_fields->known($base);
}
if ($field eq 'xc-package-type') {
tag 'xc-package-type-in-debian-control', "line $.";
}
unless (/^\S+: \S/ || /^\S+:$/) {
tag 'debian-control-has-unusual-field-spacing', "line $.";
}
}
}
close CONTROL;
my ($header, @binary_controls);
eval {
($header, @binary_controls) = read_dpkg_control($dcontrol);
};
if ($@) {
chomp $@;
$@ =~ s/^internal error: //;
$@ =~ s/^syntax error in //;
tag 'syntax-error-in-control-file', "debian/control: $@";
return;
}
for my $binary_control (@binary_controls) {
tag 'build-info-in-binary-control-file-section', 'Package '.$binary_control->{'package'}
if ($binary_control->{'build-depends'} || $binary_control->{'build-depends-indep'} ||
$binary_control->{'build-conflicts'} || $binary_control->{'build-conflicts-indep'});
for my $field (keys %$binary_control) {
tag 'binary-control-field-duplicates-source', "field \"$field\" in package ".$binary_control->{'package'},
if ($header->{$field} && $binary_control->{$field} eq $header->{$field});
}
}
# Check that fields which should be comma-separated or pipe-separated have
# separators. Places where this tends to cause problems are with wrapped
# lines such as:
#
# Depends: foo, bar
# baz
#
# or with substvars. If two substvars aren't separated by a comma, but at
# least one of them expands to an empty string, there will be a lurking bug.
# The result will be syntactically correct, but as soon as both expand into
# something non-empty, there will be a syntax error.
#
# The architecture list can contain things that look like packages separated
# by spaces, so we have to remove any architecture restrictions first. This
# unfortunately distorts our report a little, but hopefully not too much.
#
# Also check for < and > relations. dpkg-gencontrol warns about them and then
# transforms them in the output to <= and >=, but it's easy to miss the error
# message. Similarly, check for duplicates, which dpkg-source eliminates.
for my $control ($header, @binary_controls) {
for my $field (qw(pre-depends depends recommends suggests breaks
conflicts provides replaces enhances
build-depends build-depends-indep
build-conflicts build-conflicts-indep)) {
next unless $control->{$field};
my $relation = Lintian::Relation->new($control->{$field});
my @dups = $relation->duplicates;
for my $dup (@dups) {
tag 'duplicate-in-relation-field', 'in',
($control->{source} ? 'source' : $control->{package}),
"$field:", join(', ', @$dup);
}
my $value = $control->{$field};
$value =~ s/\n(\s)/$1/g;
$value =~ s/\[[^\]]*\]//g;
if ($value =~ /(?:^|\s)
(
(?:\w[^\s,|\$\(]+|\$\{\S+:Depends\})\s*
(?:\([^\)]*\)\s*)?
)
\s+
(
(?:\w[^\s,|\$\(]+|\$\{\S+:Depends\})\s*
(?:\([^\)]*\)\s*)?
)/x) {
my ($prev, $next) = ($1, $2);
for ($prev, $next) {
s/\s+$//;
}
tag 'missing-separator-between-items', 'in',
($control->{source} ? 'source' : $control->{package}),
"$field field between '$prev' and '$next'";
}
while ($value =~ /([^\s\(]+\s*\([<>]\s*[^<>=]+\))/g) {
tag 'obsolete-relation-form-in-source', 'in',
($control->{source} ? 'source' : $control->{package}),
"$field: $1";
}
}
}
# Make sure that a stronger dependency field doesn't imply any of the elements
# of a weaker dependency field. dpkg-gencontrol will fix this up for us, but
# we want to check the source package since dpkg-gencontrol may silently "fix"
# something that's a more subtle bug.
#
# Also check if a package declares a simple dependency on itself, since
# similarly dpkg-gencontrol will clean this up for us but it may be a sign of
# another problem, and check that the package doesn't hard-code a dependency
# on libc. We have to do the latter check here rather than in checks/fields
# to distinguish from dependencies created by ${shlibs:Depends}.
#
# Use this traversal to build a list of package names built from this source
# package, which we'll use later to check for dependencies in -dev packages.
my @dep_fields = qw(pre-depends depends recommends suggests);
my $libcs = Lintian::Relation->new(join(' | ', @LIBCS));
my @package_names;
for my $control (@binary_controls) {
push (@package_names, $control->{package});
for my $strong (0 .. $#dep_fields) {
next unless $control->{$dep_fields[$strong]};
my $relation = Lintian::Relation->new($control->{$dep_fields[$strong]});
tag 'package-depends-on-itself', $control->{package}, $dep_fields[$strong]
if $relation->implies($control->{package});
tag 'package-depends-on-hardcoded-libc', $control->{package}, $dep_fields[$strong]
if ($relation->implies($libcs) and $pkg !~ /^e?glibc$/);
for my $weak (($strong + 1) .. $#dep_fields) {
next unless $control->{$dep_fields[$weak]};
for my $dependency (split /\s*,\s*/, $control->{$dep_fields[$weak]}) {
next unless $dependency;
tag 'stronger-dependency-implies-weaker', $control->{package}, "$dep_fields[$strong] -> $dep_fields[$weak]", $dependency
if $relation->implies($dependency);
}
}
}
}
# Check that every package is in the same archive area, except that
# sources in main can deliver both main and contrib packages. The source
# package may or may not have a section specified; if it doesn't, derive the
# expected archive area from the first binary package by leaving $area
# undefined until parsing the first binary section. Missing sections will be
# caught by other checks.
#
# Check any package that looks like a library -dev package for a dependency on
# a shared library package built from the same source. If found, such a
# dependency should have a tight version dependency on that package.
#
# Also accumulate short and long descriptions for each package so that we can
# check for duplication, but skip udeb packages. Ideally, we should check the
# udeb package descriptions separately for duplication, but udeb packages
# should be able to duplicate the descriptions of non-udeb packages and the
# package description for udebs is much less important or significant to the
# user.
my $area;
if ($header->{'section'}) {
if ($header->{'section'} =~ m%^([^/]+)/%) {
$area = $1;
} else {
$area = '';
}
} else {
tag 'no-section-field-for-source';
}
my @descriptions;
for my $binary_control (@binary_controls) {
my $package = $binary_control->{'package'};
# Accumulate the description.
my $desc = $binary_control->{'description'};
if ($desc and (not $binary_control->{'xc-package-type'}
or $binary_control->{'xc-package-type'} ne 'udeb')) {
push(@descriptions, [ $package, split("\n", $desc, 2) ]);
}
# If this looks like a -dev package, check its dependencies.
if ($package =~ /-dev$/ and $binary_control->{'depends'}) {
check_dev_depends ($info, $package, $binary_control->{depends},
@package_names);
}
# Check mismatches in archive area.
next unless $binary_control->{'section'};
if (!defined ($area)) {
if ($binary_control->{'section'} =~ m%^([^/]+)/%) {
$area = ($1 eq 'contrib') ? '' : $1;
} else {
$area = '';
}
next;
}
tag 'section-area-mismatch', 'Package ' . $package
if ($area && $binary_control->{'section'} !~ m%^$area/%);
tag 'section-area-mismatch', 'Package ' . $package
if (!$area && $binary_control->{'section'} =~ m%^([^/]+)/% && $1 ne 'contrib');
}
# Check for duplicate descriptions.
my (%seen_short, %seen_long);
for my $i (0 .. $#descriptions) {
my (@short, @long);
for my $j (($i + 1) .. $#descriptions) {
if ($descriptions[$i][1] eq $descriptions[$j][1]) {
my $package = $descriptions[$j][0];
push(@short, $package) unless $seen_short{$package};
}
next unless ($descriptions[$i][2] and $descriptions[$j][2]);
if ($descriptions[$i][2] eq $descriptions[$j][2]) {
my $package = $descriptions[$j][0];
push(@long, $package) unless $seen_long{$package};
}
}
if (@short) {
tag 'duplicate-short-description', $descriptions[$i][0], @short;
for (@short) { $seen_short{$_} = 1 }
}
if (@long) {
tag 'duplicate-long-description', $descriptions[$i][0], @long;
for (@long) { $seen_long{$_} = 1 }
}
}
}
# Check the dependencies of a -dev package. Any dependency on one of the
# packages in @package_names that looks like the underlying library needs to
# have a version restriction that's at least as strict as the same upstream
# version.
sub check_dev_depends {
my ($info, $package, $depends, @packages) = @_;
$depends =~ s/^\s+//;
$depends =~ s/\s+$//;
for my $target (@packages) {
next unless ($target =~ /^lib[\w.+-]+\d/
and $target !~ /-(?:dev|docs?|common)$/);
my @depends = grep { /(?:^|[\s|])\Q$target\E(?:[\s|\(]|\z)/ }
split (/\s*,\s*/, $depends);
# If there are any alternatives here, something special is
# going on. Assume that the maintainer knows what they're
# doing. Otherwise, separate out just the versions.
next if grep { /\|/ } @depends;
my @versions = sort map {
if (/^[\w.+-]+(?:\s*\(([^\)]+)\))/) {
$1;
} else {
'';
}
} @depends;
# If there's only one mention of this package, the dependency
# should be tight. Otherwise, there should be both >>/>= and
# <</<= dependencies that mention the source, binary, or
# upstream version. If there are more than three mentions of
# the package, again something is weird going on, so we assume
# they know what they're doing.
if (@depends == 1) {
unless ($versions[0] =~ /^\s*=\s*\$\{(?:binary:Version|Source-Version)\}/) {
# Allow "pkg (= ${source:Version})" if (but only if)
# the target is an arch:all package. This happens
# with a lot of mono-packages.
#
# Note, we do not check if the -dev package is
# arch:all as well. The version-substvars check
# handles that for us.
next if ($info->binary_field ($target, 'architecture')//'') eq 'all'
&& $versions[0] =~ /^\s*=\s*\$\{source:Version\}/;
tag 'weak-library-dev-dependency', "$package on $depends[0]";
}
} elsif (@depends == 2) {
unless ($versions[0] =~ /^\s*<[=<]\s*\$\{(?:(?:binary|source):(?:Upstream-)?Version|Source-Version)\}/
&& $versions[1] =~ /^\s*>[=>]\s*\$\{(?:(?:binary|source):(?:Upstream-)?Version|Source-Version)\}/) {
tag 'weak-library-dev-dependency', "$package on $depends[0], $depends[1]";
}
}
}
}
1;
# Local Variables:
# indent-tabs-mode: nil
# cperl-indent-level: 4
# End:
# vim: syntax=perl sw=4 sts=4 sr et
|