summaryrefslogtreecommitdiffstats
path: root/scripts/Dpkg/Vendor
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:45:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 00:45:20 +0000
commit9a08cbfcc1ef900a04580f35afe2a4592d7d6030 (patch)
tree004cc7027bca2f2c0bcb5806527c8e0c48df2d6e /scripts/Dpkg/Vendor
parentInitial commit. (diff)
downloaddpkg-upstream/1.19.8.tar.xz
dpkg-upstream/1.19.8.zip
Adding upstream version 1.19.8.upstream/1.19.8upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--scripts/Dpkg/Vendor.pm212
-rw-r--r--scripts/Dpkg/Vendor/Debian.pm484
-rw-r--r--scripts/Dpkg/Vendor/Default.pm201
-rw-r--r--scripts/Dpkg/Vendor/Ubuntu.pm165
4 files changed, 1062 insertions, 0 deletions
diff --git a/scripts/Dpkg/Vendor.pm b/scripts/Dpkg/Vendor.pm
new file mode 100644
index 0000000..1961591
--- /dev/null
+++ b/scripts/Dpkg/Vendor.pm
@@ -0,0 +1,212 @@
+# Copyright © 2008-2009 Raphaël Hertzog <hertzog@debian.org>
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+package Dpkg::Vendor;
+
+use strict;
+use warnings;
+use feature qw(state);
+
+our $VERSION = '1.01';
+our @EXPORT_OK = qw(
+ get_current_vendor
+ get_vendor_info
+ get_vendor_file
+ get_vendor_dir
+ get_vendor_object
+ run_vendor_hook
+);
+
+use Exporter qw(import);
+
+use Dpkg ();
+use Dpkg::ErrorHandling;
+use Dpkg::Gettext;
+use Dpkg::Build::Env;
+use Dpkg::Control::HashCore;
+
+my $origins = "$Dpkg::CONFDIR/origins";
+$origins = $ENV{DPKG_ORIGINS_DIR} if $ENV{DPKG_ORIGINS_DIR};
+
+=encoding utf8
+
+=head1 NAME
+
+Dpkg::Vendor - get access to some vendor specific information
+
+=head1 DESCRIPTION
+
+The files in $Dpkg::CONFDIR/origins/ can provide information about various
+vendors who are providing Debian packages. Currently those files look like
+this:
+
+ Vendor: Debian
+ Vendor-URL: https://www.debian.org/
+ Bugs: debbugs://bugs.debian.org
+
+If the vendor derives from another vendor, the file should document
+the relationship by listing the base distribution in the Parent field:
+
+ Parent: Debian
+
+The file should be named according to the vendor name. The usual convention
+is to name the vendor file using the vendor name in all lowercase, but some
+variation is permitted. Namely, spaces are mapped to dashes ('-'), and the
+file can have the same casing as the Vendor field, or it can be capitalized.
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item $dir = get_vendor_dir()
+
+Returns the current dpkg origins directory name, where the vendor files
+are stored.
+
+=cut
+
+sub get_vendor_dir {
+ return $origins;
+}
+
+=item $fields = get_vendor_info($name)
+
+Returns a Dpkg::Control object with the information parsed from the
+corresponding vendor file in $Dpkg::CONFDIR/origins/. If $name is omitted,
+it will use $Dpkg::CONFDIR/origins/default which is supposed to be a symlink
+to the vendor of the currently installed operating system. Returns undef
+if there's no file for the given vendor.
+
+=cut
+
+sub get_vendor_info(;$) {
+ my $vendor = shift || 'default';
+ state %VENDOR_CACHE;
+ return $VENDOR_CACHE{$vendor} if exists $VENDOR_CACHE{$vendor};
+
+ my $file = get_vendor_file($vendor);
+ return unless $file;
+ my $fields = Dpkg::Control::HashCore->new();
+ $fields->load($file, compression => 0) or error(g_('%s is empty'), $file);
+ $VENDOR_CACHE{$vendor} = $fields;
+ return $fields;
+}
+
+=item $name = get_vendor_file($name)
+
+Check if there's a file for the given vendor and returns its
+name.
+
+=cut
+
+sub get_vendor_file(;$) {
+ my $vendor = shift || 'default';
+ my $file;
+ my @tries = ($vendor, lc($vendor), ucfirst($vendor), ucfirst(lc($vendor)));
+ if ($vendor =~ s/\s+/-/) {
+ push @tries, $vendor, lc($vendor), ucfirst($vendor), ucfirst(lc($vendor));
+ }
+ foreach my $name (@tries) {
+ $file = "$origins/$name" if -e "$origins/$name";
+ }
+ return $file;
+}
+
+=item $name = get_current_vendor()
+
+Returns the name of the current vendor. If DEB_VENDOR is set, it uses
+that first, otherwise it falls back to parsing $Dpkg::CONFDIR/origins/default.
+If that file doesn't exist, it returns undef.
+
+=cut
+
+sub get_current_vendor() {
+ my $f;
+ if (Dpkg::Build::Env::has('DEB_VENDOR')) {
+ $f = get_vendor_info(Dpkg::Build::Env::get('DEB_VENDOR'));
+ return $f->{'Vendor'} if defined $f;
+ }
+ $f = get_vendor_info();
+ return $f->{'Vendor'} if defined $f;
+ return;
+}
+
+=item $object = get_vendor_object($name)
+
+Return the Dpkg::Vendor::* object of the corresponding vendor.
+If $name is omitted, return the object of the current vendor.
+If no vendor can be identified, then return the Dpkg::Vendor::Default
+object.
+
+=cut
+
+sub get_vendor_object {
+ my $vendor = shift || get_current_vendor() || 'Default';
+ state %OBJECT_CACHE;
+ return $OBJECT_CACHE{$vendor} if exists $OBJECT_CACHE{$vendor};
+
+ my ($obj, @names);
+ push @names, $vendor, lc($vendor), ucfirst($vendor), ucfirst(lc($vendor));
+
+ foreach my $name (@names) {
+ eval qq{
+ pop \@INC if \$INC[-1] eq '.';
+ require Dpkg::Vendor::$name;
+ \$obj = Dpkg::Vendor::$name->new();
+ };
+ unless ($@) {
+ $OBJECT_CACHE{$vendor} = $obj;
+ return $obj;
+ }
+ }
+
+ my $info = get_vendor_info($vendor);
+ if (defined $info and defined $info->{'Parent'}) {
+ return get_vendor_object($info->{'Parent'});
+ } else {
+ return get_vendor_object('Default');
+ }
+}
+
+=item run_vendor_hook($hookid, @params)
+
+Run a hook implemented by the current vendor object.
+
+=cut
+
+sub run_vendor_hook {
+ my $vendor_obj = get_vendor_object();
+ $vendor_obj->run_hook(@_);
+}
+
+=back
+
+=head1 CHANGES
+
+=head2 Version 1.01 (dpkg 1.17.0)
+
+New function: get_vendor_dir().
+
+=head2 Version 1.00 (dpkg 1.16.1)
+
+Mark the module as public.
+
+=head1 SEE ALSO
+
+deb-origin(5).
+
+=cut
+
+1;
diff --git a/scripts/Dpkg/Vendor/Debian.pm b/scripts/Dpkg/Vendor/Debian.pm
new file mode 100644
index 0000000..a352bbd
--- /dev/null
+++ b/scripts/Dpkg/Vendor/Debian.pm
@@ -0,0 +1,484 @@
+# Copyright © 2009-2011 Raphaël Hertzog <hertzog@debian.org>
+# Copyright © 2009, 2011-2017 Guillem Jover <guillem@debian.org>
+#
+# Hardening build flags handling derived from work of:
+# Copyright © 2009-2011 Kees Cook <kees@debian.org>
+# Copyright © 2007-2008 Canonical, Ltd.
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+package Dpkg::Vendor::Debian;
+
+use strict;
+use warnings;
+
+our $VERSION = '0.01';
+
+use Dpkg;
+use Dpkg::Gettext;
+use Dpkg::ErrorHandling;
+use Dpkg::Control::Types;
+
+use parent qw(Dpkg::Vendor::Default);
+
+=encoding utf8
+
+=head1 NAME
+
+Dpkg::Vendor::Debian - Debian vendor object
+
+=head1 DESCRIPTION
+
+This vendor object customizes the behaviour of dpkg scripts for Debian
+specific behavior and policies.
+
+=cut
+
+sub run_hook {
+ my ($self, $hook, @params) = @_;
+
+ if ($hook eq 'package-keyrings') {
+ return ('/usr/share/keyrings/debian-keyring.gpg',
+ '/usr/share/keyrings/debian-maintainers.gpg');
+ } elsif ($hook eq 'keyrings') {
+ warnings::warnif('deprecated', 'deprecated keyrings vendor hook');
+ return $self->run_hook('package-keyrings', @params);
+ } elsif ($hook eq 'archive-keyrings') {
+ return ('/usr/share/keyrings/debian-archive-keyring.gpg');
+ } elsif ($hook eq 'archive-keyrings-historic') {
+ return ('/usr/share/keyrings/debian-archive-removed-keys.gpg');
+ } elsif ($hook eq 'builtin-build-depends') {
+ return qw(build-essential:native);
+ } elsif ($hook eq 'builtin-build-conflicts') {
+ return ();
+ } elsif ($hook eq 'register-custom-fields') {
+ } elsif ($hook eq 'extend-patch-header') {
+ my ($textref, $ch_info) = @params;
+ if ($ch_info->{'Closes'}) {
+ foreach my $bug (split(/\s+/, $ch_info->{'Closes'})) {
+ $$textref .= "Bug-Debian: https://bugs.debian.org/$bug\n";
+ }
+ }
+
+ # XXX: Layer violation...
+ require Dpkg::Vendor::Ubuntu;
+ my $b = Dpkg::Vendor::Ubuntu::find_launchpad_closes($ch_info->{'Changes'});
+ foreach my $bug (@$b) {
+ $$textref .= "Bug-Ubuntu: https://bugs.launchpad.net/bugs/$bug\n";
+ }
+ } elsif ($hook eq 'update-buildflags') {
+ $self->_add_build_flags(@params);
+ } elsif ($hook eq 'builtin-system-build-paths') {
+ return qw(/build/);
+ } elsif ($hook eq 'build-tainted-by') {
+ return $self->_build_tainted_by();
+ } else {
+ return $self->SUPER::run_hook($hook, @params);
+ }
+}
+
+sub _add_build_flags {
+ my ($self, $flags) = @_;
+
+ # Default feature states.
+ my %use_feature = (
+ future => {
+ lfs => 0,
+ },
+ qa => {
+ bug => 0,
+ canary => 0,
+ },
+ reproducible => {
+ timeless => 1,
+ fixfilepath => 0,
+ fixdebugpath => 1,
+ },
+ sanitize => {
+ address => 0,
+ thread => 0,
+ leak => 0,
+ undefined => 0,
+ },
+ hardening => {
+ # XXX: This is set to undef so that we can cope with the brokenness
+ # of gcc managing this feature builtin.
+ pie => undef,
+ stackprotector => 1,
+ stackprotectorstrong => 1,
+ fortify => 1,
+ format => 1,
+ relro => 1,
+ bindnow => 0,
+ },
+ );
+
+ my %builtin_feature = (
+ hardening => {
+ pie => 1,
+ },
+ );
+
+ ## Setup
+
+ require Dpkg::BuildOptions;
+
+ # Adjust features based on user or maintainer's desires.
+ my $opts_build = Dpkg::BuildOptions->new(envvar => 'DEB_BUILD_OPTIONS');
+ my $opts_maint = Dpkg::BuildOptions->new(envvar => 'DEB_BUILD_MAINT_OPTIONS');
+
+ foreach my $area (sort keys %use_feature) {
+ $opts_build->parse_features($area, $use_feature{$area});
+ $opts_maint->parse_features($area, $use_feature{$area});
+ }
+
+ require Dpkg::Arch;
+
+ my $arch = Dpkg::Arch::get_host_arch();
+ my ($abi, $libc, $os, $cpu) = Dpkg::Arch::debarch_to_debtuple($arch);
+
+ unless (defined $abi and defined $libc and defined $os and defined $cpu) {
+ warning(g_("unknown host architecture '%s'"), $arch);
+ ($abi, $os, $cpu) = ('', '', '');
+ }
+
+ ## Global defaults
+
+ my $default_flags;
+ if ($opts_build->has('noopt')) {
+ $default_flags = '-g -O0';
+ } else {
+ $default_flags = '-g -O2';
+ }
+ $flags->append('CFLAGS', $default_flags);
+ $flags->append('CXXFLAGS', $default_flags);
+ $flags->append('OBJCFLAGS', $default_flags);
+ $flags->append('OBJCXXFLAGS', $default_flags);
+ $flags->append('FFLAGS', $default_flags);
+ $flags->append('FCFLAGS', $default_flags);
+ $flags->append('GCJFLAGS', $default_flags);
+
+ ## Area: future
+
+ if ($use_feature{future}{lfs}) {
+ my ($abi_bits, $abi_endian) = Dpkg::Arch::debarch_to_abiattrs($arch);
+ my $cpu_bits = Dpkg::Arch::debarch_to_cpubits($arch);
+
+ if ($abi_bits == 32 and $cpu_bits == 32) {
+ $flags->append('CPPFLAGS',
+ '-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64');
+ }
+ }
+
+ ## Area: qa
+
+ # Warnings that detect actual bugs.
+ if ($use_feature{qa}{bug}) {
+ foreach my $warnflag (qw(array-bounds clobbered volatile-register-var
+ implicit-function-declaration)) {
+ $flags->append('CFLAGS', "-Werror=$warnflag");
+ $flags->append('CXXFLAGS', "-Werror=$warnflag");
+ }
+ }
+
+ # Inject dummy canary options to detect issues with build flag propagation.
+ if ($use_feature{qa}{canary}) {
+ require Digest::MD5;
+ my $id = Digest::MD5::md5_hex(int rand 4096);
+
+ foreach my $flag (qw(CPPFLAGS CFLAGS OBJCFLAGS CXXFLAGS OBJCXXFLAGS)) {
+ $flags->append($flag, "-D__DEB_CANARY_${flag}_${id}__");
+ }
+ $flags->append('LDFLAGS', "-Wl,-z,deb-canary-${id}");
+ }
+
+ ## Area: reproducible
+
+ my $build_path;
+
+ # Mask features that might have an unsafe usage.
+ if ($use_feature{reproducible}{fixfilepath} or
+ $use_feature{reproducible}{fixdebugpath}) {
+ require Cwd;
+
+ $build_path = $ENV{DEB_BUILD_PATH} || Cwd::getcwd();
+
+ # If we have any unsafe character in the path, disable the flag,
+ # so that we do not need to worry about escaping the characters
+ # on output.
+ if ($build_path =~ m/[^-+:.0-9a-zA-Z~\/_]/) {
+ $use_feature{reproducible}{fixfilepath} = 0;
+ $use_feature{reproducible}{fixdebugpath} = 0;
+ }
+ }
+
+ # Warn when the __TIME__, __DATE__ and __TIMESTAMP__ macros are used.
+ if ($use_feature{reproducible}{timeless}) {
+ $flags->append('CPPFLAGS', '-Wdate-time');
+ }
+
+ # Avoid storing the build path in the binaries.
+ if ($use_feature{reproducible}{fixfilepath} or
+ $use_feature{reproducible}{fixdebugpath}) {
+ my $map;
+
+ # -ffile-prefix-map is a superset of -fdebug-prefix-map, prefer it
+ # if both are set.
+ if ($use_feature{reproducible}{fixfilepath}) {
+ $map = '-ffile-prefix-map=' . $build_path . '=.';
+ } else {
+ $map = '-fdebug-prefix-map=' . $build_path . '=.';
+ }
+
+ $flags->append('CFLAGS', $map);
+ $flags->append('CXXFLAGS', $map);
+ $flags->append('OBJCFLAGS', $map);
+ $flags->append('OBJCXXFLAGS', $map);
+ $flags->append('FFLAGS', $map);
+ $flags->append('FCFLAGS', $map);
+ $flags->append('GCJFLAGS', $map);
+ }
+
+ ## Area: sanitize
+
+ # Handle logical feature interactions.
+ if ($use_feature{sanitize}{address} and $use_feature{sanitize}{thread}) {
+ # Disable the thread sanitizer when the address one is active, they
+ # are mutually incompatible.
+ $use_feature{sanitize}{thread} = 0;
+ }
+ if ($use_feature{sanitize}{address} or $use_feature{sanitize}{thread}) {
+ # Disable leak sanitizer, it is implied by the address or thread ones.
+ $use_feature{sanitize}{leak} = 0;
+ }
+
+ if ($use_feature{sanitize}{address}) {
+ my $flag = '-fsanitize=address -fno-omit-frame-pointer';
+ $flags->append('CFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('LDFLAGS', '-fsanitize=address');
+ }
+
+ if ($use_feature{sanitize}{thread}) {
+ my $flag = '-fsanitize=thread';
+ $flags->append('CFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('LDFLAGS', $flag);
+ }
+
+ if ($use_feature{sanitize}{leak}) {
+ $flags->append('LDFLAGS', '-fsanitize=leak');
+ }
+
+ if ($use_feature{sanitize}{undefined}) {
+ my $flag = '-fsanitize=undefined';
+ $flags->append('CFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('LDFLAGS', $flag);
+ }
+
+ ## Area: hardening
+
+ # Mask builtin features that are not enabled by default in the compiler.
+ my %builtin_pie_arch = map { $_ => 1 } qw(
+ amd64
+ arm64
+ armel
+ armhf
+ hurd-i386
+ i386
+ kfreebsd-amd64
+ kfreebsd-i386
+ mips
+ mipsel
+ mips64el
+ powerpc
+ ppc64
+ ppc64el
+ riscv64
+ s390x
+ sparc
+ sparc64
+ );
+ if (not exists $builtin_pie_arch{$arch}) {
+ $builtin_feature{hardening}{pie} = 0;
+ }
+
+ # Mask features that are not available on certain architectures.
+ if ($os !~ /^(?:linux|kfreebsd|knetbsd|hurd)$/ or
+ $cpu =~ /^(?:hppa|avr32)$/) {
+ # Disabled on non-(linux/kfreebsd/knetbsd/hurd).
+ # Disabled on hppa, avr32
+ # (#574716).
+ $use_feature{hardening}{pie} = 0;
+ }
+ if ($cpu =~ /^(?:ia64|alpha|hppa|nios2)$/ or $arch eq 'arm') {
+ # Stack protector disabled on ia64, alpha, hppa, nios2.
+ # "warning: -fstack-protector not supported for this target"
+ # Stack protector disabled on arm (ok on armel).
+ # compiler supports it incorrectly (leads to SEGV)
+ $use_feature{hardening}{stackprotector} = 0;
+ }
+ if ($cpu =~ /^(?:ia64|hppa|avr32)$/) {
+ # relro not implemented on ia64, hppa, avr32.
+ $use_feature{hardening}{relro} = 0;
+ }
+
+ # Mask features that might be influenced by other flags.
+ if ($opts_build->has('noopt')) {
+ # glibc 2.16 and later warn when using -O0 and _FORTIFY_SOURCE.
+ $use_feature{hardening}{fortify} = 0;
+ }
+
+ # Handle logical feature interactions.
+ if ($use_feature{hardening}{relro} == 0) {
+ # Disable bindnow if relro is not enabled, since it has no
+ # hardening ability without relro and may incur load penalties.
+ $use_feature{hardening}{bindnow} = 0;
+ }
+ if ($use_feature{hardening}{stackprotector} == 0) {
+ # Disable stackprotectorstrong if stackprotector is disabled.
+ $use_feature{hardening}{stackprotectorstrong} = 0;
+ }
+
+ # PIE
+ if (defined $use_feature{hardening}{pie} and
+ $use_feature{hardening}{pie} and
+ not $builtin_feature{hardening}{pie}) {
+ my $flag = "-specs=$Dpkg::DATADIR/pie-compile.specs";
+ $flags->append('CFLAGS', $flag);
+ $flags->append('OBJCFLAGS', $flag);
+ $flags->append('OBJCXXFLAGS', $flag);
+ $flags->append('FFLAGS', $flag);
+ $flags->append('FCFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('GCJFLAGS', $flag);
+ $flags->append('LDFLAGS', "-specs=$Dpkg::DATADIR/pie-link.specs");
+ } elsif (defined $use_feature{hardening}{pie} and
+ not $use_feature{hardening}{pie} and
+ $builtin_feature{hardening}{pie}) {
+ my $flag = "-specs=$Dpkg::DATADIR/no-pie-compile.specs";
+ $flags->append('CFLAGS', $flag);
+ $flags->append('OBJCFLAGS', $flag);
+ $flags->append('OBJCXXFLAGS', $flag);
+ $flags->append('FFLAGS', $flag);
+ $flags->append('FCFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('GCJFLAGS', $flag);
+ $flags->append('LDFLAGS', "-specs=$Dpkg::DATADIR/no-pie-link.specs");
+ }
+
+ # Stack protector
+ if ($use_feature{hardening}{stackprotectorstrong}) {
+ my $flag = '-fstack-protector-strong';
+ $flags->append('CFLAGS', $flag);
+ $flags->append('OBJCFLAGS', $flag);
+ $flags->append('OBJCXXFLAGS', $flag);
+ $flags->append('FFLAGS', $flag);
+ $flags->append('FCFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('GCJFLAGS', $flag);
+ } elsif ($use_feature{hardening}{stackprotector}) {
+ my $flag = '-fstack-protector --param=ssp-buffer-size=4';
+ $flags->append('CFLAGS', $flag);
+ $flags->append('OBJCFLAGS', $flag);
+ $flags->append('OBJCXXFLAGS', $flag);
+ $flags->append('FFLAGS', $flag);
+ $flags->append('FCFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('GCJFLAGS', $flag);
+ }
+
+ # Fortify Source
+ if ($use_feature{hardening}{fortify}) {
+ $flags->append('CPPFLAGS', '-D_FORTIFY_SOURCE=2');
+ }
+
+ # Format Security
+ if ($use_feature{hardening}{format}) {
+ my $flag = '-Wformat -Werror=format-security';
+ $flags->append('CFLAGS', $flag);
+ $flags->append('CXXFLAGS', $flag);
+ $flags->append('OBJCFLAGS', $flag);
+ $flags->append('OBJCXXFLAGS', $flag);
+ }
+
+ # Read-only Relocations
+ if ($use_feature{hardening}{relro}) {
+ $flags->append('LDFLAGS', '-Wl,-z,relro');
+ }
+
+ # Bindnow
+ if ($use_feature{hardening}{bindnow}) {
+ $flags->append('LDFLAGS', '-Wl,-z,now');
+ }
+
+ ## Commit
+
+ # Set used features to their builtin setting if unset.
+ foreach my $area (sort keys %builtin_feature) {
+ foreach my $feature (keys %{$builtin_feature{$area}}) {
+ $use_feature{$area}{$feature} //= $builtin_feature{$area}{$feature};
+ }
+ }
+
+ # Store the feature usage.
+ foreach my $area (sort keys %use_feature) {
+ while (my ($feature, $enabled) = each %{$use_feature{$area}}) {
+ $flags->set_feature($area, $feature, $enabled);
+ }
+ }
+}
+
+sub _build_tainted_by {
+ my $self = shift;
+ my %tainted;
+
+ foreach my $pathname (qw(/bin /sbin /lib /lib32 /libo32 /libx32 /lib64)) {
+ next unless -l $pathname;
+
+ my $linkname = readlink $pathname;
+ if ($linkname eq "usr$pathname") {
+ $tainted{'merged-usr-via-symlinks'} = 1;
+ last;
+ }
+ }
+
+ require File::Find;
+ my %usr_local_types = (
+ configs => [ qw(etc) ],
+ includes => [ qw(include) ],
+ programs => [ qw(bin sbin) ],
+ libraries => [ qw(lib) ],
+ );
+ foreach my $type (keys %usr_local_types) {
+ File::Find::find({
+ wanted => sub { $tainted{"usr-local-has-$type"} = 1 if -f },
+ no_chdir => 1,
+ }, map { "/usr/local/$_" } @{$usr_local_types{$type}});
+ }
+
+ my @tainted = sort keys %tainted;
+ return @tainted;
+}
+
+=head1 CHANGES
+
+=head2 Version 0.xx
+
+This is a private module.
+
+=cut
+
+1;
diff --git a/scripts/Dpkg/Vendor/Default.pm b/scripts/Dpkg/Vendor/Default.pm
new file mode 100644
index 0000000..ed05c30
--- /dev/null
+++ b/scripts/Dpkg/Vendor/Default.pm
@@ -0,0 +1,201 @@
+# Copyright © 2009 Raphaël Hertzog <hertzog@debian.org>
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+package Dpkg::Vendor::Default;
+
+use strict;
+use warnings;
+
+our $VERSION = '0.01';
+
+# If you use this file as template to create a new vendor object, please
+# uncomment the following lines
+#use parent qw(Dpkg::Vendor::Default);
+
+=encoding utf8
+
+=head1 NAME
+
+Dpkg::Vendor::Default - default vendor object
+
+=head1 DESCRIPTION
+
+A vendor object is used to provide vendor specific behaviour
+in various places. This is the default object used in case
+there's none for the current vendor or in case the vendor could
+not be identified (see Dpkg::Vendor documentation).
+
+It provides some hooks that are called by various dpkg-* tools.
+If you need a new hook, please file a bug against dpkg-dev and explain
+your need. Note that the hook API has no guarantee to be stable over an
+extended period of time. If you run an important distribution that makes
+use of vendor hooks, you'd better submit them for integration so that
+we avoid breaking your code.
+
+=head1 METHODS
+
+=over 4
+
+=item $vendor_obj = Dpkg::Vendor::Default->new()
+
+Creates the default vendor object. Can be inherited by all vendor objects
+if they don't need any specific initialization at object creation time.
+
+=cut
+
+sub new {
+ my $this = shift;
+ my $class = ref($this) || $this;
+ my $self = {};
+ bless $self, $class;
+ return $self;
+}
+
+=item $vendor_obj->run_hook($id, @params)
+
+Run the corresponding hook. The parameters are hook-specific. The
+supported hooks are:
+
+=over 8
+
+=item before-source-build ($srcpkg)
+
+The first parameter is a Dpkg::Source::Package object. The hook is called
+just before the execution of $srcpkg->build().
+
+=item package-keyrings ()
+
+The hook is called when dpkg-source is checking a signature on a source
+package (since dpkg 1.18.11). It takes no parameters, but returns a
+(possibly empty) list of vendor-specific keyrings.
+
+=item archive-keyrings ()
+
+The hook is called when there is a need to check signatures on artifacts
+from repositories, for example by a download method (since dpkg 1.18.11).
+It takes no parameters, but returns a (possibly empty) list of
+vendor-specific keyrings.
+
+=item archive-keyrings-historic ()
+
+The hook is called when there is a need to check signatures on artifacts
+from historic repositories, for example by a download method
+(since dpkg 1.18.11). It takes no parameters, but returns a (possibly empty)
+list of vendor-specific keyrings.
+
+=item builtin-build-depends ()
+
+The hook is called when dpkg-checkbuilddeps is initializing the source
+package build dependencies (since dpkg 1.18.2). It takes no parameters,
+but returns a (possibly empty) list of vendor-specific B<Build-Depends>.
+
+=item builtin-build-conflicts ()
+
+The hook is called when dpkg-checkbuilddeps is initializing the source
+package build conflicts (since dpkg 1.18.2). It takes no parameters,
+but returns a (possibly empty) list of vendor-specific B<Build-Conflicts>.
+
+=item register-custom-fields ()
+
+The hook is called in Dpkg::Control::Fields to register custom fields.
+You should return a list of arrays. Each array is an operation to perform.
+The first item is the name of the operation and corresponds
+to a field_* function provided by Dpkg::Control::Fields. The remaining
+fields are the parameters that are passed unchanged to the corresponding
+function.
+
+Known operations are "register", "insert_after" and "insert_before".
+
+=item post-process-changelog-entry ($fields)
+
+The hook is called in Dpkg::Changelog to post-process a
+Dpkg::Changelog::Entry after it has been created and filled with the
+appropriate values.
+
+=item update-buildflags ($flags)
+
+The hook is called in Dpkg::BuildFlags to allow the vendor to override
+the default values set for the various build flags. $flags is a
+Dpkg::BuildFlags object.
+
+=item builtin-system-build-paths ()
+
+The hook is called by dpkg-genbuildinfo to determine if the current path
+should be recorded in the B<Build-Path> field (since dpkg 1.18.11). It takes
+no parameters, but returns a (possibly empty) list of root paths considered
+acceptable. As an example, if the list contains "/build/", a Build-Path
+field will be created if the current directory is "/build/dpkg-1.18.0". If
+the list contains "/", the path will always be recorded. If the list is
+empty, the current path will never be recorded.
+
+=item build-tainted-by ()
+
+The hook is called by dpkg-genbuildinfo to determine if the current system
+has been tainted in some way that could affect the resulting build, which
+will be recorded in the B<Build-Tainted-By> field (since dpkg 1.19.5). It
+takes no parameters, but returns a (possibly empty) list of tainted reason
+tags (formed by alphanumeric and dash characters).
+
+=back
+
+=cut
+
+sub run_hook {
+ my ($self, $hook, @params) = @_;
+
+ if ($hook eq 'before-source-build') {
+ my $srcpkg = shift @params;
+ } elsif ($hook eq 'keyrings') {
+ warnings::warnif('deprecated', 'obsolete keyrings vendor hook');
+ return ();
+ } elsif ($hook eq 'package-keyrings') {
+ return ();
+ } elsif ($hook eq 'archive-keyrings') {
+ return ();
+ } elsif ($hook eq 'archive-keyrings-historic') {
+ return ();
+ } elsif ($hook eq 'register-custom-fields') {
+ return ();
+ } elsif ($hook eq 'builtin-build-depends') {
+ return ();
+ } elsif ($hook eq 'builtin-build-conflicts') {
+ return ();
+ } elsif ($hook eq 'post-process-changelog-entry') {
+ my $fields = shift @params;
+ } elsif ($hook eq 'extend-patch-header') {
+ my ($textref, $ch_info) = @params;
+ } elsif ($hook eq 'update-buildflags') {
+ my $flags = shift @params;
+ } elsif ($hook eq 'builtin-system-build-paths') {
+ return ();
+ } elsif ($hook eq 'build-tainted-by') {
+ return ();
+ }
+
+ # Default return value for unknown/unimplemented hooks
+ return;
+}
+
+=back
+
+=head1 CHANGES
+
+=head2 Version 0.xx
+
+This is a private module.
+
+=cut
+
+1;
diff --git a/scripts/Dpkg/Vendor/Ubuntu.pm b/scripts/Dpkg/Vendor/Ubuntu.pm
new file mode 100644
index 0000000..e6335c2
--- /dev/null
+++ b/scripts/Dpkg/Vendor/Ubuntu.pm
@@ -0,0 +1,165 @@
+# Copyright © 2008 Ian Jackson <ijackson@chiark.greenend.org.uk>
+# Copyright © 2008 Canonical, Ltd.
+# written by Colin Watson <cjwatson@ubuntu.com>
+# Copyright © 2008 James Westby <jw+debian@jameswestby.net>
+# Copyright © 2009 Raphaël Hertzog <hertzog@debian.org>
+#
+# 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, see <https://www.gnu.org/licenses/>.
+
+package Dpkg::Vendor::Ubuntu;
+
+use strict;
+use warnings;
+
+our $VERSION = '0.01';
+
+use Dpkg::ErrorHandling;
+use Dpkg::Gettext;
+use Dpkg::Control::Types;
+
+use parent qw(Dpkg::Vendor::Debian);
+
+=encoding utf8
+
+=head1 NAME
+
+Dpkg::Vendor::Ubuntu - Ubuntu vendor object
+
+=head1 DESCRIPTION
+
+This vendor object customizes the behaviour of dpkg scripts for Ubuntu
+specific behavior and policies.
+
+=cut
+
+sub run_hook {
+ my ($self, $hook, @params) = @_;
+
+ if ($hook eq 'before-source-build') {
+ my $src = shift @params;
+ my $fields = $src->{fields};
+
+ # check that Maintainer/XSBC-Original-Maintainer comply to
+ # https://wiki.ubuntu.com/DebianMaintainerField
+ if (defined($fields->{'Version'}) and defined($fields->{'Maintainer'}) and
+ $fields->{'Version'} =~ /ubuntu/) {
+ if ($fields->{'Maintainer'} !~ /ubuntu/i) {
+ if (length $ENV{DEBEMAIL} and $ENV{DEBEMAIL} =~ /\@ubuntu\.com/) {
+ error(g_('Version number suggests Ubuntu changes, but Maintainer: does not have Ubuntu address'));
+ } else {
+ warning(g_('Version number suggests Ubuntu changes, but Maintainer: does not have Ubuntu address'));
+ }
+ }
+ unless ($fields->{'Original-Maintainer'}) {
+ warning(g_('Version number suggests Ubuntu changes, but there is no XSBC-Original-Maintainer field'));
+ }
+ }
+
+ } elsif ($hook eq 'keyrings') {
+ return $self->run_hook('package-keyrings', @params);
+ } elsif ($hook eq 'package-keyrings') {
+ return ($self->SUPER::run_hook($hook),
+ '/usr/share/keyrings/ubuntu-archive-keyring.gpg');
+ } elsif ($hook eq 'archive-keyrings') {
+ return ($self->SUPER::run_hook($hook),
+ '/usr/share/keyrings/ubuntu-archive-keyring.gpg');
+ } elsif ($hook eq 'archive-keyrings-historic') {
+ return ($self->SUPER::run_hook($hook),
+ '/usr/share/keyrings/ubuntu-archive-removed-keys.gpg');
+ } elsif ($hook eq 'register-custom-fields') {
+ my @field_ops = $self->SUPER::run_hook($hook);
+ push @field_ops,
+ [ 'register', 'Launchpad-Bugs-Fixed',
+ CTRL_FILE_CHANGES | CTRL_CHANGELOG ],
+ [ 'insert_after', CTRL_FILE_CHANGES, 'Closes', 'Launchpad-Bugs-Fixed' ],
+ [ 'insert_after', CTRL_CHANGELOG, 'Closes', 'Launchpad-Bugs-Fixed' ];
+ return @field_ops;
+
+ } elsif ($hook eq 'post-process-changelog-entry') {
+ my $fields = shift @params;
+
+ # Add Launchpad-Bugs-Fixed field
+ my $bugs = find_launchpad_closes($fields->{'Changes'} // '');
+ if (scalar(@$bugs)) {
+ $fields->{'Launchpad-Bugs-Fixed'} = join(' ', @$bugs);
+ }
+
+ } elsif ($hook eq 'update-buildflags') {
+ my $flags = shift @params;
+
+ # Run the Debian hook to add hardening flags
+ $self->SUPER::run_hook($hook, $flags);
+
+ require Dpkg::BuildOptions;
+
+ my $build_opts = Dpkg::BuildOptions->new();
+
+ if (!$build_opts->has('noopt')) {
+ require Dpkg::Arch;
+
+ my $arch = Dpkg::Arch::get_host_arch();
+ if (Dpkg::Arch::debarch_eq($arch, 'ppc64el')) {
+ for my $flag (qw(CFLAGS CXXFLAGS OBJCFLAGS OBJCXXFLAGS GCJFLAGS
+ FFLAGS FCFLAGS)) {
+ my $value = $flags->get($flag);
+ $value =~ s/-O[0-9]/-O3/;
+ $flags->set($flag, $value);
+ }
+ }
+ }
+ # Per https://wiki.ubuntu.com/DistCompilerFlags
+ $flags->prepend('LDFLAGS', '-Wl,-Bsymbolic-functions');
+ } else {
+ return $self->SUPER::run_hook($hook, @params);
+ }
+
+}
+
+=head1 PUBLIC FUNCTIONS
+
+=over
+
+=item $bugs = Dpkg::Vendor::Ubuntu::find_launchpad_closes($changes)
+
+Takes one string as argument and finds "LP: #123456, #654321" statements,
+which are references to bugs on Launchpad. Returns all closed bug
+numbers in an array reference.
+
+=cut
+
+sub find_launchpad_closes {
+ my $changes = shift;
+ my %closes;
+
+ while ($changes &&
+ ($changes =~ /lp:\s+\#\d+(?:,\s*\#\d+)*/pig)) {
+ $closes{$_} = 1 foreach (${^MATCH} =~ /\#?\s?(\d+)/g);
+ }
+
+ my @closes = sort { $a <=> $b } keys %closes;
+
+ return \@closes;
+}
+
+=back
+
+=head1 CHANGES
+
+=head2 Version 0.xx
+
+This is a semi-private module. Only documented functions are public.
+
+=cut
+
+1;