Bug#841670: lintian: Check udev rules and AppStream metadata
Niels suggested to me on IRC to move the test deb from t/debs/ to
t/tests/ and split it in two, one for the udev and one for the appstream
check. In the process of doing this I discovered bugs in the udev
check, so this proved very valuable. Here is a set of updated patches.
--
Vennlig hilsen
Petter Reinholdtsen
>From 09f0d85756dc7a30d938de0313f12b40e7988496 Mon Sep 17 00:00:00 2001
From: Petter Reinholdtsen <pere@hungry.com>
Date: Wed, 26 Oct 2016 12:01:16 +0000
Subject: [PATCH 1/3] Added two new test debs udev-rules and appstream-metadata
for AppStream and udev checks.
---
.../appstream-metadata-obsolete.metadata.xml | 2 ++
.../debian/debian/appstream-metadata.desktop | 8 ++++++++
.../debian/debian/appstream-metadata.dirs | 2 ++
.../debian/debian/appstream-metadata.metadata.xml | 22 ++++++++++++++++++++++
.../debian/debian/appstream-metadata.udev | 14 ++++++++++++++
t/tests/appstream-metadata/debian/debian/rules | 14 ++++++++++++++
t/tests/appstream-metadata/desc | 8 ++++++++
t/tests/appstream-metadata/tags | 6 ++++++
t/tests/udev-rules/debian/debian/rules | 13 +++++++++++++
t/tests/udev-rules/debian/debian/udev-rules.dirs | 2 ++
.../debian/debian/udev-rules.metadata.xml | 22 ++++++++++++++++++++++
t/tests/udev-rules/debian/debian/udev-rules.udev | 17 +++++++++++++++++
t/tests/udev-rules/desc | 7 +++++++
t/tests/udev-rules/tags | 4 ++++
14 files changed, 141 insertions(+)
create mode 100644 t/tests/appstream-metadata/debian/debian/appstream-metadata-obsolete.metadata.xml
create mode 100644 t/tests/appstream-metadata/debian/debian/appstream-metadata.desktop
create mode 100644 t/tests/appstream-metadata/debian/debian/appstream-metadata.dirs
create mode 100644 t/tests/appstream-metadata/debian/debian/appstream-metadata.metadata.xml
create mode 100644 t/tests/appstream-metadata/debian/debian/appstream-metadata.udev
create mode 100644 t/tests/appstream-metadata/debian/debian/rules
create mode 100644 t/tests/appstream-metadata/desc
create mode 100644 t/tests/appstream-metadata/tags
create mode 100644 t/tests/udev-rules/debian/debian/rules
create mode 100644 t/tests/udev-rules/debian/debian/udev-rules.dirs
create mode 100644 t/tests/udev-rules/debian/debian/udev-rules.metadata.xml
create mode 100644 t/tests/udev-rules/debian/debian/udev-rules.udev
create mode 100644 t/tests/udev-rules/desc
create mode 100644 t/tests/udev-rules/tags
diff --git a/t/tests/appstream-metadata/debian/debian/appstream-metadata-obsolete.metadata.xml b/t/tests/appstream-metadata/debian/debian/appstream-metadata-obsolete.metadata.xml
new file mode 100644
index 0000000..31d281e
--- /dev/null
+++ b/t/tests/appstream-metadata/debian/debian/appstream-metadata-obsolete.metadata.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<application/>
diff --git a/t/tests/appstream-metadata/debian/debian/appstream-metadata.desktop b/t/tests/appstream-metadata/debian/debian/appstream-metadata.desktop
new file mode 100644
index 0000000..4c91430
--- /dev/null
+++ b/t/tests/appstream-metadata/debian/debian/appstream-metadata.desktop
@@ -0,0 +1,8 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Name=appstream-udev-data
+Terminal=true
+Exec=true
+Categories=ConsoleOnly;Game;
+Keywords=Text;
diff --git a/t/tests/appstream-metadata/debian/debian/appstream-metadata.dirs b/t/tests/appstream-metadata/debian/debian/appstream-metadata.dirs
new file mode 100644
index 0000000..402f5d5
--- /dev/null
+++ b/t/tests/appstream-metadata/debian/debian/appstream-metadata.dirs
@@ -0,0 +1,2 @@
+usr/share/metainfo
+usr/share/appdata
diff --git a/t/tests/appstream-metadata/debian/debian/appstream-metadata.metadata.xml b/t/tests/appstream-metadata/debian/debian/appstream-metadata.metadata.xml
new file mode 100644
index 0000000..82294c1
--- /dev/null
+++ b/t/tests/appstream-metadata/debian/debian/appstream-metadata.metadata.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component>
+ <id>appstream-udev-data</id>
+ <metadata_license>MIT</metadata_license>
+ <name>lintian appstream-udev-data</name>
+ <summary>Test AppStream and udev related checks in lintian</summary>
+ <description>
+ <p>
+ This is a test package designed to exercise some feature or tag
+ of Lintian. It is part of the Lintian test suite and may do
+ very odd things. It should not be installed like a regular
+ package. It may be an empty package.
+ </p>
+ </description>
+ <provides>
+ <modalias>usb:v0000p0001d*</modalias>
+ <modalias>usb:v0000p0002d*</modalias>
+ <modalias>usb:v0000p0003d*</modalias>
+ <modalias>usb:v0000p0004d*</modalias>
+ <modalias>usb:v0000p000ad*</modalias>
+ </provides>
+</component>
diff --git a/t/tests/appstream-metadata/debian/debian/appstream-metadata.udev b/t/tests/appstream-metadata/debian/debian/appstream-metadata.udev
new file mode 100644
index 0000000..e2f2841
--- /dev/null
+++ b/t/tests/appstream-metadata/debian/debian/appstream-metadata.udev
@@ -0,0 +1,14 @@
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0001", \
+ MODE="0666"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0002", \
+ MODE="0660", GROUP="plugdev"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0003", \
+ TAG+="uaccess"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0004", \
+ MODE="0660", GROUP="plugdev", TAG+="uaccess"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="000a", \
+ ID_TEST_DEVICE="1"
diff --git a/t/tests/appstream-metadata/debian/debian/rules b/t/tests/appstream-metadata/debian/debian/rules
new file mode 100644
index 0000000..5302e21
--- /dev/null
+++ b/t/tests/appstream-metadata/debian/debian/rules
@@ -0,0 +1,14 @@
+#!/usr/bin/make -f
+
+DESTDIR = debian/$(shell dh_listpackages)
+APPSYNC_DIR=$(DESTDIR)/usr/share/metainfo/
+OBSOLETE_APPSYNC_DIR=$(DESTDIR)/usr/share/appdata/
+UDEV_DIR=$(DESTDIR)/lib/udev/rules.d/
+
+%:
+ dh $@
+
+override_dh_install:
+ dh_install
+ install -m 0644 debian/appstream-metadata.metadata.xml $(APPSYNC_DIR)
+ install -m 0644 debian/appstream-metadata-obsolete.metadata.xml $(OBSOLETE_APPSYNC_DIR)
diff --git a/t/tests/appstream-metadata/desc b/t/tests/appstream-metadata/desc
new file mode 100644
index 0000000..2a424af
--- /dev/null
+++ b/t/tests/appstream-metadata/desc
@@ -0,0 +1,8 @@
+Testname: appstream-metadata
+Version: 1.0
+Description: Test AppStream and udev metadata in binary package
+Test-For:
+ appstream-metadata-in-legacy-location
+ appstream-metadata-legacy-format
+ appstream-metadata-missing-modalias-provide
+ appstream-metadata-malformed-modalias-provide
diff --git a/t/tests/appstream-metadata/tags b/t/tests/appstream-metadata/tags
new file mode 100644
index 0000000..03eeba9
--- /dev/null
+++ b/t/tests/appstream-metadata/tags
@@ -0,0 +1,6 @@
+E: appstream-metadata: appstream-metadata-legacy-format usr/share/appdata/appstream-metadata-obsolete.metadata.xml
+W: appstream-metadata: appstream-metadata-in-legacy-location usr/share/appdata/appstream-metadata-obsolete.metadata.xml
+W: appstream-metadata: appstream-metadata-malformed-modalias-provide usr/share/metainfo/appstream-metadata.metadata.xml include non-valid hex digit in USB matching rule 'usb:v0000p000ad*'
+W: appstream-metadata: appstream-metadata-missing-modalias-provide lib/udev/rules.d/60-appstream-metadata.rules match rule usb:v0000p000Ad*
+W: appstream-metadata: udev-rule-missing-uaccess lib/udev/rules.d/60-appstream-metadata.rules:2 user accessible device missing TAG+="uaccess"
+W: appstream-metadata: udev-rule-missing-uaccess lib/udev/rules.d/60-appstream-metadata.rules:5 user accessible device missing TAG+="uaccess"
diff --git a/t/tests/udev-rules/debian/debian/rules b/t/tests/udev-rules/debian/debian/rules
new file mode 100644
index 0000000..1ecb975
--- /dev/null
+++ b/t/tests/udev-rules/debian/debian/rules
@@ -0,0 +1,13 @@
+#!/usr/bin/make -f
+
+DESTDIR = debian/$(shell dh_listpackages)
+APPSYNC_DIR=$(DESTDIR)/usr/share/metainfo/
+UDEV_DIR=$(DESTDIR)/lib/udev/rules.d/
+
+%:
+ dh $@
+
+override_dh_install:
+ dh_install
+ install -m 0644 debian/udev-rules.metadata.xml $(APPSYNC_DIR)
+ ln -s dangling $(UDEV_DIR)/60-dangling-symlink.rules
diff --git a/t/tests/udev-rules/debian/debian/udev-rules.dirs b/t/tests/udev-rules/debian/debian/udev-rules.dirs
new file mode 100644
index 0000000..d0cd146
--- /dev/null
+++ b/t/tests/udev-rules/debian/debian/udev-rules.dirs
@@ -0,0 +1,2 @@
+lib/udev/rules.d
+usr/share/metainfo
diff --git a/t/tests/udev-rules/debian/debian/udev-rules.metadata.xml b/t/tests/udev-rules/debian/debian/udev-rules.metadata.xml
new file mode 100644
index 0000000..2564e98
--- /dev/null
+++ b/t/tests/udev-rules/debian/debian/udev-rules.metadata.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component>
+ <id>udev-rules</id>
+ <metadata_license>MIT</metadata_license>
+ <name>lintian udev-rules test</name>
+ <summary>Test udev related checks in lintian</summary>
+ <description>
+ <p>
+ This is a test package designed to exercise some feature or tag
+ of Lintian. It is part of the Lintian test suite and may do
+ very odd things. It should not be installed like a regular
+ package. It may be an empty package.
+ </p>
+ </description>
+ <provides>
+ <modalias>usb:v0000p0001d*</modalias>
+ <modalias>usb:v0000p0002d*</modalias>
+ <modalias>usb:v0000p0003d*</modalias>
+ <modalias>usb:v0000p0004d*</modalias>
+ <modalias>usb:v0000p000Ad*</modalias>
+ </provides>
+</component>
diff --git a/t/tests/udev-rules/debian/debian/udev-rules.udev b/t/tests/udev-rules/debian/debian/udev-rules.udev
new file mode 100644
index 0000000..dd3442b
--- /dev/null
+++ b/t/tests/udev-rules/debian/debian/udev-rules.udev
@@ -0,0 +1,17 @@
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0001", \
+ MODE="0666"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0002", \
+ MODE="0660", GROUP="plugdev"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0003", \
+ TAG+="uaccess"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0004", \
+ MODE="0660", GROUP="plugdev", TAG+="uaccess"
+
+ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="0005", \
+ MODE="0660", GROUP="plugdev", TAG+="uaccess"
+
+SUBSYSTEM=="usb", ACTION=="add", ATTR{idVendor}=="0000", ATTR{idProduct}=="000a", \
+ ID_TEST_DEVICE="1"
diff --git a/t/tests/udev-rules/desc b/t/tests/udev-rules/desc
new file mode 100644
index 0000000..b633996
--- /dev/null
+++ b/t/tests/udev-rules/desc
@@ -0,0 +1,7 @@
+Testname: udev-rules
+Version: 1.0
+Description: Check udev rules for mistakes
+Test-For:
+ udev-rule-unreadable
+ udev-rule-missing-uaccess
+ udev-rule-missing-subsystem
diff --git a/t/tests/udev-rules/tags b/t/tests/udev-rules/tags
new file mode 100644
index 0000000..5798a00
--- /dev/null
+++ b/t/tests/udev-rules/tags
@@ -0,0 +1,4 @@
+E: udev-rules: udev-rule-unreadable lib/udev/rules.d/60-dangling-symlink.rules
+W: udev-rules: udev-rule-missing-subsystem lib/udev/rules.d/60-udev-rules.rules:14 vendor/product matching missing SUBSYSTEM specifier
+W: udev-rules: udev-rule-missing-uaccess lib/udev/rules.d/60-udev-rules.rules:2 user accessible device missing TAG+="uaccess"
+W: udev-rules: udev-rule-missing-uaccess lib/udev/rules.d/60-udev-rules.rules:5 user accessible device missing TAG+="uaccess"
--
2.9.3
>From eab5a1d25afa7a590fe4f59561c92c6f07851c49 Mon Sep 17 00:00:00 2001
From: Petter Reinholdtsen <pere@hungry.com>
Date: Sun, 23 Oct 2016 23:33:22 +0200
Subject: [PATCH 2/3] Added new check for udev rule files.
Mostly check USB rules.
---
checks/udev.desc | 32 +++++++++++++
checks/udev.pm | 114 +++++++++++++++++++++++++++++++++++++++++++++++
t/scripts/pod-spelling.t | 2 +-
3 files changed, 147 insertions(+), 1 deletion(-)
create mode 100644 checks/udev.desc
create mode 100644 checks/udev.pm
diff --git a/checks/udev.desc b/checks/udev.desc
new file mode 100644
index 0000000..7ccfdf8
--- /dev/null
+++ b/checks/udev.desc
@@ -0,0 +1,32 @@
+Check-Script: udev
+Author: Petter Reinholdtsen <pere@hungry.com>
+Type: binary
+Needs-Info: unpacked
+Info: This script checks the udev rules for problems.
+
+Tag: udev-rule-unreadable
+Severity: serious
+Certainty: certain
+Ref: https://wiki.debian.org/USB/GadgetSetup
+Info: The udev rule entry should be a file
+ The package contain a non-file in /lib/udev/rules.d/. The directory
+ should only contain readable files.
+
+Tag: udev-rule-missing-uaccess
+Severity: normal
+Certainty: possible
+Ref: https://wiki.debian.org/USB/GadgetSetup
+Info: The package set up a device for user access without using the
+ uaccess tag. Some udev rules get the same effect using other markers
+ enabling console user access using rules in
+ /lib/udev/rules.d/70-uaccess.rules. Others should specify
+ TAG+="uaccess" in the udev rule.
+
+Tag: udev-rule-missing-subsystem
+Severity: normal
+Certainty: possible
+Ref: https://wiki.debian.org/USB/GadgetSetup
+Info: The package matches vendor/product IDs without specifying
+ subsystem. The vendor/product IDs are subsystem specific. Matching
+ rules using those should specify subsystem too, for example by using
+ SUBSYSTEM=="usb" at the start of the matching rule.
diff --git a/checks/udev.pm b/checks/udev.pm
new file mode 100644
index 0000000..3aa5e2a
--- /dev/null
+++ b/checks/udev.pm
@@ -0,0 +1,114 @@
+# udev -- lintian check script -*- perl -*-
+
+# Copyright © 2016 Petter Reinholdtsen
+#
+# 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::udev;
+
+use strict;
+use warnings;
+
+use Lintian::Tags qw(tag);
+
+# Check /lib/udev/rules.d/, detect use of MODE="0666" and use of
+# GROUP="plugdev" without TAG+="uaccess".
+
+sub run {
+ my ($pkg, $type, $info, $proc, $group) = @_;
+ my $rules_dir = $info->index_resolved_path('lib/udev/rules.d/');
+ return unless $rules_dir;
+ foreach my $file ($rules_dir->children) {
+ if (! $file->is_open_ok()) {
+ tag('udev-rule-unreadable', $file);
+ next;
+ }
+ check_udev_rules($file, \&check_rule);
+ }
+ return;
+}
+
+sub check_rule {
+ my ($file, $linenum, $rule) = @_;
+
+ # for USB, if everyone or the plugdev group members are
+ # allowed access, the uaccess tag should be used too.
+ if ($rule =~ m/SUBSYSTEM=="usb"/
+ && ($rule =~ m/GROUP="plugdev"/
+ || $rule =~ m/MODE="0666"/)
+ && $rule !~ m/ENV\{COLOR_MEASUREMENT_DEVICE\}/
+ && $rule !~ m/ENV\{DDC_DEVICE\}/
+ && $rule !~ m/ENV\{ID_CDROM\}/
+ && $rule !~ m/ENV\{ID_FFADO\}/
+ && $rule !~ m/ENV\{ID_GPHOTO2\}/
+ && $rule !~ m/ENV\{ID_HPLIP\}/
+ && $rule !~ m/ENV\{ID_INPUT_JOYSTICK\}/
+ && $rule !~ m/ENV\{ID_MAKER_TOOL\}/
+ && $rule !~ m/ENV\{ID_MEDIA_PLAYER\}/
+ && $rule !~ m/ENV\{ID_PDA\}/
+ && $rule !~ m/ENV\{ID_REMOTE_CONTROL\}/
+ && $rule !~ m/ENV\{ID_SECURITY_TOKEN\}/
+ && $rule !~ m/ENV\{ID_SMARTCARD_READER\}/
+ && $rule !~ m/ENV\{ID_SOFTWARE_RADIO\}/
+ && $rule !~ m/TAG\+="uaccess"/) {
+ tag('udev-rule-missing-uaccess', "$file:$linenum",
+ 'user accessible device missing TAG+="uaccess"');
+ }
+
+ # Matching rules mentioning vendor/product should also specify
+ # subsystem, as vendor/product is subsystem specific.
+ if ($rule =~ m/ATTR\{idVendor\}=="[0-9a-fA-F]+"/
+ && $rule =~ m/ATTR\{idProduct\}=="[0-9a-fA-F]*"/
+ && $rule !~ m/SUBSYSTEM=="[^"]+"/ ) {
+ tag('udev-rule-missing-subsystem', "$file:$linenum",
+ 'vendor/product matching missing SUBSYSTEM specifier');
+ }
+ return 0;
+}
+
+sub check_udev_rules {
+ my ($file, $check) = @_;
+
+ my $fd = $file->open();
+ my $linenum = 0;
+ my $cont;
+ my $retval = 0;
+ while (<$fd>) {
+ chomp;
+ $linenum++;
+ if (defined $cont) {
+ $_ = $cont . $_;
+ $cont = undef;
+ }
+ if (/^(.*)\\$/) {
+ $cont = $1;
+ next;
+ }
+ next if /^#.*/; # Skip comments
+ $retval |= $check->($file, $linenum, $_);
+ }
+ close($fd);
+ return $retval;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/t/scripts/pod-spelling.t b/t/scripts/pod-spelling.t
index 75787eb..6973488 100755
--- a/t/scripts/pod-spelling.t
+++ b/t/scripts/pod-spelling.t
@@ -121,7 +121,7 @@ hashrefs namespace subdir SIGPIPE SIG blocknumber blocksub readwindow
REMOVESLASH STAMPFILE TAGNAME TCODE TESTDATA BLOCKSIZE jN
POSIX t1c2pfb init runtime txt executability writability
INHANDLE OUTHANDLES UTC timestamp faux tagname READMEs Testname
-debhelper dh buildpackage
+debhelper dh buildpackage uaccess udev
__END__
--
2.9.3
>From 3b24ddaf0a6ec0178b3431715696c954eeae8edb Mon Sep 17 00:00:00 2001
From: Petter Reinholdtsen <pere@hungry.com>
Date: Sun, 23 Oct 2016 23:41:47 +0200
Subject: [PATCH 3/3] Added checks for AppStream metadata and compare the
metadata to udev rules.
---
checks/appstream-metadata.desc | 36 +++++++
checks/appstream-metadata.pm | 215 +++++++++++++++++++++++++++++++++++++++++
t/scripts/pod-spelling.t | 2 +-
3 files changed, 252 insertions(+), 1 deletion(-)
create mode 100644 checks/appstream-metadata.desc
create mode 100644 checks/appstream-metadata.pm
diff --git a/checks/appstream-metadata.desc b/checks/appstream-metadata.desc
new file mode 100644
index 0000000..3eea7cc
--- /dev/null
+++ b/checks/appstream-metadata.desc
@@ -0,0 +1,36 @@
+Check-Script: appstream-metadata
+Author: Petter Reinholdtsen <pere@hungry.com>
+Type: binary
+Needs-Info: unpacked
+Info: This script checks the AppStream metadata files for problems.
+
+Tag: appstream-metadata-in-legacy-location
+Severity: minor
+Certainty: certain
+Ref: https://wiki.debian.org/AppStream/Guidelines
+Info: AppStream metadata file was found in /usr/share/appdata/. The
+ AppStream XML files should be placed in /usr/share/metadata/.
+
+Tag: appstream-metadata-legacy-format
+Severity: important
+Certainty: certain
+Ref: https://wiki.debian.org/AppStream/Guidelines
+Info: AppStream metadata with obsolete <application> root node found.
+ The XML root node should be <component>.
+
+Tag: appstream-metadata-missing-modalias-provide
+Severity: normal
+Certainty: certain
+Ref: https://wiki.debian.org/AppStream/Guidelines
+Info: This package contain a udev rule for providing device access to
+ the console user (using the uaccess udev TAG) or to members of the
+ plugdev file group without announcing the hardware support using
+ AppStream.
+
+Tag: appstream-metadata-malformed-modalias-provide
+Severity: normal
+Certainty: certain
+Ref: https://wiki.debian.org/AppStream/Guidelines
+Info: The modalias matching rule in the AppStream metadata file is
+ malformed. Hexadecimal numbers in vendor and product IDs must be
+ upper case.
diff --git a/checks/appstream-metadata.pm b/checks/appstream-metadata.pm
new file mode 100644
index 0000000..af65354
--- /dev/null
+++ b/checks/appstream-metadata.pm
@@ -0,0 +1,215 @@
+# appstream-metadata -- lintian check script -*- perl -*-
+
+# Copyright © 2016 Petter Reinholdtsen
+#
+# 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::appstream_metadata;
+
+# For .desktop files, the lintian check would be really easy: Check if
+# .desktop file is there, check if matching file exists in
+# /usr/share/metainfo, if not throw a warning. Maybe while we're at it
+# also check for legacy locations (stuff in /usr/share/appdata) and
+# legacy data (metainfo files starting with `<application>`).
+#
+# For modaliases, maybe udev rules could give some hints.
+# Check modalias values to ensure hex numbers are using capital A-F.
+
+use strict;
+use warnings;
+
+use XML::Simple qw(:strict);
+use File::Basename qw(basename);
+
+use Lintian::Tags qw(tag);
+
+sub run {
+ my ($pkg, $type, $info, $proc, $group) = @_;
+
+ my %desktopfiles;
+ my %metainfo;
+ my @udevrules;
+ my $found_modalias = 0;
+ my $modaliases = [];
+ if (defined(my $dir = $info->index_resolved_path('usr/share/applications/'))) {
+ for my $file ($dir->children('breadth-first')) {
+ $desktopfiles{$file} = 1 if ($file->is_file);
+ }
+ }
+ if (defined(my $dir = $info->index_resolved_path('usr/share/metainfo/'))) {
+ for my $file ($dir->children) {
+ if ($file->is_file) {
+ $metainfo{$file} = 1;
+ $found_modalias |= check_modalias($info, $file, $modaliases);
+ }
+ }
+ }
+ if (defined(my $dir = $info->index_resolved_path('usr/share/appdata/'))) {
+ for my $file ($dir->children('breadth-first')) {
+ if ($file->is_file) {
+ tag('appstream-metadata-in-legacy-location', $file);
+ $found_modalias |= check_modalias($info, $file, $modaliases);
+ }
+ }
+ }
+ if (defined(my $dir = $info->index_resolved_path('lib/udev/rules.d/'))) {
+ for my $file ($dir->children('breadth-first')) {
+ push(@udevrules, $file) if ($file->is_file);
+ }
+ }
+
+ for my $udevrule (@udevrules) {
+ if (check_udev_rules($udevrule, \&provides_user_device, $modaliases)
+ && !$found_modalias) {
+ tag('appstream-metadata-missing-modalias-provide', $udevrule);
+ }
+ }
+ return;
+}
+
+=head1 NAME
+
+check_modalias
+
+=head1 DESCRIPTION
+
+Check if a AppStream XML file contain a provides->modalias block and
+check its content.
+
+=cut
+sub check_modalias {
+ my ($info, $metadatafile, $modaliases) = @_;
+# my $metadatafile = $info->index_resolved_path($metadatapath);
+ if (! $metadatafile->is_open_ok()) {
+ # FIXME report this as an error
+ return;
+ }
+ my $xml = XMLin($metadatafile->fs_path(),
+ ForceArray => [ 'provides', 'modalias' ],
+ KeepRoot => 1,
+ KeyAttr => [],
+ );
+ if (exists $xml->{'application'}) {
+ tag('appstream-metadata-legacy-format', $metadatafile);
+ return 0;
+ }
+ if (exists $xml->{'component'}
+ && exists $xml->{'component'}->{'provides'}
+ && exists $xml->{'component'}->{'provides'}[0]->{'modalias'}) {
+ for (@{$xml->{'component'}->{'provides'}[0]->{'modalias'}}) {
+ push(@{$modaliases}, $_);
+ if (m/^usb:v[0-9a-f]{4}p[0-9a-f]{4}d/i
+ && ! m/^usb:v[0-9A-F]{4}p[0-9A-F]{4}d/) {
+ tag('appstream-metadata-malformed-modalias-provide',
+ $metadatafile,
+ "include non-valid hex digit in USB matching rule '$_'"
+ );
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+=head1 NAME
+
+provides_user_device
+
+=head1 DESCRIPTION
+
+Check if a udev rule file contain rules for plugdev or uaccess.
+
+=cut
+sub provides_user_device {
+ my ($udevrulefile, $linenum, $rule, $data) = @_;
+ my $retval = 0;
+ if (
+ m/plugdev/
+ || m/uaccess/
+ || m/MODE=\"0666\"/
+ ) {
+ $retval = 1;
+ }
+ if ($rule =~ m/SUBSYSTEM=="usb"/) {
+ my ($vmatch, $pmatch);
+ if ($rule =~ m/ATTR\{idVendor\}=="([0-9a-fA-F]{4})"/) {
+ $vmatch = "v" . uc($1);
+ }
+ if ($rule =~ m/ATTR\{idProduct\}=="([0-9a-fA-F]{4})"/) {
+ $pmatch = "p" . uc($1);
+ }
+ if (defined $vmatch && defined $pmatch) {
+ my $match = "usb:${vmatch}${pmatch}d";
+ my $foundmatch;
+ for my $aliasmatch (@{$data}) {
+ if (0 == index($aliasmatch, $match)) {
+ $foundmatch = 1;
+ }
+ }
+ if (! $foundmatch) {
+ tag('appstream-metadata-missing-modalias-provide',
+ $udevrulefile, "match rule $match*");
+ }
+ }
+ }
+ return $retval;
+}
+
+=head1 NAME
+
+check_udev_rules
+
+=head1 DESCRIPTION
+
+Extract all udev rules from a rule file and pass them on one by one to
+the callback function.
+
+This is a copy of a function in udev.pm.
+
+=cut
+sub check_udev_rules {
+ my ($file, $check, $data) = @_;
+
+ my $fd = $file->open();
+ my $linenum = 0;
+ my $cont;
+ my $retval = 0;
+ while (<$fd>) {
+ chomp;
+ $linenum++;
+ if (defined $cont) {
+ $_ = $cont . $_;
+ $cont = undef;
+ }
+ if (/^(.*)\\$/) {
+ $cont = $1;
+ next;
+ }
+ next if /^#.*/; # Skip comments
+ $retval |= $check->($file, $linenum, $_, $data);
+ }
+ close($fd);
+ return $retval;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/t/scripts/pod-spelling.t b/t/scripts/pod-spelling.t
index 6973488..a5b07db 100755
--- a/t/scripts/pod-spelling.t
+++ b/t/scripts/pod-spelling.t
@@ -121,7 +121,7 @@ hashrefs namespace subdir SIGPIPE SIG blocknumber blocksub readwindow
REMOVESLASH STAMPFILE TAGNAME TCODE TESTDATA BLOCKSIZE jN
POSIX t1c2pfb init runtime txt executability writability
INHANDLE OUTHANDLES UTC timestamp faux tagname READMEs Testname
-debhelper dh buildpackage uaccess udev
+debhelper dh buildpackage uaccess udev AppStream plugdev
__END__
--
2.9.3
Reply to: