1 # debconf -- lintian check script -*- perl -*-
3 # Copyright (C) 2001 Colin Watson
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, you can find it on the World Wide
17 # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
18 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 package Lintian::debconf;
33 # From debconf-devel(7), section 'THE TEMPLATES FILE', up to date with debconf
34 # version 1.3.22. Added indices for cdebconf (indicates sort order for
35 # choices); debconf doesn't support it, but it ignores it, which is safe
38 map { $template_fields{$_}=1 }
39 qw(template type choices indices default description);
41 # From debconf-devel(7), section 'THE TEMPLATES FILE', up to date with debconf
44 map { $valid_types{$_}=1 } qw(
56 # From debconf-devel(7), section 'THE DEBCONF PROTOCOL' under 'INPUT', up to
57 # date with debconf version 1.5.3.
58 my %valid_priorities = map { $_ => 1 }
59 qw(low medium high critical);
61 # All the packages that provide debconf functionality. Anything using debconf
62 # needs to have dependencies that satisfy one of these.
63 my @debconfs = qw(debconf debconf-2.0 cdebconf cdebconf-udeb libdebconfclient0
64 libdebconfclient0-udeb);
69 my $usesmultiselect='';
71 if ($type eq 'source') {
72 open(BINARY, '<', "fields/binary") or fail("Can't open fields/binary: $!");
73 my $binaries = <BINARY>;
76 my @files = map { "$_.templates" } split /,\s+/, $binaries;
77 push @files, "templates";
79 foreach my $file (@files) {
80 my $templates_file = "debfiles/$file";
82 $binary =~ s/\.?templates$//;
83 # Single binary package (so @files contains "templates" and
84 # "binary.templates")?
85 if (!$binary and $#files == 1) {
89 if (-f $templates_file) {
90 my @templates = read_dpkg_control($templates_file, "templates file");
92 foreach my $template (@templates) {
93 if (exists $template->{template} and exists $template->{_choices}) {
94 tag "template-uses-unsplit-choices",
95 "$binary - $template->{template}";
101 # The remainder of the checks are for binary packages, so we exit now
105 if (open(PREINST, '<', "control/preinst")) {
107 s/#.*//; # Not perfect for Perl, but should be OK
108 if (m,/usr/share/debconf/confmodule, or
109 m/(?:Debconf|Debian::DebConf)::Client::ConfModule/) {
117 if (-f "control/config") {
120 if (-f "control/templates") {
124 # This still misses packages that use debconf only in the postrm. Packages
125 # that ask debconf questions in the postrm should load the confmodule in the
126 # postinst so that debconf can register their templates.
127 return unless $seenconfig or $seentemplates or $usespreinst;
129 # parse depends info for later checks
131 # Consider every package to depend on itself.
133 if (-f "fields/version") {
134 open(IN, '<', "fields/version") or fail("Can't open fields/version: $!");
136 $version = "$pkg (= $_)";
140 my (%dependencies, @alldeps);
142 for my $field (qw(depends pre-depends)) {
143 if (-f "fields/$field") {
144 open(IN, '<', "fields/$field") or fail("Can't open fields/$field: $!");
147 $_ .= ", $version" if defined $version;
149 $dependencies{$field} = Dep::parse($_);
153 $dependencies{$field} = Dep::parse($dep);
157 my $alldependencies = Dep::parse(join ', ', @alldeps);
159 # See if the package depends on dbconfig-common. Packages that do are allowed
160 # to have a config file with no templates, since they use the dbconfig-common
162 my $usesdbconfig = Dep::implies($alldependencies, Dep::parse('dbconfig-common'));
164 # Check that both debconf control area files are present.
165 if ($seenconfig and not $seentemplates and not $usesdbconfig) {
166 tag "no-debconf-templates", "";
167 } elsif ($seentemplates and not $seenconfig and not $usespreinst and $type ne 'udeb') {
168 tag "no-debconf-config", "";
171 if ($seenconfig and not -x "control/config") {
172 tag "debconf-config-not-executable", "";
175 # First check that templates look valid
176 if ($seentemplates) {
177 open(TMPL, '<', "control/templates")
178 or fail("Can't open control/templates: $!");
183 my $name = 'unknown';
185 foreach my $line (split "\n", $_) {
186 if ($line =~ s/^([-_.A-Za-z0-9]+):\s*(.+)//) {
188 $name = $2 if ($1 eq 'Template');
192 foreach (keys %fields) {
193 if ($fields{$_} > 1) {
194 tag "duplicate-fields-in-templates", "$name $_";
195 # Templates file is corrupted, no need to report
204 # Lots of template checks.
206 my @templates = $seentemplates ? read_dpkg_control("control/templates", "templates file") : ();
207 my %potential_db_abuse;
210 foreach my $template (@templates) {
213 if (not exists $template->{template}) {
214 tag "no-template-name", "";
215 $template->{template} = 'no-template-name';
217 push @templates_seen, $template->{template};
218 if ($template->{template}!~m|[A-Za-z0-9.+-](?:/[A-Za-z0-9.+-])|) {
219 tag "malformed-template-name", "$template->{template}";
223 if (not exists $template->{type}) {
224 tag "no-template-type", "$template->{template}";
225 } elsif (not $valid_types{$template->{type}}) {
226 tag "unknown-template-type", "$template->{type}";
227 } elsif ($template->{type} eq 'select') {
229 } elsif ($template->{type} eq 'multiselect') {
232 } elsif ($template->{type} eq 'error') {
233 unless (Dep::implies($alldependencies, Dep::parse('debconf (>= 1.4.69) | cdebconf'))) {
234 tag "debconf-error-requires-versioned-depends", "$template->{template}"
235 unless $type eq 'udeb';
237 } elsif ($template->{type} eq 'boolean') {
238 tag "boolean-template-has-bogus-default",
239 "$template->{template} $template->{default}"
240 if defined $template->{default}
241 and $template->{default} ne 'true'
242 and $template->{default} ne 'false';
245 if ($template->{choices} && ($template->{choices} !~ /^\s*$/)) {
246 my $nrchoices = count_choices ($template->{choices});
247 for my $key (keys %$template) {
248 if ($key =~ /^choices-/) {
249 if (! $template->{$key} || ($template->{$key} =~ /^\s*$/)) {
250 tag "empty-translated-choices", "$template->{template} $key";
252 if (count_choices ($template->{$key}) != $nrchoices) {
253 tag "mismatch-translated-choices", "$template->{template} $key";
257 if ($template->{choices} =~ /^\s*(yes\s*,\s*no|no\s*,\s*yes)\s*$/i) {
258 tag "select-with-boolean-choices", "$template->{template}";
262 if ($isselect and not exists $template->{choices}) {
263 tag "select-without-choices", "$template->{template}";
266 if (not exists $template->{description}) {
267 tag "no-template-description", "$template->{template}";
268 } elsif ($template->{description}=~m/^\s*(.*?)\s*?\n\s*\1\s*$/) {
269 # Check for duplication. Should all this be folded into the
270 # description checks?
271 tag "duplicate-long-description-in-template",
272 "$template->{template}";
276 foreach my $field (sort keys %$template) {
277 # Tests on translations
278 my ($mainfield, $lang) = split m/-/, $field, 2;
280 $languages{$lang}{$mainfield}=1;
282 unless ($template_fields{$mainfield}) { # Ignore language codes here
283 tag "unknown-field-in-templates", "$template->{template} $field";
287 if ($template->{template} && $template->{type}) {
288 $potential_db_abuse{$template->{template}} = 1
289 if (($template->{type} eq "note") or ($template->{type} eq "text"));
292 # Check the description against the best practices in the Developer's
293 # Reference, but skip all templates where the short description contains
294 # the string "for internal use".
295 my ($short, $extended);
296 if (defined $template->{description}) {
297 $template->{description} =~ m/^([^\n]*)\n(.*)$/s;
298 ($short, $extended) = ($1, $2);
299 unless (defined $short) {
300 $short = $template->{description};
303 ($short, $extended) = ('', '');
305 my $type = $template->{type} || '';
306 unless ($short =~ /for internal use/i) {
307 my $isprompt = grep { $_ eq $type } qw(string password);
308 my $isselect = grep { $_ eq $type } qw(select multiselect);
310 if ($short && ($short !~ m/:$/ || $short =~ m/^(what|who|when|where|which|how)/i)) {
311 tag "malformed-prompt-in-templates", $template->{template};
315 if ($short =~ /^(Please|Cho+se|Enter|Select|Specify|Give)/) {
316 tag "using-imperative-form-in-templates", $template->{template};
319 if ($type eq 'boolean') {
320 if ($short !~ /\?/) {
321 tag "malformed-question-in-templates", $template->{template};
324 if (defined ($extended) && $extended =~ /\?/) {
325 tag "using-question-in-extended-description-in-templates", $template->{template};
327 if ($type eq 'note') {
328 if ($short =~ /[.?;:]$/) {
329 tag "malformed-title-in-templates", $template->{template};
332 if (length ($short) > 75) {
333 tag "too-long-short-description-in-templates", $template->{template};
335 if (defined $template->{description}) {
336 if ($template->{description} =~ /(\A|\s)(I|[Mm]y|[Ww]e|[Oo]ur|[Oo]urs|mine|myself|ourself|me|us)(\Z|\s)/) {
337 tag "using-first-person-in-templates", $template->{template};
339 if ($template->{description} =~ /[ \'\"]yes[ \'\",;.]/i and $type eq 'boolean') {
340 tag "making-assumptions-about-interfaces-in-templates", $template->{template};
344 # Check whether the extended description is too long.
347 for my $string (split ("\n", $extended)) {
348 while (length ($string) > 80) {
349 my $pos = rindex ($string, ' ', 80);
351 $pos = index ($string, ' ');
356 $string = substr ($string, $pos + 1);
363 tag "too-long-extended-description-in-templates", $template->{template};
369 # Check the maintainer scripts.
371 my $config_calls_db_input;
374 my %template_aliases;
375 for my $file (qw(config prerm postrm preinst postinst)) {
376 my $potential_makedev = {};
377 if (open(IN, '<', "control/$file")) {
378 my $usesconfmodule='';
379 my $obsoleteconfmodule='';
384 # Only check scripts.
386 unless ($fl && $fl =~ /^\#!/) {
392 s/#.*//; # Not perfect for Perl, but should be OK
399 if (m,(?:\.|source)\s+/usr/share/debconf/confmodule, ||
400 m/(use|require)\s+Debconf::Client::ConfModule/) {
403 if (not $obsoleteconfmodule and
404 m,(/usr/share/debconf/confmodule\.sh|
405 Debian::DebConf::Client::ConfModule),x) {
406 tag "loads-obsolete-confmodule", "$file:$. $1";
408 $obsoleteconfmodule=1;
410 if ($file eq 'config' and m/db_input/) {
411 $config_calls_db_input = 1;
413 if ($file eq 'postinst' and not $db_input and m/db_input/
414 and not $config_calls_db_input) {
416 tag "postinst-uses-db-input", ""
417 unless $type eq 'udeb';
421 $potential_makedev->{$.} = 1;
423 if (m/^\s*(?:db_input|db_text)\s+[\"\']?(\S+?)[\"\']?\s+(\S+)\s/) {
424 my ($priority, $template) = ($1, $2);
425 $templates_used{$template} = 1;
426 if ($priority !~ /^\$\S+$/) {
427 tag "unknown-debconf-priority", "$file:$. $1"
428 unless ($valid_priorities{$priority});
429 tag "possible-debconf-note-abuse", "$file:$. $template"
430 if ($potential_db_abuse{$template}
431 and (not ($potential_makedev->{($. - 1)} and ($priority eq "low")))
432 and ($priority =~ /^(low|medium)$/));
435 if (m/^\s*(?:db_get|db_set(?:title)?)\s+[\"\']?(\S+?)[\"\']?(\s|\Z)/) {
436 $templates_used{$1} = 1;
438 if (m/^\s*db_register\s+[\"\']?(\S+?)[\"\']?\s+(\S+)\s/) {
439 my ($template, $question) = ($1, $2);
440 push @{$template_aliases{$template}}, $question;
442 if (not $isdefault and m/db_fset.*isdefault/) {
444 tag "isdefault-flag-is-deprecated", "$file";
447 if (not $db_purge and m/db_purge/) { # TODO: Perl?
452 if ($file eq 'postinst' or $file eq 'config') {
453 unless ($usesconfmodule) {
454 tag "$file-does-not-load-confmodule", ""
455 unless ($type eq 'udeb' || ($file eq 'postinst' && !$seenconfig));
459 if ($file eq 'postrm') {
461 tag "postrm-does-not-purge-debconf", "";
466 } elsif ($file eq 'postinst') {
467 tag "$file-does-not-load-confmodule", ""
468 unless ($type eq 'udeb' || !$seenconfig);
469 } elsif ($file eq 'postrm') {
470 tag "postrm-does-not-purge-debconf", ""
471 unless ($type eq 'udeb');
475 foreach my $template (@templates_seen) {
478 if ($templates_used{$template}) {
481 foreach my $alias (@{$template_aliases{$template}}) {
482 if ($templates_used{$alias}) {
488 tag "unused-debconf-template", $template
489 unless $used or $pkg eq "debconf";
492 # Check that the right dependencies are in the control file. Accept any
493 # package that might provide debconf functionality.
495 my $anydebconf = Dep::parse(join (' | ', @debconfs));
497 unless (Dep::implies($dependencies{'pre-depends'}, $anydebconf)) {
498 tag "missing-debconf-dependency-for-preinst", ""
499 unless $type eq 'udeb';
502 unless (Dep::implies($alldependencies, $anydebconf) or $usesdbconfig) {
503 tag "missing-debconf-dependency", "";
507 # Now make sure that no scripts are using debconf as a registry.
508 # Unfortunately this requires us to unpack to level 2 and grep all the
509 # scripts in the package.
510 # the following checks is ignored if the package being checked is debconf
513 return 0 if ($pkg eq "debconf") || ($type eq 'udeb');
515 open(SCRIPTS, '<', "scripts") or fail("cannot open lintian scripts file: $!");
519 # From checks/scripts.
520 my ($calls_env, $interpreter, $filename) = m/^(env )?(\S*) (.*)$/
521 or fail("bad line in scripts file: $_");
523 open(IN, '<', "unpacked/$filename") or fail("cannot open $filename: $!");
525 s/#.*//; # Not perfect for Perl, but should be OK
526 if (m,/usr/share/debconf/confmodule, or
527 m/(?:Debconf|Debian::DebConf)::Client::ConfModule/) {
528 tag "debconf-is-not-a-registry", "$filename";
538 # -----------------------------------
540 # Count the number of choices. Splitting code copied from debconf 1.5.8
541 # (Debconf::Question).
546 for my $chunk (split /(\\[, ]|,\s+)/, $choices) {
547 if ($chunk =~ /^\\([, ])$/) {
549 } elsif ($chunk =~ /^,\s+$/) {
550 push (@items, $item);
556 push (@items, $item) if $item ne '';
557 return scalar (@items);
563 # indent-tabs-mode: t
564 # cperl-indent-level: 4
566 # vim: syntax=perl ts=8