forked from josch/mmdebstrap
use distro-info-data and debootstrap to help with suite name and keyring discovery
This commit is contained in:
parent
7c532d5572
commit
dd64e8220d
1 changed files with 277 additions and 124 deletions
401
mmdebstrap
401
mmdebstrap
|
@ -37,7 +37,7 @@ use Cwd qw(abs_path);
|
||||||
require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
||||||
use Fcntl qw(S_IFCHR S_IFBLK FD_CLOEXEC F_GETFD F_SETFD);
|
use Fcntl qw(S_IFCHR S_IFBLK FD_CLOEXEC F_GETFD F_SETFD);
|
||||||
use List::Util qw(any none);
|
use List::Util qw(any none);
|
||||||
use POSIX qw(SIGINT SIGHUP SIGPIPE SIGTERM SIG_BLOCK SIG_UNBLOCK);
|
use POSIX qw(SIGINT SIGHUP SIGPIPE SIGTERM SIG_BLOCK SIG_UNBLOCK strftime);
|
||||||
use Carp;
|
use Carp;
|
||||||
use Term::ANSIColor;
|
use Term::ANSIColor;
|
||||||
use Socket;
|
use Socket;
|
||||||
|
@ -3322,6 +3322,275 @@ sub hooklistener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# parse files of the format found in /usr/share/distro-info/ and return two
|
||||||
|
# lists: the first contains codenames of end-of-life distros and the second
|
||||||
|
# list contains codenames of currently active distros
|
||||||
|
sub parse_distro_info {
|
||||||
|
my $file = shift;
|
||||||
|
my @eol = ();
|
||||||
|
my @current = ();
|
||||||
|
my $today = POSIX::strftime "%Y-%m-%d", localtime;
|
||||||
|
open my $fh, '<', $file or error "cannot open $file: $!";
|
||||||
|
my $i = 0;
|
||||||
|
while (my $line = <$fh>) {
|
||||||
|
chomp($line);
|
||||||
|
$i++;
|
||||||
|
my @cells = split /,/, $line;
|
||||||
|
if (scalar @cells < 4) {
|
||||||
|
error "cannot parse line $i of $file";
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
$i == 1
|
||||||
|
and ( scalar @cells < 6
|
||||||
|
or $cells[0] ne 'version'
|
||||||
|
or $cells[1] ne 'codename'
|
||||||
|
or $cells[2] ne 'series'
|
||||||
|
or $cells[3] ne 'created'
|
||||||
|
or $cells[4] ne 'release'
|
||||||
|
or $cells[5] ne 'eol')
|
||||||
|
) {
|
||||||
|
error "cannot find correct header in $file";
|
||||||
|
}
|
||||||
|
if ($i == 1) {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if (scalar @cells == 6) {
|
||||||
|
if ($cells[5] !~ m/^\d\d\d\d-\d\d-\d\d$/) {
|
||||||
|
error "invalid eof date format in $file:$i: $cells[5]";
|
||||||
|
}
|
||||||
|
# since the date format is iso8601, we can use lexicographic string
|
||||||
|
# comparison to compare dates
|
||||||
|
if ($cells[5] lt $today) {
|
||||||
|
push @eol, $cells[2];
|
||||||
|
} else {
|
||||||
|
push @current, $cells[2];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push @current, $cells[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close $fh;
|
||||||
|
return ([@eol], [@current]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_suite_by_vendor {
|
||||||
|
my %suite_by_vendor = (
|
||||||
|
'debian' => {},
|
||||||
|
'ubuntu' => {},
|
||||||
|
'tanglu' => {},
|
||||||
|
'kali' => {},
|
||||||
|
);
|
||||||
|
|
||||||
|
# pre-fill with some known values
|
||||||
|
foreach my $suite (
|
||||||
|
'potato', 'woody', 'sarge', 'etch',
|
||||||
|
'lenny', 'squeeze', 'wheezy', 'jessie'
|
||||||
|
) {
|
||||||
|
$suite_by_vendor{'debian'}->{$suite} = 1;
|
||||||
|
}
|
||||||
|
foreach my $suite (
|
||||||
|
'unstable', 'stable', 'oldstable', 'stretch',
|
||||||
|
'buster', 'bullseye', 'bookworm'
|
||||||
|
) {
|
||||||
|
$suite_by_vendor{'debian'}->{$suite} = 0;
|
||||||
|
}
|
||||||
|
foreach my $suite ('aequorea', 'bartholomea', 'chromodoris', 'dasyatis') {
|
||||||
|
$suite_by_vendor{'tanglu'}->{$suite} = 0;
|
||||||
|
}
|
||||||
|
foreach my $suite ('kali-dev', 'kali-rolling', 'kali-bleeding-edge') {
|
||||||
|
$suite_by_vendor{'kali'}->{$suite} = 0;
|
||||||
|
}
|
||||||
|
foreach
|
||||||
|
my $suite ('trusty', 'xenial', 'zesty', 'artful', 'bionic', 'cosmic') {
|
||||||
|
$suite_by_vendor{'ubuntu'}->{$suite} = 0;
|
||||||
|
}
|
||||||
|
# if the Debian package distro-info-data is installed, then we can use it,
|
||||||
|
# to get better data about new distros or EOL distros
|
||||||
|
if (-e '/usr/share/distro-info/debian.csv') {
|
||||||
|
my ($eol, $current)
|
||||||
|
= parse_distro_info('/usr/share/distro-info/debian.csv');
|
||||||
|
foreach my $suite (@{$eol}) {
|
||||||
|
$suite_by_vendor{'debian'}->{$suite} = 1;
|
||||||
|
}
|
||||||
|
foreach my $suite (@{$current}) {
|
||||||
|
$suite_by_vendor{'debian'}->{$suite} = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-e '/usr/share/distro-info/ubuntu.csv') {
|
||||||
|
my ($eol, $current)
|
||||||
|
= parse_distro_info('/usr/share/distro-info/ubuntu.csv');
|
||||||
|
foreach my $suite (@{$eol}, @{$current}) {
|
||||||
|
$suite_by_vendor{'ubuntu'}->{$suite} = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# if debootstrap is installed we infer distro names from the symlink
|
||||||
|
# targets of the scripts in /usr/share/debootstrap/scripts/
|
||||||
|
my $debootstrap_scripts = '/usr/share/debootstrap/scripts/';
|
||||||
|
if (-d $debootstrap_scripts) {
|
||||||
|
opendir(my $dh, $debootstrap_scripts)
|
||||||
|
or error "Can't opendir($debootstrap_scripts): $!";
|
||||||
|
while (my $suite = readdir $dh) {
|
||||||
|
# this is only a heuristic -- don't overwrite anything but instead
|
||||||
|
# just update anything that was missing
|
||||||
|
if (!-l "$debootstrap_scripts/$suite") {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
my $target = readlink "$debootstrap_scripts/$suite";
|
||||||
|
if ($target eq "sid"
|
||||||
|
and not exists $suite_by_vendor{'debian'}->{$suite}) {
|
||||||
|
$suite_by_vendor{'debian'}->{$suite} = 0;
|
||||||
|
} elsif ($target eq "gutsy"
|
||||||
|
and not exists $suite_by_vendor{'ubuntu'}->{$suite}) {
|
||||||
|
$suite_by_vendor{'ubuntu'}->{$suite} = 0;
|
||||||
|
} elsif ($target eq "aequorea"
|
||||||
|
and not exists $suite_by_vendor{'tanglu'}->{$suite}) {
|
||||||
|
$suite_by_vendor{'tanglu'}->{$suite} = 0;
|
||||||
|
} elsif ($target eq "kali"
|
||||||
|
and not exists $suite_by_vendor{'kali'}->{$suite}) {
|
||||||
|
$suite_by_vendor{'kali'}->{$suite} = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir($dh);
|
||||||
|
}
|
||||||
|
|
||||||
|
return %suite_by_vendor;
|
||||||
|
}
|
||||||
|
|
||||||
|
# try to guess the right keyring path for the given suite
|
||||||
|
sub get_keyring_by_suite {
|
||||||
|
my $query = shift;
|
||||||
|
my $suite_by_vendor = shift;
|
||||||
|
|
||||||
|
my $debianvendor;
|
||||||
|
my $ubuntuvendor;
|
||||||
|
eval {
|
||||||
|
require Dpkg::Vendor::Debian;
|
||||||
|
require Dpkg::Vendor::Ubuntu;
|
||||||
|
$debianvendor = Dpkg::Vendor::Debian->new();
|
||||||
|
$ubuntuvendor = Dpkg::Vendor::Ubuntu->new();
|
||||||
|
};
|
||||||
|
|
||||||
|
my $keyring_by_vendor = sub {
|
||||||
|
my $vendor = shift;
|
||||||
|
my $eol = shift;
|
||||||
|
if ($vendor eq 'debian') {
|
||||||
|
if ($eol) {
|
||||||
|
if (defined $debianvendor) {
|
||||||
|
return $debianvendor->run_hook(
|
||||||
|
'archive-keyrings-historic');
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
'/usr/share/keyrings/debian-archive-removed-keys.gpg';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (defined $debianvendor) {
|
||||||
|
return $debianvendor->run_hook('archive-keyrings');
|
||||||
|
} else {
|
||||||
|
return '/usr/share/keyrings/debian-archive-keyring.gpg';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif ($vendor eq 'ubuntu') {
|
||||||
|
if (defined $ubuntuvendor) {
|
||||||
|
return $ubuntuvendor->run_hook('archive-keyrings');
|
||||||
|
} else {
|
||||||
|
return '/usr/share/keyrings/ubuntu-archive-keyring.gpg';
|
||||||
|
}
|
||||||
|
} elsif ($vendor eq 'tanglu') {
|
||||||
|
return '/usr/share/keyrings/tanglu-archive-keyring.gpg';
|
||||||
|
} elsif ($vendor eq 'kali') {
|
||||||
|
return '/usr/share/keyrings/kali-archive-keyring.gpg';
|
||||||
|
} else {
|
||||||
|
error "unknown vendor: $vendor";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
my %keyrings = ();
|
||||||
|
foreach my $vendor (keys %{$suite_by_vendor}) {
|
||||||
|
foreach my $suite (keys %{ $suite_by_vendor->{$vendor} }) {
|
||||||
|
my $keyring = $keyring_by_vendor->(
|
||||||
|
$vendor, $suite_by_vendor->{$vendor}->{$suite});
|
||||||
|
debug "suite $suite with keyring $keyring";
|
||||||
|
$keyrings{$suite} = $keyring;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exists $keyrings{$query}) {
|
||||||
|
return $keyrings{$query};
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_sourceslist_by_suite {
|
||||||
|
my $suite = shift;
|
||||||
|
my $arch = shift;
|
||||||
|
my $signedby = shift;
|
||||||
|
my $compstr = shift;
|
||||||
|
my $suite_by_vendor = shift;
|
||||||
|
|
||||||
|
my @debstable = keys %{ $suite_by_vendor->{'debian'} };
|
||||||
|
my @ubuntustable = keys %{ $suite_by_vendor->{'ubuntu'} };
|
||||||
|
my @tanglustable = keys %{ $suite_by_vendor->{'tanglu'} };
|
||||||
|
my @kali = keys %{ $suite_by_vendor->{'kali'} };
|
||||||
|
|
||||||
|
my $mirror = 'http://deb.debian.org/debian';
|
||||||
|
my $secmirror = 'http://security.debian.org/debian-security';
|
||||||
|
if (any { $_ eq $suite } @ubuntustable) {
|
||||||
|
if (any { $_ eq $arch } ('amd64', 'i386')) {
|
||||||
|
$mirror = 'http://archive.ubuntu.com/ubuntu';
|
||||||
|
$secmirror = 'http://security.ubuntu.com/ubuntu';
|
||||||
|
} else {
|
||||||
|
$mirror = 'http://ports.ubuntu.com/ubuntu-ports';
|
||||||
|
$secmirror = 'http://ports.ubuntu.com/ubuntu-ports';
|
||||||
|
}
|
||||||
|
if (-e '/usr/share/debootstrap/scripts/gutsy') {
|
||||||
|
# try running the debootstrap script but ignore errors
|
||||||
|
my $script = 'set -eu;
|
||||||
|
default_mirror() { echo $1; };
|
||||||
|
mirror_style() { :; };
|
||||||
|
download_style() { :; };
|
||||||
|
finddebs_style() { :; };
|
||||||
|
variants() { :; };
|
||||||
|
keyring() { :; };
|
||||||
|
doing_variant() { false; };
|
||||||
|
. /usr/share/debootstrap/scripts/gutsy;';
|
||||||
|
open my $fh, '-|', 'env', "ARCH=$arch", "SUITE=$suite",
|
||||||
|
'sh', '-c', $script // last;
|
||||||
|
chomp(
|
||||||
|
my $output = do { local $/; <$fh> }
|
||||||
|
);
|
||||||
|
close $fh;
|
||||||
|
if ($? == 0 && $output ne '') {
|
||||||
|
$mirror = $output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elsif (any { $_ eq $suite } @tanglustable) {
|
||||||
|
$mirror = 'http://archive.tanglu.org/tanglu';
|
||||||
|
} elsif (any { $_ eq $suite } @kali) {
|
||||||
|
$mirror = 'https://http.kali.org/kali';
|
||||||
|
}
|
||||||
|
my $sourceslist = '';
|
||||||
|
$sourceslist .= "deb$signedby $mirror $suite $compstr\n";
|
||||||
|
if (any { $_ eq $suite } @ubuntustable) {
|
||||||
|
$sourceslist .= "deb$signedby $mirror $suite-updates $compstr\n";
|
||||||
|
$sourceslist .= "deb$signedby $secmirror $suite-security $compstr\n";
|
||||||
|
} elsif (any { $_ eq $suite } @tanglustable) {
|
||||||
|
$sourceslist .= "deb$signedby $secmirror $suite-updates $compstr\n";
|
||||||
|
} elsif (any { $_ eq $suite } @debstable
|
||||||
|
and none { $_ eq $suite } ('testing', 'unstable', 'sid')) {
|
||||||
|
$sourceslist .= "deb$signedby $mirror $suite-updates $compstr\n";
|
||||||
|
if (any { $_ eq $suite } ('bullseye')) {
|
||||||
|
# starting from bullseye use
|
||||||
|
# https://lists.debian.org/87r26wqr2a.fsf@43-1.org
|
||||||
|
$sourceslist
|
||||||
|
.= "deb$signedby $secmirror $suite-security" . " $compstr\n";
|
||||||
|
} else {
|
||||||
|
$sourceslist
|
||||||
|
.= "deb$signedby $secmirror $suite/updates" . " $compstr\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $sourceslist;
|
||||||
|
}
|
||||||
|
|
||||||
sub guess_sources_format {
|
sub guess_sources_format {
|
||||||
my $content = shift;
|
my $content = shift;
|
||||||
my $is_deb822 = 0;
|
my $is_deb822 = 0;
|
||||||
|
@ -3989,70 +4258,11 @@ sub main() {
|
||||||
# if the currently selected apt keyrings do not contain the
|
# if the currently selected apt keyrings do not contain the
|
||||||
# necessary key material for the chosen suite, then attempt adding
|
# necessary key material for the chosen suite, then attempt adding
|
||||||
# a signed-by option
|
# a signed-by option
|
||||||
my $signedby = '';
|
my $signedby = '';
|
||||||
|
my %suite_by_vendor = get_suite_by_vendor();
|
||||||
{
|
{
|
||||||
# try to guess the right keyring path for the given suite
|
my $keyring = get_keyring_by_suite($suite, \%suite_by_vendor);
|
||||||
my $debianvendor;
|
if (!defined $keyring) {
|
||||||
my $ubuntuvendor;
|
|
||||||
eval {
|
|
||||||
require Dpkg::Vendor::Debian;
|
|
||||||
require Dpkg::Vendor::Ubuntu;
|
|
||||||
$debianvendor = Dpkg::Vendor::Debian->new();
|
|
||||||
$ubuntuvendor = Dpkg::Vendor::Ubuntu->new();
|
|
||||||
};
|
|
||||||
my $keyring;
|
|
||||||
if (
|
|
||||||
any { $_ eq $suite } (
|
|
||||||
'potato', 'woody', 'sarge', 'etch',
|
|
||||||
'lenny', 'squeeze', 'wheezy'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if (defined $debianvendor) {
|
|
||||||
$keyring = $debianvendor->run_hook(
|
|
||||||
'archive-keyrings-historic');
|
|
||||||
} else {
|
|
||||||
$keyring
|
|
||||||
= '/usr/share/keyrings/'
|
|
||||||
. 'debian-archive-removed-keys.gpg';
|
|
||||||
}
|
|
||||||
} elsif (
|
|
||||||
any { $_ eq $suite }
|
|
||||||
('aequorea', 'bartholomea', 'chromodoris', 'dasyatis')
|
|
||||||
) {
|
|
||||||
$keyring
|
|
||||||
= '/usr/share/keyrings/tanglu-archive-keyring.gpg';
|
|
||||||
} elsif (
|
|
||||||
any { $_ eq $suite }
|
|
||||||
('kali-dev', 'kali-rolling', 'kali-bleeding-edge')
|
|
||||||
) {
|
|
||||||
$keyring = '/usr/share/keyrings/kali-archive-keyring.gpg';
|
|
||||||
} elsif (
|
|
||||||
any { $_ eq $suite } (
|
|
||||||
'trusty', 'xenial', 'zesty', 'artful', 'bionic',
|
|
||||||
'cosmic'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if (defined $ubuntuvendor) {
|
|
||||||
$keyring = $ubuntuvendor->run_hook('archive-keyrings');
|
|
||||||
} else {
|
|
||||||
$keyring
|
|
||||||
= '/usr/share/keyrings/'
|
|
||||||
. 'ubuntu-archive-keyring.gpg';
|
|
||||||
}
|
|
||||||
} elsif (
|
|
||||||
any { $_ eq $suite } (
|
|
||||||
'unstable', 'stable', 'oldstable', 'jessie',
|
|
||||||
'stretch', 'buster', 'bullseye', 'bookworm'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if (defined $debianvendor) {
|
|
||||||
$keyring = $debianvendor->run_hook('archive-keyrings');
|
|
||||||
} else {
|
|
||||||
$keyring
|
|
||||||
= '/usr/share/keyrings/'
|
|
||||||
. 'debian-archive-keyring.gpg';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4248,66 +4458,9 @@ sub main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
my @debstable = (
|
my $sourceslist
|
||||||
'oldoldstable', 'oldstable', 'stable', 'jessie',
|
= get_sourceslist_by_suite($suite, $options->{nativearch},
|
||||||
'stretch', 'buster', 'bullseye', 'bookworm'
|
$signedby, $compstr, \%suite_by_vendor);
|
||||||
);
|
|
||||||
my @ubuntustable
|
|
||||||
= ('trusty', 'xenial', 'zesty', 'artful', 'bionic',
|
|
||||||
'cosmic');
|
|
||||||
my @tanglustable
|
|
||||||
= ('aequorea', 'bartholomea', 'chromodoris', 'dasyatis');
|
|
||||||
my @kali = ('kali-dev', 'kali-rolling', 'kali-bleeding-edge');
|
|
||||||
|
|
||||||
my $mirror = 'http://deb.debian.org/debian';
|
|
||||||
my $secmirror = 'http://security.debian.org/debian-security';
|
|
||||||
if (any { $_ eq $suite } @ubuntustable) {
|
|
||||||
if (
|
|
||||||
any { $_ eq $options->{nativearch} }
|
|
||||||
('amd64', 'i386')
|
|
||||||
) {
|
|
||||||
$mirror = 'http://archive.ubuntu.com/ubuntu';
|
|
||||||
$secmirror = 'http://security.ubuntu.com/ubuntu';
|
|
||||||
} else {
|
|
||||||
$mirror = 'http://ports.ubuntu.com/ubuntu-ports';
|
|
||||||
$secmirror = 'http://ports.ubuntu.com/ubuntu-ports';
|
|
||||||
}
|
|
||||||
} elsif (any { $_ eq $suite } @tanglustable) {
|
|
||||||
$mirror = 'http://archive.tanglu.org/tanglu';
|
|
||||||
} elsif (any { $_ eq $suite } @kali) {
|
|
||||||
$mirror = 'https://http.kali.org/kali';
|
|
||||||
}
|
|
||||||
my $sourceslist = '';
|
|
||||||
$sourceslist .= "deb$signedby $mirror $suite $compstr\n";
|
|
||||||
if (any { $_ eq $suite } @ubuntustable) {
|
|
||||||
$sourceslist
|
|
||||||
.= "deb$signedby $mirror $suite-updates $compstr\n";
|
|
||||||
$sourceslist
|
|
||||||
.= "deb$signedby $secmirror $suite-security $compstr\n";
|
|
||||||
} elsif (any { $_ eq $suite } @tanglustable) {
|
|
||||||
$sourceslist
|
|
||||||
.= "deb$signedby $secmirror $suite-updates $compstr\n";
|
|
||||||
} elsif (any { $_ eq $suite } @debstable) {
|
|
||||||
$sourceslist
|
|
||||||
.= "deb$signedby $mirror $suite-updates $compstr\n";
|
|
||||||
if (
|
|
||||||
any { $_ eq $suite } (
|
|
||||||
'oldoldstable', 'oldstable',
|
|
||||||
'stable', 'jessie',
|
|
||||||
'stretch', 'buster'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
$sourceslist
|
|
||||||
.= "deb$signedby $secmirror $suite/updates"
|
|
||||||
. " $compstr\n";
|
|
||||||
} else {
|
|
||||||
# starting from bullseye use
|
|
||||||
# https://lists.debian.org/87r26wqr2a.fsf@43-1.org
|
|
||||||
$sourceslist
|
|
||||||
.= "deb$signedby $secmirror $suite-security"
|
|
||||||
. " $compstr\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
push @{$sourceslists},
|
push @{$sourceslists},
|
||||||
{
|
{
|
||||||
type => 'one-line',
|
type => 'one-line',
|
||||||
|
|
Loading…
Reference in a new issue