From aa2cfef40b026feba2157bb4f9d9abe68d42c1bf Mon Sep 17 00:00:00 2001 From: Johannes 'josch' Schauer Date: Sat, 24 Dec 2016 13:04:06 +0100 Subject: [PATCH] introduce main() function and remove 36 global variables --- multistrap | 932 +++++++++++++++++++++++++++-------------------------- 1 file changed, 477 insertions(+), 455 deletions(-) diff --git a/multistrap b/multistrap index d7955cd..dd68449 100755 --- a/multistrap +++ b/multistrap @@ -1,6 +1,7 @@ #!/usr/bin/perl -# Copyright (C) 2009-2011 Neil Williams +# Copyright (C) 2009-2015 Neil Williams +# Copyright (C) 2015-2017 Johannes Schauer # # This package is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -26,475 +27,472 @@ use POSIX qw(locale_h); use Locale::gettext; use File::Copy; -use vars qw/ $progname $ourversion $dstrap $extra @aptsources - $deb $cachedir $config_str %packages $retval $str $retries - $dir $include $arch $foreign $url $unpack $sourcedir $msg $etcdir - @e $sourcesname $libdir $dpkgdir @debootstrap %suites %components $chk - $repo @dirs @touch %sources $section %keys $host $key $value $preffile - $type $file $config $tidy $noauth $keyring %keyrings $deflist $cfgdir - @extrapkgs @includes %source $setupsh $configsh $omitrequired $dryrun - $omitpreinst @reinstall $tgzname %required $check @check - $explicit_suite $allow_recommends %omitdebsrc @dsclist @sectoutput - %flatfile %important $addimportant @debconf $hookdir %hooks - $warn_count $use_shortcut @foreignarches $olddpkg $ignorenative - %foreignpkgs $markauto $default_release $pre_config_str/; +main(); -setlocale(LC_MESSAGES, ""); -textdomain("multistrap"); -$progname = basename($0); -$ourversion = &our_version(); -$default_release = "*"; -$unpack = "true"; -%omitdebsrc=(); -%foreignpkgs=(); -while( @ARGV ) { - $_= shift( @ARGV ); - last if m/^--$/; - if (!/^-/) { - unshift(@ARGV,$_); - last; - } elsif (/^(-\?|-h|--help|--version)$/) { - &usageversion(); - exit( 0 ); - } elsif (/^(-s|--shortcut)$/) { - $use_shortcut = shift(@ARGV); - } elsif (/^(-f|--file)$/) { - $file = shift(@ARGV); - } elsif (/^(-a|--arch)$/) { - $arch = shift(@ARGV); - } elsif (/^(-d|--dir)$/) { - $dir = shift(@ARGV); - $dir .= ($dir =~ m:/$:) ? '' : "/"; - } elsif (/^(--tidy-up)$/) { - $tidy++; - } elsif (/^(--source-dir)$/) { - $sourcedir = shift (@ARGV); - $sourcedir .= ($sourcedir =~ m:/$:) ? '' : "/"; - $sourcedir = (-d $sourcedir) ? $sourcedir : undef; - } elsif (/^(--no-auth)$/) { - $noauth++; - } elsif (/^(--dry-run|--simulate)$/) { - $dryrun++; - } else { - die "$progname: "._g("Unknown option")." $_.\n"; - } -} -if (defined $use_shortcut) { - my $short = "/usr/share/multistrap/".$use_shortcut.".conf"; - $file = $short if (-f $short); - $short = "/etc/multistrap.d/".$use_shortcut.".conf"; - $file = $short if (-f $short); -} -$msg = sprintf (_g("Need a configuration file - use %s -f\n"), $progname); -die ($msg) - if (not defined $file); -undef ($msg); +sub main { + use vars qw/ @aptsources %packages $str $retries $dir $arch $foreign + $unpack $sourcedir @debootstrap %suites %components %sources %keys $host + $preffile $file $tidy $noauth %keyrings $deflist @extrapkgs @includes + $setupsh $configsh $omitrequired $omitpreinst @reinstall $tgzname @check + $explicit_suite $allow_recommends %omitdebsrc @dsclist %flatfile + %important $addimportant @debconf %hooks $warn_count @foreignarches + $olddpkg $ignorenative $markauto $default_release/; -$cachedir = "var/cache/apt/"; # archives -$libdir = "var/lib/apt/"; # lists -$etcdir = "etc/apt/"; # sources -$dpkgdir = "var/lib/dpkg/"; # state + setlocale(LC_MESSAGES, ""); + textdomain("multistrap"); + my $progname = basename($0); + my $ourversion = &our_version(); + $default_release = "*"; + $unpack = "true"; + %omitdebsrc=(); + my $dryrun; + my $use_shortcut; + while( @ARGV ) { + $_= shift( @ARGV ); + last if m/^--$/; + if (!/^-/) { + unshift(@ARGV,$_); + last; + } elsif (/^(-\?|-h|--help|--version)$/) { + &usageversion(); + exit( 0 ); + } elsif (/^(-s|--shortcut)$/) { + $use_shortcut = shift(@ARGV); + } elsif (/^(-f|--file)$/) { + $file = shift(@ARGV); + } elsif (/^(-a|--arch)$/) { + $arch = shift(@ARGV); + } elsif (/^(-d|--dir)$/) { + $dir = shift(@ARGV); + $dir .= ($dir =~ m:/$:) ? '' : "/"; + } elsif (/^(--tidy-up)$/) { + $tidy++; + } elsif (/^(--source-dir)$/) { + $sourcedir = shift (@ARGV); + $sourcedir .= ($sourcedir =~ m:/$:) ? '' : "/"; + $sourcedir = (-d $sourcedir) ? $sourcedir : undef; + } elsif (/^(--no-auth)$/) { + $noauth++; + } elsif (/^(--dry-run|--simulate)$/) { + $dryrun++; + } else { + die "$progname: "._g("Unknown option")." $_.\n"; + } + } + if (defined $use_shortcut) { + my $short = "/usr/share/multistrap/".$use_shortcut.".conf"; + $file = $short if (-f $short); + $short = "/etc/multistrap.d/".$use_shortcut.".conf"; + $file = $short if (-f $short); + } + if (not defined $file) { + die (sprintf (_g("Need a configuration file - use %s -f\n"), $progname)); + } -$cfgdir=dirname($file); -cascade($file); + my $cachedir = "var/cache/apt/"; # archives + my $libdir = "var/lib/apt/"; # lists + my $etcdir = "etc/apt/"; # sources + my $dpkgdir = "var/lib/dpkg/"; # state + + my $cfgdir=dirname($file); + cascade($file); # Translators: fields are programname, version string, include file. -printf (_g("%s %s using %s\n"), $progname, $ourversion, $file); -$host = `dpkg --print-architecture`; -chomp($host); -foreach my $inc (@includes) { - cascade($inc); -} -if (defined $omitrequired and defined $addimportant) { - warn("\n"._g("Error: Cannot set 'add Priority: important' when packages ". - "of 'Priority: required' are being omitted.\n")); - if (scalar @includes > 0) { - my $plural = ngettext("Please also check the included configuration file:", - "Please also check the included configuration files:", scalar @includes); - warn (sprintf("%s '%s'\n", $plural, join ("', '", sort @includes))); - } - if (defined $dryrun) { - warn("\n"); - &dump_config; - exit 0; - } - exit (7); -} -uniq_sort (\@debootstrap); -uniq_sort (\@aptsources); -if (defined $dryrun) { - &dump_config; - exit 0; -} + printf (_g("%s %s using %s\n"), $progname, $ourversion, $file); + $host = `dpkg --print-architecture`; + chomp($host); + foreach my $inc (@includes) { + cascade($inc); + } + if (defined $omitrequired and defined $addimportant) { + warn("\n"._g("Error: Cannot set 'add Priority: important' when packages ". + "of 'Priority: required' are being omitted.\n")); + if (scalar @includes > 0) { + my $plural = ngettext("Please also check the included configuration file:", + "Please also check the included configuration files:", scalar @includes); + warn (sprintf("%s '%s'\n", $plural, join ("', '", sort @includes))); + } + if (defined $dryrun) { + warn("\n"); + &dump_config; + exit 0; + } + exit (7); + } + uniq_sort (\@debootstrap); + uniq_sort (\@aptsources); + if (defined $dryrun) { + &dump_config; + exit 0; + } # Translators: fields are: programname, versionstring, configfile. -printf (_g("%s %s using %s\n"), $progname, $ourversion, $file); -if ((not defined $arch) or ($arch eq "")) { - $arch = $host; - printf (_g("Defaulting architecture to native: %s\n"),$arch); -} elsif ($arch eq $host) { - printf (_g("Defaulting architecture to native: %s\n"),$arch); -} else { - printf (_g("Using foreign architecture: %s\n"), $arch); -} -$foreign++ if (($host ne $arch) or (defined $ignorenative)); -if (not defined $dir or not defined $arch) { - &dump_config; - exit 3; -} -unless (keys %sources) { - my $msg = sprintf(_g("No sources defined for a foreign multistrap. - Using your existing apt sources. To use different sources, - list them with aptsources= in '%s'."), $file); - warn ("$progname: $msg\n"); - $warn_count++; - my $l = prepare_sources_list(); - $deflist = join ("", @$l); -} + printf (_g("%s %s using %s\n"), $progname, $ourversion, $file); + if ((not defined $arch) or ($arch eq "")) { + $arch = $host; + printf (_g("Defaulting architecture to native: %s\n"),$arch); + } elsif ($arch eq $host) { + printf (_g("Defaulting architecture to native: %s\n"),$arch); + } else { + printf (_g("Using foreign architecture: %s\n"), $arch); + } + $foreign++ if (($host ne $arch) or (defined $ignorenative)); + if (not defined $dir or not defined $arch) { + &dump_config; + exit 3; + } + unless (keys %sources) { + my $msg = sprintf(_g("No sources defined for a foreign multistrap. + Using your existing apt sources. To use different sources, + list them with aptsources= in '%s'."), $file); + warn ("$progname: $msg\n"); + $warn_count++; + my $l = prepare_sources_list(); + $deflist = join ("", @$l); + } # Translators: fields are: programname, architecture, host architecture. -printf (_g("%s building %s multistrap on '%s'\n"), $progname, $arch, $host); -if ($dir =~ /^$/) { - my $msg = _g("No directory specified!"); - die "$progname: $msg\n"; -} -&mkdir_fatal ($dir); -$dir = realpath ($dir); -$dir .= ($dir =~ m:/$:) ? '' : "/"; -system_fatal ("mkdir -p " . shellescape("${dir}${cachedir}")) if (not -d "${dir}${cachedir}"); -system_fatal ("mkdir -p " . shellescape("${dir}${libdir}")) if (not -d "${dir}${libdir}"); -system_fatal ("mkdir -p " . shellescape("${dir}${dpkgdir}")) if (not -d "${dir}${dpkgdir}"); -system_fatal ("mkdir -p " . shellescape("${dir}etc/apt/sources.list.d/")) - if (not -d "${dir}etc/apt/sources.list.d/"); -system_fatal ("mkdir -p " . shellescape("${dir}etc/apt/trusted.gpg.d/")) - if (not -d "${dir}etc/apt/trusted.gpg.d/"); -system_fatal ("mkdir -p " . shellescape("${dir}etc/apt/preferences.d/")) - if (not -d "${dir}etc/apt/preferences.d/"); -system_fatal ("mkdir -p " . shellescape("${dir}usr/share/info/")) - if (not -d "${dir}usr/share/info/"); -system_fatal ("touch " . shellescape("${dir}usr/share/info/dir")); -if (defined $preffile) { - open (PREF, "$preffile") or die ("$progname: $preffile $!"); - my @prefs=; - close (PREF); - my $name = basename($preffile); - open (MPREF, ">${dir}etc/apt/preferences.d/$name") or die ("$progname: $name $!"); - print MPREF @prefs; - close (MPREF); -} -@dirs = qw/ alternatives info parts updates /; -@touch = qw/ arch diversions statoverride status lock/; -foreach my $dpkgd (@dirs) { - if (not -d "${dir}${dpkgdir}$dpkgd") { - mkdir_fatal ("${dir}${dpkgdir}$dpkgd"); - } -} -foreach my $file (@touch) { - utime(time, time, "${dir}${dpkgdir}/$file") or ( - open(F, ">${dir}${dpkgdir}/$file") && close F ); -} -utime(time, time, "${dir}etc/shells") or - (open(F, ">${dir}etc/shells") && close F ); + printf (_g("%s building %s multistrap on '%s'\n"), $progname, $arch, $host); + if ($dir =~ /^$/) { + my $msg = _g("No directory specified!"); + die "$progname: $msg\n"; + } + &mkdir_fatal ($dir); + $dir = realpath ($dir); + $dir .= ($dir =~ m:/$:) ? '' : "/"; + system_fatal ("mkdir -p " . shellescape("${dir}${cachedir}")) if (not -d "${dir}${cachedir}"); + system_fatal ("mkdir -p " . shellescape("${dir}${libdir}")) if (not -d "${dir}${libdir}"); + system_fatal ("mkdir -p " . shellescape("${dir}${dpkgdir}")) if (not -d "${dir}${dpkgdir}"); + system_fatal ("mkdir -p " . shellescape("${dir}etc/apt/sources.list.d/")) + if (not -d "${dir}etc/apt/sources.list.d/"); + system_fatal ("mkdir -p " . shellescape("${dir}etc/apt/trusted.gpg.d/")) + if (not -d "${dir}etc/apt/trusted.gpg.d/"); + system_fatal ("mkdir -p " . shellescape("${dir}etc/apt/preferences.d/")) + if (not -d "${dir}etc/apt/preferences.d/"); + system_fatal ("mkdir -p " . shellescape("${dir}usr/share/info/")) + if (not -d "${dir}usr/share/info/"); + system_fatal ("touch " . shellescape("${dir}usr/share/info/dir")); + if (defined $preffile) { + open (PREF, "$preffile") or die ("$progname: $preffile $!"); + my @prefs=; + close (PREF); + my $name = basename($preffile); + open (MPREF, ">${dir}etc/apt/preferences.d/$name") or die ("$progname: $name $!"); + print MPREF @prefs; + close (MPREF); + } + my @dirs = qw/ alternatives info parts updates /; + my @touch = qw/ arch diversions statoverride status lock/; + foreach my $dpkgd (@dirs) { + if (not -d "${dir}${dpkgdir}$dpkgd") { + mkdir_fatal ("${dir}${dpkgdir}$dpkgd"); + } + } + foreach my $file (@touch) { + utime(time, time, "${dir}${dpkgdir}/$file") or ( + open(F, ">${dir}${dpkgdir}/$file") && close F ); + } + utime(time, time, "${dir}etc/shells") or + (open(F, ">${dir}etc/shells") && close F ); -if (not -d "${dir}etc/network") { - mkdir_fatal ("${dir}etc/network"); -} + if (not -d "${dir}etc/network") { + mkdir_fatal ("${dir}etc/network"); + } -if (not -d "${dir}dev") { - mkdir_fatal ("${dir}dev"); -} -if (($olddpkg == 0) and (scalar (@foreignarches) > 0)) { - open (VMA, ">${dir}${dpkgdir}arch"); - print VMA "$host\n"; - foreach my $farch (@foreignarches) { - print VMA "$farch\n"; - } - close (VMA); -} + if (not -d "${dir}dev") { + mkdir_fatal ("${dir}dev"); + } + if (($olddpkg == 0) and (scalar (@foreignarches) > 0)) { + open (VMA, ">${dir}${dpkgdir}arch"); + print VMA "$host\n"; + foreach my $farch (@foreignarches) { + print VMA "$farch\n"; + } + close (VMA); + } -&guard_lib64($dir); + &guard_lib64($dir); -system_fatal ("rm -rf " . shellescape("${dir}etc/apt/sources.list.d") . "/*"); -unlink ("${dir}etc/apt/sources.list") - if (-f "${dir}etc/apt/sources.list"); + system_fatal ("rm -rf " . shellescape("${dir}etc/apt/sources.list.d") . "/*"); + unlink ("${dir}etc/apt/sources.list") + if (-f "${dir}etc/apt/sources.list"); -foreach $repo (sort keys %suites) { - if (not -e "${dir}${cachedir}") { - mkdir_fatal ("${dir}${cachedir}"); - } - if (not -e "$dir/${libdir}lists") { - mkdir_fatal ("$dir/${libdir}lists"); - } - if (not -e "$dir/${libdir}lists/partial") { - mkdir_fatal ("$dir/${libdir}lists/partial"); - } - if (not -e "$dir/${cachedir}archives") { - mkdir_fatal ("$dir/${cachedir}archives"); - } - if (not -e "$dir/${cachedir}archives/partial") { - mkdir_fatal ("$dir/${cachedir}archives/partial"); - } - if (not -e "${dir}${etcdir}apt.conf.d") { - mkdir_fatal ("${dir}${etcdir}apt.conf.d"); - } -} -foreach my $aptsrc (@debootstrap) { - if (defined $deflist) { - open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap.sources.list") - or die _g("Cannot open sources list"). $!; - print SOURCES $deflist; - close SOURCES; - } elsif (-d "${dir}etc/apt/") { - open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap-${aptsrc}.list") - or die _g("Cannot open sources list"). $!; - my $mirror = $sources{$aptsrc}; - my $suite = (exists $flatfile{$aptsrc}) ? "" : $suites{$aptsrc}; - my $component = (exists $flatfile{$aptsrc}) ? "" - : (defined $components{$aptsrc}) ? $components{$aptsrc} : "main"; - if (defined $mirror and defined $suite) { - if ($olddpkg != 0) { - print SOURCES "deb $mirror $suite $component\n"; - } else { - if (scalar (@foreignarches) == 0) { - print SOURCES "deb [arch=$arch] $mirror $suite $component\n"; - } else { - foreach my $farch (@foreignarches) { - print SOURCES "deb [arch=$farch] $mirror $suite $component\n"; - } - } - } - print SOURCES "deb-src $mirror $suite $component\n" if (not defined $omitdebsrc{$aptsrc}); - close SOURCES; - } - } -} -my $k; -foreach my $pkg (values %keyrings) { - next if (not defined $pkg); - next if ("" eq "$pkg"); - $k .= "$pkg "; -} -if ((defined $k) and (not defined $noauth)) { - printf (_g("I: Downloading %s\n"), $k); - system ("apt-get -y download $k"); - foreach my $keyring_pkg (values %keyrings) { - next if (not defined $keyring_pkg); - my @files=(); - my $file = `find ./ -name "${keyring_pkg}_*_all.deb"|grep -m1 $keyring_pkg`; - chomp ($file); - if ($file eq "") { - my $msg = sprintf (_g("Unable to download keyring package: '%s'"),$dir); - die "$progname: $msg\n"; - } - my $xdir = `mktemp -d -t keyring.XXXXXX`; - chomp ($xdir); - system ("dpkg -X $file $xdir >/dev/null"); - if (-d "${xdir}/usr/share/keyrings") { - opendir (DIR, "${xdir}/usr/share/keyrings"); - @files=grep(!m:\.\.?$:,readdir DIR); - closedir (DIR); - } - foreach my $gpg (@files) { - next if ($gpg =~ /removed/); - File::Copy::copy "${xdir}/usr/share/keyrings/${gpg}", "${dir}${etcdir}trusted.gpg.d/"; - } - system ("rm -rf ${xdir}"); - unlink ($file); - } -} + foreach my $repo (sort keys %suites) { + if (not -e "${dir}${cachedir}") { + mkdir_fatal ("${dir}${cachedir}"); + } + if (not -e "$dir/${libdir}lists") { + mkdir_fatal ("$dir/${libdir}lists"); + } + if (not -e "$dir/${libdir}lists/partial") { + mkdir_fatal ("$dir/${libdir}lists/partial"); + } + if (not -e "$dir/${cachedir}archives") { + mkdir_fatal ("$dir/${cachedir}archives"); + } + if (not -e "$dir/${cachedir}archives/partial") { + mkdir_fatal ("$dir/${cachedir}archives/partial"); + } + if (not -e "${dir}${etcdir}apt.conf.d") { + mkdir_fatal ("${dir}${etcdir}apt.conf.d"); + } + } + foreach my $aptsrc (@debootstrap) { + if (defined $deflist) { + open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap.sources.list") + or die _g("Cannot open sources list"). $!; + print SOURCES $deflist; + close SOURCES; + } elsif (-d "${dir}etc/apt/") { + open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap-${aptsrc}.list") + or die _g("Cannot open sources list"). $!; + my $mirror = $sources{$aptsrc}; + my $suite = (exists $flatfile{$aptsrc}) ? "" : $suites{$aptsrc}; + my $component = (exists $flatfile{$aptsrc}) ? "" + : (defined $components{$aptsrc}) ? $components{$aptsrc} : "main"; + if (defined $mirror and defined $suite) { + if ($olddpkg != 0) { + print SOURCES "deb $mirror $suite $component\n"; + } else { + if (scalar (@foreignarches) == 0) { + print SOURCES "deb [arch=$arch] $mirror $suite $component\n"; + } else { + foreach my $farch (@foreignarches) { + print SOURCES "deb [arch=$farch] $mirror $suite $component\n"; + } + } + } + print SOURCES "deb-src $mirror $suite $component\n" if (not defined $omitdebsrc{$aptsrc}); + close SOURCES; + } + } + } + my $k; + foreach my $pkg (values %keyrings) { + next if (not defined $pkg); + next if ("" eq "$pkg"); + $k .= "$pkg "; + } + if ((defined $k) and (not defined $noauth)) { + printf (_g("I: Downloading %s\n"), $k); + system ("apt-get -y download $k"); + foreach my $keyring_pkg (values %keyrings) { + next if (not defined $keyring_pkg); + my @files=(); + my $file = `find ./ -name "${keyring_pkg}_*_all.deb"|grep -m1 $keyring_pkg`; + chomp ($file); + if ($file eq "") { + my $msg = sprintf (_g("Unable to download keyring package: '%s'"),$dir); + die "$progname: $msg\n"; + } + my $xdir = `mktemp -d -t keyring.XXXXXX`; + chomp ($xdir); + system ("dpkg -X $file $xdir >/dev/null"); + if (-d "${xdir}/usr/share/keyrings") { + opendir (DIR, "${xdir}/usr/share/keyrings"); + @files=grep(!m:\.\.?$:,readdir DIR); + closedir (DIR); + } + foreach my $gpg (@files) { + next if ($gpg =~ /removed/); + File::Copy::copy "${xdir}/usr/share/keyrings/${gpg}", "${dir}${etcdir}trusted.gpg.d/"; + } + system ("rm -rf ${xdir}"); + unlink ($file); + } + } -$pre_config_str = ''; -$pre_config_str .= "Dir::Etc \"${dir}${etcdir}\";\n"; -$pre_config_str .= "Dir::Etc::Parts \"${dir}${etcdir}apt.conf.d/\";\n"; -$pre_config_str .= "Dir::Etc::PreferencesParts \"${dir}${etcdir}preferences.d/\";\n"; + my $pre_config_str = ''; + $pre_config_str .= "Dir::Etc \"${dir}${etcdir}\";\n"; + $pre_config_str .= "Dir::Etc::Parts \"${dir}${etcdir}apt.conf.d/\";\n"; + $pre_config_str .= "Dir::Etc::PreferencesParts \"${dir}${etcdir}preferences.d/\";\n"; -my $tmp_apt_conf = `mktemp -t multistrap.XXXXXX`; -chomp ($tmp_apt_conf); + my $tmp_apt_conf = `mktemp -t multistrap.XXXXXX`; + chomp ($tmp_apt_conf); -open CONFIG, ">$tmp_apt_conf"; -print CONFIG $pre_config_str; -close CONFIG; + open CONFIG, ">$tmp_apt_conf"; + print CONFIG $pre_config_str; + close CONFIG; -$config_str = ''; -$config_str .= " -o Apt::Architecture=" . shellescape($arch); -$config_str .= " -o Dir::Etc::TrustedParts=" . shellescape("${dir}${etcdir}trusted.gpg.d"); -$config_str .= " -o Dir::Etc::Trusted=" . shellescape("${dir}${etcdir}trusted.gpg"); -$config_str .= " -o Apt::Get::AllowUnauthenticated=true" - if (defined $noauth); -$config_str .= " -o Apt::Get::Download-Only=true"; -$config_str .= " -o Apt::Install-Recommends=false" - if (not defined $allow_recommends); -$config_str .= " -o Dir=" . shellescape($dir); -$config_str .= " -o Dir::Etc=" . shellescape("${dir}${etcdir}"); -$config_str .= " -o Dir::Etc::Parts=" . shellescape("${dir}${etcdir}apt.conf.d/"); -$config_str .= " -o Dir::Etc::PreferencesParts=" . shellescape("${dir}${etcdir}preferences.d/"); -$config_str .= " -o APT::Default-Release=" . shellescape($default_release); + my $config_str = ''; + $config_str .= " -o Apt::Architecture=" . shellescape($arch); + $config_str .= " -o Dir::Etc::TrustedParts=" . shellescape("${dir}${etcdir}trusted.gpg.d"); + $config_str .= " -o Dir::Etc::Trusted=" . shellescape("${dir}${etcdir}trusted.gpg"); + $config_str .= " -o Apt::Get::AllowUnauthenticated=true" + if (defined $noauth); + $config_str .= " -o Apt::Get::Download-Only=true"; + $config_str .= " -o Apt::Install-Recommends=false" + if (not defined $allow_recommends); + $config_str .= " -o Dir=" . shellescape($dir); + $config_str .= " -o Dir::Etc=" . shellescape("${dir}${etcdir}"); + $config_str .= " -o Dir::Etc::Parts=" . shellescape("${dir}${etcdir}apt.conf.d/"); + $config_str .= " -o Dir::Etc::PreferencesParts=" . shellescape("${dir}${etcdir}preferences.d/"); + $config_str .= " -o APT::Default-Release=" . shellescape($default_release); # if (not defined $preffile); -if (defined $deflist) { - $sourcesname = "sources.list.d/multistrap.sources.list"; - $config_str .= " -o Dir::Etc::SourceList=" . shellescape("${dir}${etcdir}$sourcesname"); -} -$config_str .= " -o Dir::State=" . shellescape("${dir}${libdir}"); -$config_str .= " -o Dir::State::Status=" . shellescape("${dir}${dpkgdir}status"); -$config_str .= " -o Dir::Cache=" . shellescape("${dir}${cachedir}"); + if (defined $deflist) { + my $sourcesname = "sources.list.d/multistrap.sources.list"; + $config_str .= " -o Dir::Etc::SourceList=" . shellescape("${dir}${etcdir}$sourcesname"); + } + $config_str .= " -o Dir::State=" . shellescape("${dir}${libdir}"); + $config_str .= " -o Dir::State::Status=" . shellescape("${dir}${dpkgdir}status"); + $config_str .= " -o Dir::Cache=" . shellescape("${dir}${cachedir}"); -my $apt_get = "APT_CONFIG=" . shellescape($tmp_apt_conf) . " apt-get $config_str"; -my $apt_mark = "APT_CONFIG=" . shellescape($tmp_apt_conf) . " apt-mark $config_str"; -printf (_g("Getting package lists: %s update\n"), $apt_get); + my $apt_get = "APT_CONFIG=" . shellescape($tmp_apt_conf) . " apt-get $config_str"; + my $apt_mark = "APT_CONFIG=" . shellescape($tmp_apt_conf) . " apt-mark $config_str"; + printf (_g("Getting package lists: %s update\n"), $apt_get); -$retval = system ("$apt_get update"); -$retval >>= 8; -die (sprintf (_g("apt update failed. Exit value: %d\n"), $retval)) - if ($retval != 0); -my @s = (); -$str = ""; -if (not defined $omitrequired) { - print _g("I: Calculating required packages.\n"); - &get_required_debs; - $str .= join (' ', keys %required); - if (defined $addimportant) { - my $imps = join (' ', sort keys %important); - printf(_g("I: Adding 'Priority: important': %s\n"), $imps); - $str .= " ".$imps; - } - chomp($str); -} -$str .= " "; -foreach my $sect (sort keys %packages) { - my @list = split (' ', $sect); - foreach my $pkg (@list) { - next if ($packages{$pkg} =~ /^\s*$/); - next if (!(grep(/^$sect$/i, @debootstrap))); - my @long=split (/ /, $packages{$sect}); - foreach my $l (@long) { - chomp ($l); - if (defined $explicit_suite and $suites{$sect}) { - # instruct apt to get packages from the specified - # suites (when the package exists in more than one). - $str .= " $l/$suites{$sect}" if ((defined $l) and ($l !~ /^\s*$/)); - } else { - $str .= " $l" if ((defined $l) and ($l !~ /^\s*$/)); - } - } - } -} -chomp($str); -foreach my $keystr (values %keyrings) { - next if (not defined $keystr); - $str .= " " . $keystr . " "; -} -chomp($str); -@s = split (/ /, $str); -uniq_sort (\@s); -$str = join (' ', @s); -print "$apt_get -y install $str\n"; -$retval = 0; -$retval = system ("$apt_get -y install $str"); -$retval >>= 8; -die (sprintf (_g("apt download failed. Exit value: %d\n"),$retval)) - if ($retval != 0); -&force_unpack if ($unpack eq "true"); -&mark_manual_install ($str) if (defined $markauto); -system ("touch " . shellescape("${dir}${libdir}lists/lock")); -if ((defined $setupsh) and (-x $setupsh)) { - $retval = 0; - $retval = system (shellescape($setupsh) . " " . shellescape($dir) . " $arch"); - $retval >>= 8; - if ($retval != 0) { - warn sprintf(_g("setupscript '%s' returned %d.\n"), $setupsh, $retval); - $warn_count++; - } -} + my $retval = system ("$apt_get update"); + $retval >>= 8; + die (sprintf (_g("apt update failed. Exit value: %d\n"), $retval)) + if ($retval != 0); + my @s = (); + $str = ""; + if (not defined $omitrequired) { + print _g("I: Calculating required packages.\n"); + my %required = &get_required_debs($libdir); + $str .= join (' ', keys %required); + if (defined $addimportant) { + my $imps = join (' ', sort keys %important); + printf(_g("I: Adding 'Priority: important': %s\n"), $imps); + $str .= " ".$imps; + } + chomp($str); + } + $str .= " "; + foreach my $sect (sort keys %packages) { + my @list = split (' ', $sect); + foreach my $pkg (@list) { + next if ($packages{$pkg} =~ /^\s*$/); + next if (!(grep(/^$sect$/i, @debootstrap))); + my @long=split (/ /, $packages{$sect}); + foreach my $l (@long) { + chomp ($l); + if (defined $explicit_suite and $suites{$sect}) { + # instruct apt to get packages from the specified + # suites (when the package exists in more than one). + $str .= " $l/$suites{$sect}" if ((defined $l) and ($l !~ /^\s*$/)); + } else { + $str .= " $l" if ((defined $l) and ($l !~ /^\s*$/)); + } + } + } + } + chomp($str); + foreach my $keystr (values %keyrings) { + next if (not defined $keystr); + $str .= " " . $keystr . " "; + } + chomp($str); + @s = split (/ /, $str); + uniq_sort (\@s); + $str = join (' ', @s); + print "$apt_get -y install $str\n"; + $retval = 0; + $retval = system ("$apt_get -y install $str"); + $retval >>= 8; + die (sprintf (_g("apt download failed. Exit value: %d\n"),$retval)) + if ($retval != 0); + &force_unpack($cachedir, $libdir, $dpkgdir) if ($unpack eq "true"); + &mark_manual_install ($apt_mark, $cachedir, $str) if (defined $markauto); + system ("touch " . shellescape("${dir}${libdir}lists/lock")); + if ((defined $setupsh) and (-x $setupsh)) { + $retval = 0; + $retval = system (shellescape($setupsh) . " " . shellescape($dir) . " $arch"); + $retval >>= 8; + if ($retval != 0) { + warn sprintf(_g("setupscript '%s' returned %d.\n"), $setupsh, $retval); + $warn_count++; + } + } # run first set of hooks - probably unnecessary re setupscript. -&run_download_hooks(sort @{$hooks{'D'}}) if (defined $hooks{'D'}); -my $err = &native if (not defined ($foreign) and $unpack eq "true"); -if (defined $err and $err != 0) { - warn (_g("Native mode configuration reported an error!\n")); - $warn_count++; -} -&add_extra_packages; -system ("cp " . shellescape($configsh) . " " . shellescape("$dir/")) if ((defined $configsh) and (-f $configsh)); -&handle_source_packages; -(not defined $tidy) ? system ("$apt_get update") : &tidy_apt; -&guard_lib64($dir); + &run_download_hooks(sort @{$hooks{'D'}}) if (defined $hooks{'D'}); + my $err = &native if (not defined ($foreign) and $unpack eq "true"); + if (defined $err and $err != 0) { + warn (_g("Native mode configuration reported an error!\n")); + $warn_count++; + } + &add_extra_packages($apt_get, $cachedir, $libdir, $dpkgdir); + system ("cp " . shellescape($configsh) . " " . shellescape("$dir/")) if ((defined $configsh) and (-f $configsh)); + &handle_source_packages($apt_get, $cachedir, $dpkgdir); + (not defined $tidy) ? system ("$apt_get update") : &tidy_apt($cachedir, $libdir); + &guard_lib64($dir); # cleanly separate the bootstrap sources from the final apt sources. -unlink ("${dir}etc/apt/sources.list.d/multistrap.sources.list") - if (-f "${dir}etc/apt/sources.list.d/multistrap.sources.list"); -opendir (LISTS, "${dir}etc/apt/sources.list.d/") - or die (_g("Cannot read apt sources list directory.\n")); -my @sources=grep(m:^multistrap-.*\.list$:, readdir LISTS); -closedir (LISTS); -foreach my $filelist (@sources) { - next if (-d $filelist); - unlink ("${dir}etc/apt/sources.list.d/$filelist"); -} -foreach my $aptsrc (@aptsources) { - if (defined $deflist) { - open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap.sources.list") - or die _g("Cannot open sources list"). $!; - print SOURCES $deflist; - close SOURCES; - } elsif (-d "${dir}etc/apt/") { - open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap-${aptsrc}.list") - or die _g("Cannot open sources list"). $!; - my $mirror = $sources{$aptsrc}; - my $suite = (exists $flatfile{$aptsrc}) ? "" : $suites{$aptsrc}; - my $component = (exists $flatfile{$aptsrc}) ? "" - : (defined $components{$aptsrc}) ? $components{$aptsrc} : "main"; - if (defined $mirror and defined $suite) { - if ($olddpkg != 0) { - print SOURCES "deb $mirror $suite $component\n"; - } else { - if (scalar (@foreignarches) == 0) { - print SOURCES "deb [arch=$arch] $mirror $suite $component\n"; - } else { - foreach my $farch (@foreignarches) { - print SOURCES "deb [arch=$farch] $mirror $suite $component\n"; - } - } - } - print SOURCES "deb-src $mirror $suite $component\n" if (not defined $omitdebsrc{$aptsrc}); - close SOURCES; - } - } -} + unlink ("${dir}etc/apt/sources.list.d/multistrap.sources.list") + if (-f "${dir}etc/apt/sources.list.d/multistrap.sources.list"); + opendir (LISTS, "${dir}etc/apt/sources.list.d/") + or die (_g("Cannot read apt sources list directory.\n")); + my @sources=grep(m:^multistrap-.*\.list$:, readdir LISTS); + closedir (LISTS); + foreach my $filelist (@sources) { + next if (-d $filelist); + unlink ("${dir}etc/apt/sources.list.d/$filelist"); + } + foreach my $aptsrc (@aptsources) { + if (defined $deflist) { + open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap.sources.list") + or die _g("Cannot open sources list"). $!; + print SOURCES $deflist; + close SOURCES; + } elsif (-d "${dir}etc/apt/") { + open (SOURCES, ">>${dir}etc/apt/sources.list.d/multistrap-${aptsrc}.list") + or die _g("Cannot open sources list"). $!; + my $mirror = $sources{$aptsrc}; + my $suite = (exists $flatfile{$aptsrc}) ? "" : $suites{$aptsrc}; + my $component = (exists $flatfile{$aptsrc}) ? "" + : (defined $components{$aptsrc}) ? $components{$aptsrc} : "main"; + if (defined $mirror and defined $suite) { + if ($olddpkg != 0) { + print SOURCES "deb $mirror $suite $component\n"; + } else { + if (scalar (@foreignarches) == 0) { + print SOURCES "deb [arch=$arch] $mirror $suite $component\n"; + } else { + foreach my $farch (@foreignarches) { + print SOURCES "deb [arch=$farch] $mirror $suite $component\n"; + } + } + } + print SOURCES "deb-src $mirror $suite $component\n" if (not defined $omitdebsrc{$aptsrc}); + close SOURCES; + } + } + } # altered the sources, so get apt to update. -(not defined $tidy) ? system ("$apt_get update") : &tidy_apt; + (not defined $tidy) ? system ("$apt_get update") : &tidy_apt($cachedir, $libdir); # run second set of hooks -&run_completion_hooks(sort @{$hooks{'A'}}) if (defined ($hooks{'A'})); -unlink $tmp_apt_conf; -if (not defined $warn_count) { - printf (_g("\nMultistrap system installed successfully in %s.\n"), $dir); -} else { - my $plural = sprintf(ngettext ("\nMultistrap system reported %d error in %s.\n", - "\nMultistrap system reported %d errors in %s.\n", $warn_count), $warn_count, $dir); - warn ($plural); - $warn_count++; + &run_completion_hooks(sort @{$hooks{'A'}}) if (defined ($hooks{'A'})); + unlink $tmp_apt_conf; + if (not defined $warn_count) { + printf (_g("\nMultistrap system installed successfully in %s.\n"), $dir); + } else { + my $plural = sprintf(ngettext ("\nMultistrap system reported %d error in %s.\n", + "\nMultistrap system reported %d errors in %s.\n", $warn_count), $warn_count, $dir); + warn ($plural); + $warn_count++; + } + if (defined $tgzname) { + printf (_g("\nCompressing multistrap system in '%s' to a tarball called: '%s'.\n"), $dir, $tgzname); + chdir ("$dir"); + unlink $tgzname if (-f $tgzname); + my $retval = system ("tar -czf " . shellescape("../$tgzname .")); + $retval >>= 8; + if ($retval == 0) { + printf (_g("\nRemoving build directory: '%s'\n"), $dir); + system ("rm -rf " . shellescape($dir) . "/*"); + } + my $final_path=realpath ("$dir/../$tgzname"); + if (not defined $warn_count) { + printf (_g("\nMultistrap system packaged successfully as '%s'.\n"), $final_path); + } else { + warn sprintf(_g("\nMultistrap system packaged as '%s' with warnings.\n"), $final_path); + } + } + print "\n"; + if (not defined $warn_count) { + exit 0; + } else { + exit $warn_count; + } } -if (defined $tgzname) { - printf (_g("\nCompressing multistrap system in '%s' to a tarball called: '%s'.\n"), $dir, $tgzname); - chdir ("$dir"); - unlink $tgzname if (-f $tgzname); - my $retval = system ("tar -czf " . shellescape("../$tgzname .")); - $retval >>= 8; - if ($retval == 0) { - printf (_g("\nRemoving build directory: '%s'\n"), $dir); - system ("rm -rf " . shellescape($dir) . "/*"); - } - my $final_path=realpath ("$dir/../$tgzname"); - if (not defined $warn_count) { - printf (_g("\nMultistrap system packaged successfully as '%s'.\n"), $final_path); - } else { - warn sprintf(_g("\nMultistrap system packaged as '%s' with warnings.\n"), $final_path); - } -} -print "\n"; -if (not defined $warn_count) { - exit 0; -} else { - exit $warn_count; -} - -######### sub routine start ########## # avoid dependency on String::ShellQuote by implementing the mechanism # from python's shlex.quote function @@ -520,17 +518,23 @@ sub our_version { } sub add_extra_packages { + my $apt_get = shift; + my $cachedir = shift; + my $libdir = shift; + my $dpkgdir = shift; if (scalar @extrapkgs > 0) { $str = join (' ', @extrapkgs); print "$apt_get -y install $str\n"; system ("$apt_get -y install $str"); - &force_unpack (@extrapkgs) if ($unpack eq "true"); + &force_unpack ($cachedir, $libdir, $dpkgdir, @extrapkgs) if ($unpack eq "true"); system ("touch " . shellescape("${dir}${libdir}lists/lock")); &native if (not defined ($foreign)); } } sub mark_manual_install { + my $apt_mark = shift; + my $cachedir = shift; my @manual = split(/ +/, $_[0]); printf (_g("Marking automatically installed packages... please wait\n")); opendir (DEBS, "${dir}${cachedir}archives/") @@ -550,6 +554,9 @@ sub mark_manual_install { } sub force_unpack { + my $cachedir = shift; + my $libdir = shift; + my $dpkgdir = shift; my (@limits) = @_; my %unpack=(); my %filter = (); @@ -568,7 +575,7 @@ sub force_unpack { @archives = sort values %filter; } print _g("I: Calculating obsolete packages\n"); - foreach $deb (sort @archives) { + foreach my $deb (sort @archives) { my $escaped_path = shellescape("${dir}${cachedir}archives/$deb"); my $version = `LC_ALL=C dpkg -f $escaped_path Version`; my $package = `LC_ALL=C dpkg -f $escaped_path Package`; @@ -604,7 +611,7 @@ sub force_unpack { chomp ($old); chdir ("${dir}"); printf (_g("Using directory %s for unpacking operations\n"), $dir); - foreach $deb (sort @archives) { + foreach my $deb (sort @archives) { printf (_g("I: Extracting %s...\n"), $deb); my $escaped_path = shellescape("./${cachedir}archives/$deb"); my $ver=`LC_ALL=C dpkg -f $escaped_path Version`; @@ -851,6 +858,9 @@ sub check_bin_sh { } sub handle_source_packages { + my $apt_get = shift; + my $cachedir = shift; + my $dpkgdir = shift; return if (not defined $sourcedir); if ($unpack eq "true") { opendir (DEBS, "${dir}${cachedir}/archives/") @@ -911,6 +921,8 @@ sub handle_source_packages { } sub tidy_apt { + my $cachedir = shift; + my $libdir = shift; print _g("I: Tidying up apt cache and list data.\n"); if ($unpack eq "true") { opendir (DEBS, "${dir}${cachedir}/archives/") @@ -1006,11 +1018,12 @@ sub native { } sub get_required_debs { + my $libdir = shift; # emulate required="$(get_debs Priority: required)" # from debootstrap/functions # needs to be run after the first apt-get install so that # Packages files exist - %required=(); + my %required=(); my %listfiles=(); opendir (PKGS, "${dir}${libdir}lists/") or die sprintf(_g("Cannot open %s directory. %s\n"), @@ -1039,6 +1052,7 @@ sub get_required_debs { } } } + return %required; } # inherited from apt-cross @@ -1070,6 +1084,8 @@ sub prepare_sources_list { } sub usageversion { + my $progname = basename($0); + my $ourversion = &our_version(); printf STDERR (_g(" %s version %s @@ -1143,19 +1159,22 @@ will be created - it is not packed into a .tgz once complete. } sub cascade { + my $progname = basename($0); $olddpkg = &check_multiarch_dpkg; $file = shift; my @req_arches=(); - $config = Config::Auto::parse($file, format => 'ini'); + my $config = Config::Auto::parse($file, format => 'ini'); if (not defined $config or (scalar keys %$config) == 0) { die ("$progname: ". sprintf(_g("Failed to parse '%s'!\n"), $file)); } - foreach $key (%$config) { + my $type; + my $value; + foreach my $key (%$config) { $type = lc($key) if (ref $key ne "HASH"); $value = $key if (ref $key eq "HASH"); $keys{$type} = $value; } - foreach $section (sort keys %keys) { + foreach my $section (sort keys %keys) { if ($section eq "general") { $arch = $keys{$section}{'arch'} if (defined $keys{$section}{'arch'} and (not defined $arch)); @@ -1247,7 +1266,8 @@ sub cascade { foreach my $inc (@i) { # look for the full filepath or try same directory as current conf. if (not -f $inc) { - $chk = realpath ("$cfgdir/$inc"); + my $cfgdir=dirname($file); + my $chk = realpath ("$cfgdir/$inc"); chomp ($chk) if (defined $chk); $inc = $chk if (-f $chk); } @@ -1258,7 +1278,7 @@ sub cascade { } push @includes, @i; } else { - $sources{$section}=$keys{$section}{'source'} if (not exists $source{$section}); + $sources{$section}=$keys{$section}{'source'}; # don't set suite or component if URL is of apt-ftparchive trailing-slash form # regexp is: optional string in '[]', string without '[' or ']', string ending in '/' $flatfile{$section}++ if (($sources{$section} =~ /^(\[.*\] )*[^\[\]]+ .+\/$/)); @@ -1343,6 +1363,7 @@ sub system_fatal { } sub mkdir_fatal { + my $progname = basename($0); my $d = shift; if (not -d "$d") { my $ret = system ("mkdir -p " . shellescape($d)); @@ -1366,8 +1387,9 @@ sub uniq_sort { } sub dump_config { + my $msg; if (not defined $dir or not defined $arch) { - my $msg = sprintf(_g("The supplied configuration file '%s'". + $msg = sprintf(_g("The supplied configuration file '%s'". " cannot be parsed correctly."), $file); warn ("\n$msg\n\n"); }