#!/usr/bin/perl -w # # rpmbootstrap application, a debootstrap like for RPM distros # # $Id$ # # Copyright B. Cornec 2010-today # Eric Anderson's changes are (c) Copyright 2012 Hewlett Packard # Provided under the GPL v2 # Syntax: see at end use strict 'vars'; use Getopt::Long qw(:config auto_abbrev no_ignore_case); use Data::Dumper; use English; use LWP::UserAgent; use File::Basename; use File::Copy; use File::Find; use ProjectBuilder::Version; use ProjectBuilder::Base; use ProjectBuilder::Env; use ProjectBuilder::Conf; use ProjectBuilder::Distribution; # Global variables my %opts; # CLI Options =pod =head1 NAME rpmbootstrap - creates a chrooted RPM based distribution a la debootstrap, aka Virtual Environment (VE) =head1 DESCRIPTION rpmbootstrap creates a chroot environment (Virtual Environment or VE) with a minimal distribution in it, suited for building packages for example. It's very much like debootstrap but for RPM based distribution. It aims at supporting all distributions supported by project-builder.org (RHEL, RH, Fedora, OpeSUSE, SLES, Mandriva, ...) It is inspired by work done by Steve Kemp for rinse (http://www.steve.org.uk/), and similar to mock or febootstrap, but fully integrated with project-builder.org (which also supports rinse and mock). Contrary to these, rpmbootstrap creates an environment where the packages commands are usable after build, as described hereafter. rpmbootstrap works in 2 phases. The first one is used to download all the required packages to have a working package management system in the chroot working. This list of packages is stored in /etc/pb/pb.yml under the rbsmindep parameter (aka rpmbootstrap minimal dependencies). Once the packages have been downloaded from the mirror, they are extracted with rpm2cpio. At that point you should be able to use yum on Fedora, urpmi on Mandriva/Mageia and zypper on OpenSuSE. The second phase uses exactly the previous mentioned tools to install exactly the same package list to have a coherent RPM db at the end. rpmbootstrap has additional options to execute a post-install script (-s) or to add packages (-a). Then pb can use the chroot to perform even more actions in it. =head1 SYNOPSIS rpmbootstrap [-vhmqpdk][-s script][-i image][-a pkg1[,pkg2,...]] distribution-version-arch [target-dir] [mirror [script]] rpmbootstrap [--verbose][--help][--man][--quiet][--print-rpms][--download-only] [--keep][--script script][--image image][--add pkg1,[pkg2,...]] distribution-version-arch [target-dir] [mirror [script]] =head1 OPTIONS =over 4 =item B<-v|--verbose> Print a brief help message and exits. =item B<-h|--help> Print a brief help message and exits. =item B<--man> Prints the manual page and exits. =item B<-q|--quiet> Do not print any output. =item B<-p|--print-rpms> Print the packages to be installed, and exit. Note that a target directory must be specified so rpmbootstrap can determine which packages should be installed, and to resolve dependencies. The target directory will be deleted. =item B<-d|--download-only> Download packages, but don't perform installation. =item B<-k|--keep> Keep packages in the cache dir for later reuse. By default remove them. =item B<-s|--script script> Name of the script you want to execute on the related VEs after the installation. It is executed in host environment. You can use the chroot command to execute actions in the VE. =item B<-i|--image image> Name of the ISO image or the docker image of the distribution you want to install on the related VE. =item B<-a|--add pkg1[,pkg2,...]> Additional packages to add from the distribution you want to install on the related VE at the end of the chroot build. =item B<--no-stop-on-error> Continue through errors with best effort. =back =head1 ARGUMENTS =over 4 =item B Full name of the distribution that needs to be installed in the VE. E.g. fedora-11-x86_64. =item B This is the target directory under which the VE will be created. Created on the fly if needed. If none is given use the default directory hosting VE for project-builder.org (Cf: vepath parameter in $HOME/.pbrc.yml) =back =head1 EXAMPLE To setup a Fedora 12 distribution with an i386 architecture issue: rpmbootstrap fedora-12-i386 /tmp/fedora/12/i386 =head1 WEB SITES The main Web site of the project is available at L. Bug reports should be filled using the trac instance of the project at L. =head1 USER MAILING LIST Cf: L for announces and L for the development of the pb project. =head1 CONFIGURATION FILE Uses Project-Builder.org configuration file (/etc/pb/pb.yml or /usr/local/etc/pb/pb.yml) =head1 AUTHORS The Project-Builder.org team L lead by Bruno Cornec L. =head1 COPYRIGHT Project-Builder.org is distributed under the GPL v2.0 license described in the file C included with the distribution. =cut # --------------------------------------------------------------------------- $Global::pb_stop_on_error = 1; my ($projectbuilderver,$projectbuilderrev) = pb_version_init(); my $appname = "rpmbootstrap"; $ENV{'PBPROJ'} = $appname; # Initialize the syntax string pb_syntax_init("$appname Version $projectbuilderver-$projectbuilderrev\n"); pb_temp_init(); pb_conf_init($appname); GetOptions("help|?|h" => \$opts{'h'}, "man|m" => \$opts{'man'}, "verbose|v+" => \$opts{'v'}, "quiet|q" => \$opts{'q'}, "log-files|l=s" => \$opts{'l'}, "script|s=s" => \$opts{'s'}, "print-rpms|p" => \$opts{'p'}, "download-only|d" => \$opts{'d'}, "keep|k" => \$opts{'k'}, "image|i=s" => \$opts{'i'}, "add|a=s" => \$opts{'a'}, "version|V=s" => \$opts{'V'}, "stop-on-error!" => \$Global::pb_stop_on_error, ) || pb_syntax(-1,0); if (defined $opts{'h'}) { pb_syntax(0,1); } if (defined $opts{'man'}) { pb_syntax(0,2); } if (defined $opts{'v'}) { $pbdebug = $opts{'v'}; } if (defined $opts{'q'}) { $pbdebug=-1; } if (defined $opts{'l'}) { open(pbLOG,"> $opts{'l'}") || die "Unable to log to $opts{'l'}: $!"; $pbLOG = \*pbLOG; $pbdebug = 0 if ($pbdebug == -1); } pb_log_init($pbdebug, $pbLOG); #pb_display_init("text",""); #if (defined $opts{'s'}) { #$pbscript = $opts{'s'}; #} #if (defined $opts{'i'}) { #$image = $opts{'i'}; #} # Get VE name $ENV{'PBV'} = shift @ARGV; die pb_syntax(-1,1) if (not defined $ENV{'PBV'}); die "Needs to be run as root" if ($EFFECTIVE_USER_ID != 0); # # Initialize distribution info from pb conf file # pb_log(0,"Starting VE build for $ENV{'PBV'}\n"); my $pbos = pb_distro_get_context($ENV{'PBV'}); # # Check target dir # Create if not existent and use default if none given # pb_env_init_pbrc(); # to get content of HOME/.pbrc.yml my $vepath = shift @ARGV; # # Check for command requirements # my ($req,$opt) = pb_conf_get_if("oscmd","oscmdopt"); pb_check_requirements($req,$opt,$appname); if (not defined $vepath) { my ($vestdpath) = pb_conf_get("vepath"); $vepath = pb_path_expand("$vestdpath->{'default'}/$pbos->{'name'}/$pbos->{'version'}/$pbos->{'arch'}") if (defined $vestdpath->{'default'}); } die pb_log(0,"No target-dir specified and no default vepath found in $ENV{'PBETC'}\n") if (not defined $vepath); # Cleanup first if ( -d $vepath) { pb_rm_rf($vepath); } pb_mkdir_p($vepath); # # Get the package list to download, store them in a cache directory # my ($rbscachedir) = pb_conf_get_if("cachedir"); my ($pkgs,$mirror) = pb_distro_get($pbos,("rbsmindep","rbsmirrorsrv")); my ($updater) = pb_distro_get_if($pbos,"rbsmirrorupd"); die "No packages defined for $pbos->{name}-$pbos->{version}-$pbos->{arch}" unless $pkgs =~ /\w/; my $cachedir = "/var/cache/rpmbootstrap"; $cachedir = $rbscachedir->{'default'} if (defined $rbscachedir->{'default'}); $cachedir = $rbscachedir->{$appname} if (defined $rbscachedir->{$appname}); # Point to the right subdir and create it if needed $cachedir .= "/$pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}"; pb_mkdir_p($cachedir) if (! -d $cachedir); # Get the complete package name from the mirror # my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; die "No mirror defined for $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}" if ((not defined $mirror) || ($mirror =~ /^\t*$/)); my $resp; my $repo; my %list_pkg; ($repo,$resp) = rbs_mirror_response($mirror); foreach my $r (split(/\n/,$resp->as_string())) { $list_pkg{$r} = $mirror; } # If an update source is availble add it after so that these pkgs update the main ones if (defined $updater) { my $void; ($void,$resp) = rbs_mirror_response($mirror.$updater); foreach my $r (split(/\n/,$resp->as_string())) { $list_pkg{$r} = $mirror.$updater; } } # Manages architectures specificities my $parch = $pbos->{'arch'}; $parch = "i[3456]86" if ($pbos->{'arch'} eq "i386"); # Get the list of packages and their URL in this hash my %url; my %done; foreach my $l (keys %list_pkg) { my ($url,$desc) = rbs_find_pkg($l,$parch,"pkg"); if (defined $url) { $url{$url} = "$list_pkg{$l}/$desc"; } else { pb_log(3,"not a package, maybe a dir containing packages\n"); ($url,$desc) = rbs_find_pkg($l,$parch,"dir"); if ((defined $desc) and (not defined $done{$desc})) { my $response1 = $ua->get("$mirror/$desc"); # Check if we have a fedora 17/18 type of repo if ($response1->is_success) { $done{$desc} = "true"; foreach my $d (split(/\n/,$response1->as_string())) { my ($url2,$desc2) = rbs_find_pkg($d,$parch,"pkg"); if (defined $url2) { # Here we have the dir in which are packages $url{$url2} = "$mirror/$desc/$desc2"; } else { pb_log(3,"not a package, and not a dir containing packages\n"); } } } else { } } } } # # Prepare early the yum cache env for the VE in order to copy in it packages on the fly # my $oscachedir = "/tmp"; my $osupdcachedir; my $osupdname = ""; if ($pbos->{'install'} =~ /yum/) { $oscachedir = "$vepath/var/cache/yum/core/packages/"; $osupdcachedir = "$vepath/var/cache/yum/updates-released/packages/"; $osupdname = "YUM"; # Recent Fedora release use a new yum cache dir if (($pbos->{'name'} eq "fedora") && ($pbos->{'version'} > 8)) { $oscachedir = "$vepath/var/cache/yum/$pbos->{'arch'}/$pbos->{'version'}/fedora/packages"; #$osupdcachedir = "$vepath/var/cache/yum/$pbos->{'arch'}/$pbos->{'version'}/updates/packages"; $osupdcachedir = "$vepath/var/cache/yum/updates-released/packages/"; } } elsif ($pbos->{'install'} =~ /dnf/) { $osupdname = "DNF"; $oscachedir = "$vepath/var/cache/dnf/$pbos->{'arch'}/$pbos->{'version'}/fedora/packages"; $osupdcachedir = "$vepath/var/cache/dnf/updates-released/packages/"; } elsif ($pbos->{'install'} =~ /zypper/) { $oscachedir = "$vepath/var/cache/zypp/packages/opensuse/suse/$pbos->{'arch'}"; $osupdname = "Zypper"; } elsif ($pbos->{'install'} =~ /urpmi/) { $oscachedir = "$vepath/var/cache/urpmi/rpms"; $osupdname = "URPMI"; } pb_log(1,"Setting up $osupdname cache in VE\n"); pb_mkdir_p($oscachedir); pb_mkdir_p($osupdcachedir) if (defined $osupdcachedir); # For each package to process, get it, put it in the cache dir # and extract it in the target dir. If not asked to keep, remove it # Just download if asked so. my $warning = 0; my $lwpkg =""; my @installed_packages; # On systemd systems, the pkg needs to be first # to have the correct links made first if ($pkgs =~ /,filesystem,/) { $pkgs =~ s/,filesystem,/,/; $pkgs = "filesystem,".$pkgs; } foreach my $p (split(/,/,$pkgs)) { $p =~ s/\s+//go; pb_log(1,"Processing package $p ...\n"); # Just print packages names if asked so. if (defined $url{$p}) { if ($opts{'p'}) { pb_log(0,"$url{$p}\n"); next; } else { # Now download if not already in cache my $p1 = basename($url{$p}); if (! -f "$cachedir/$p1") { pb_system("wget --tries=5 --quiet -O $cachedir/$p1-new $url{$p}","Downloading package $p1 ..."); rename("$cachedir/$p1-new", "$cachedir/$p1") || die "mv $cachedir/$p1-new $cachedir/$p1 failed: $!"; } else { pb_log(1,"Package $p1 already in cache\n"); } # End if download only if ($opts{'d'}) { next; } # # Copy the cached .RPM files into the oscachedir directory, so that os doesn't need to download them again. # pb_log(1,"Link package into $oscachedir\n"); copy("$cachedir/$p1",$oscachedir) if (defined $oscachedir); symlink("$oscachedir/$p1","$osupdcachedir/p1") if (defined $osupdcachedir); # And extract it to the finale dir pb_system("cd $vepath ; rpm2cpio $cachedir/$p1 | cpio -ivdum --extract-over-symlinks","Extracting package $p1 into $vepath"); # Remove cached package if not asked to keep if (! $opts{'k'}) { unlink("$cachedir/$p1"); } push(@installed_packages, $p); } } else { pb_log(0,"WARNING: unable to find URL for $p\n"); $warning++; $lwpkg .= " $p"; } } if ($warning ge 1) { pb_log(0,"$warning WARNINGS found.\nMaybe you should review your package list for $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}\nand remove$lwpkg\n"); } # Stop here if we just print if ($opts{'p'}) { pb_exit(0); } # Now executes the VE finalization steps required for it to work correctly pb_log(0,"VE post configuration\n"); # yum needs that distro-release package be installed, so force it if (($pbos->{'install'} =~ /yum/) || ($pbos->{'install'} =~ /dnf/)) { my $ddir = $pbos->{'name'}; foreach my $p1 (<$cachedir/($ddir|redhat)-release-*.rpm>) { copy("$cachedir/$p1","$vepath/tmp"); pb_system("chroot $vepath rpm -ivh --force --nodeps /tmp/$p1","Forcing RPM installation of $p1"); unlink("$vepath/tmp/$p1"); } # RedHat 6.2 has a buggy termcap setup and doesn't support usage of setarch, so still returns x86_64 in a chroot } elsif (($pbos->{'name'} =~ /redhat/) && ( $pbos->{'version'} =~ /^6/)) { pb_system("chroot $vepath ldconfig","Forcing ldconfig on $pbos->{'name'} $pbos->{'version'}"); pb_system("chroot $vepath echo 'arch_canon: x86_64: x86_64 1' >> /etc/rpmrc","Forcing ldconfig on $pbos->{'name'} $pbos->{'version'}"); pb_system("chroot $vepath echo 'arch_compat: x86_64: i386' >> /etc/rpmrc","Forcing ldconfig on $pbos->{'name'} $pbos->{'version'}"); pb_system("chroot $vepath echo 'buildarch_compat: x86_64: i386' >> /etc/rpmrc","Forcing ldconfig on $pbos->{'name'} $pbos->{'version'}"); pb_system("chroot $vepath echo 'buildarchtranslate: x86_64: i386' >> /etc/rpmrc","Forcing ldconfig on $pbos->{'name'} $pbos->{'version'}"); } # # Make sure there is a resolv.conf file present, such that DNS lookups succeed. # pb_log(1,"Creating resolv.conf\n"); pb_mkdir_p("$vepath/etc"); copy("/etc/resolv.conf","$vepath/etc/"); # # BUGFIX: # if ((($pbos->{'name'} eq "centos") || ($pbos->{'name'} eq "rhel")) && ($pbos->{'version'} eq "5")) { pb_log(1,"BUGFIX for centos-5\n"); pb_mkdir_p("$vepath/usr/lib/python2.4/site-packages/urlgrabber.skx"); foreach my $i (<$vepath/usr/lib/python2.4/site-packages/urlgrabber/keepalive.*>) { move($i,"$vepath/usr/lib/python2.4/site-packages/urlgrabber.skx/"); } } # # /proc needed # pb_mkdir_p("$vepath/proc"); pb_system("mount -o bind /proc $vepath/proc","Mounting /proc") unless (-d "$vepath/proc/$$"); # # Some devices may be needed # pb_mkdir_p("$vepath/dev"); chmod 0755,"$vepath/dev"; pb_system("mknod -m 644 $vepath/dev/random c 1 8","Creating $vepath/dev/random") if (! -c "$vepath/dev/random"); pb_system("mknod -m 644 $vepath/dev/urandom c 1 9","Creating $vepath/dev/urandom") if (! -c "$vepath/dev/urandom"); pb_system("mknod -m 666 $vepath/dev/zero c 1 5","Creating $vepath/dev/zero") if (! -c "$vepath/dev/zero"); pb_system("mknod -m 666 $vepath/dev/null c 1 3","Creating $vepath/dev/null") if (! -c "$vepath/dev/null"); # Where is bash my $bash = "/usr/bin/bash"; if (! -x "$vepath/$bash" ) { $bash = "/bin/bash"; if (! -x "$vepath/$bash" ) { die "No bash found in usual places. Please report to dev team"; } } my $minipkglist; pb_log(1,"Adapting $osupdname repository entries\n"); if (($pbos->{'install'} =~ /yum/) || ($pbos->{'install'} =~ /dnf/)) { # # Force the architecture for yum/dnf # The goal is to allow i386 chroot on x86_64 # # FIX: Not sufficient to have yum/dnf working # mirrorlist is not usable # $releasever also needs to be filtered # yum.conf as well foreach my $i (<$vepath/etc/yum.repos.d/*.repo>,"$vepath/etc/yum.conf","$vepath/etc/dnf/dnf.conf") { pb_system("sed -i -e 's/\$basearch/$pbos->{'arch'}/g' $i","","quiet"); pb_system("sed -i -e 's/\$releasever/$pbos->{'version'}/g' $i","","quiet"); pb_system("sed -i -e 's/^mirrorlist/#mirrorlist/' $i","","quiet"); pb_system("sed -i -e 's/^metalink/#metalink/' $i","","quiet"); # rather use neutral separators here pb_system("sed -i -e 's|^#baseurl.*\$|baseurl=$repo|' $i","","quiet"); } my $pkgmgr = ""; if ($pbos->{'install'} =~ /yum/) { $pkgmgr = "yum"; } if ($pbos->{'install'} =~ /dnf/) { $pkgmgr = "dnf"; } $minipkglist = "ldconfig $pkgmgr passwd vim-minimal dhclient authconfig"; } elsif ($pbos->{'install'} =~ /zypper/) { pb_mkdir_p("$vepath/etc/zypp/repos.d"); open(REPO,"> $vepath/etc/zypp/repos.d/$pbos->{'name'}-$pbos->{'version'}") || die "Unable to create repo file"; my $baseurl = dirname(dirname($mirror)); # Setup the repo if ($pbos->{'version'} eq "10.2") { pb_system("chroot $vepath $bash -c \"yes | /usr/bin/zypper sa $baseurl $pbos->{'name'}-$pbos->{'version'}\"","Bootstrapping Zypper"); } else { # don't care if remove fails if add succeeds. pb_system("chroot $vepath $bash -c \"/usr/bin/zypper rr $pbos->{'name'}-$pbos->{'version'}\"","Bootstrapping Zypper","mayfail"); pb_system("chroot $vepath $bash -c \"/usr/bin/zypper ar $baseurl $pbos->{'name'}-$pbos->{'version'}\"","Bootstrapping Zypper"); } #print REPO << "EOF"; #[opensuse] #name=$pbos->{'name'}-$pbos->{'version'} #baseurl=$baseurl #enabled=1 #gpgcheck=1 # #EOF close(REPO); $minipkglist = "zypper aaa_base"; # TODO: Re-installing packages missing and necessary on opensuse 11.4 to get /etc/passwd created. } elsif ($pbos->{'install'} =~ /urpmi/) { # Setup the repo my $baseurl = dirname(dirname(dirname($mirror))); pb_system("chroot $vepath $bash -c \"urpmi.addmedia --distrib $baseurl\"","Bootstrapping URPMI"); # TODO here too ? $minipkglist = "ldconfig urpmi bash passwd vim-minimal dhcp-client"; } elsif ($pbos->{'install'} =~ /\/rpm/) { opendir(CDIR,$cachedir) || die "Unable to open directory $cachedir: $!"; foreach my $p (@installed_packages) { foreach my $f (readdir(CDIR)) { # find an rpm package ref name-ver-tag.arch.rpm next if ($f =~ /^\./); if ($f =~ /^$p-([^-]+)-([^-]+)\.(noarch|$parch)\.rpm$/) { # Copy it to the chroot and reference it copy("$cachedir/$f","$vepath/var/cache"); $minipkglist .= " /var/cache/$f"; last; } } rewinddir(CDIR); } closedir(CDIR); } # # Run "install the necessary modules". # No need for sudo here # $pbos->{'install'} =~ s/sudo//g; if (((defined $ENV{'http_proxy'}) && ($ENV{'http_proxy'} ne '')) || ((defined $ENV{'https_proxy'}) && ($ENV{'https_proxy'} ne '')) || ((defined $ENV{'ftp_proxy'}) && ($ENV{'ftp_proxy'} ne ''))) { if ($pbos->{'name'} eq "opensuse") { # For opensuse 11.4 or 12.1 -- one of them didn't work with http_proxy or HTTP_PROXY set. open(PROXY, "> $vepath/etc/sysconfig/proxy") || die "can't open $vepath/etc/sysconfig/proxy: $!"; print PROXY "HTTP_PROXY=$ENV{'http_proxy'}\n" if ((defined $ENV{'http_proxy'}) && ($ENV{'http_proxy'} ne '')); print PROXY "HTTPS_PROXY=$ENV{'https_proxy'}\n" if ((defined $ENV{'https_proxy'}) && ($ENV{'https_proxy'} ne '')); print PROXY "FTP_PROXY=$ENV{'ftp_proxy'}\n" if ((defined $ENV{'ftp_proxy'}) && ($ENV{'ftp_proxy'} ne '')); close(PROXY); } } # Keep redhat variants from destroying nis domain on install #pb_system("chroot $vepath $bash -e -c \"ln -snf /bin/true /bin/domainname\""); #if ($pbos->{'name'} =~ /fedora/i) { # hack to prevent fedora from destroying NIS settings on host # open (AUTH, ">$vepath/etc/pam.d/system-auth-ac") || die "unable to open $vepath/etc/pam.d/system-auth-ac for write: $!"; # print AUTH "#pam_systemd -- will fix later in bootstrap\n"; # close(AUTH); #} pb_system("chroot $vepath $bash -c \"$pbos->{'install'} $minipkglist \"","Bootstrapping OS by running $pbos->{'install'} $minipkglist"); # CentOS6 will replace the yum.repos.d files; oddly it will leave the yum.conf file alone and make the new one ".rpmnew" if (($pbos->{'name'} eq "centos") && ($pbos->{'version'} =~ /^6.*/)) { pb_log(0,"Fixing $pbos->{'name'} $pbos->{'version'} bug for yum conf files"); foreach my $from (<$vepath/etc/yum.repos.d/*.rpmorig>) { my $to = $from; $to =~ s/.rpmorig$//; pb_system("mv $from $to", "Recover $from"); } } # # make 'passwd' work. # pb_log(1,"Authfix\n"); # TODO: Not generic enough to be done like that IMHO # In case it was changed during the install #pb_system("chroot $vepath $bash -e -c \"ln -snf /bin/true /bin/domainname\""); pb_system("chroot $vepath $bash -c \"if [ -x /usr/bin/authconfig ]; then /usr/bin/authconfig --enableshadow --update --nostart; fi\"","Calling authconfig"); # Installed additional packages we were asked to if (defined $opts{'a'}) { $opts{'a'} =~ s/,/ /g; pb_system("chroot $vepath $bash -c \"$pbos->{'install'} $opts{'a'} \"","Adding packages to OS by running $pbos->{'install'} $opts{'a'}"); } # # Clean up # pb_log(1,"Cleaning up\n"); if ($pbos->{'install'} =~ /yum/) { pb_system("chroot $vepath /usr/bin/yum clean all","Cleaning yum"); } if ($pbos->{'install'} =~ /dnf/) { pb_system("chroot $vepath /usr/bin/dnf clean all","Cleaning dnf"); } pb_system("umount $vepath/proc","Unmounting /proc"); find(\&unlink_old_conf, $vepath); # Executes post-install step if asked for if ($opts{'s'}) { pb_system("$opts{'s'} $vepath","Executing the post-install script: $opts{'s'} $vepath"); } if ($warning > 0) { pb_log(0,"\n\n\n\n$warning WARNINGS found.\nMaybe you should review your package list for $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}\nand remove$lwpkg\n"); pb_log(0,"waiting 60 seconds to give you a chance to notice.\n"); sleep(60); } pb_exit(); # Function for File::Find sub unlink_old_conf { unlink($_) if ($_ =~ /\.rpmorig$/); unlink($_) if ($_ =~ /\.rpmnew$/); } # Function to store packages found on Web pages sub rbs_find_pkg { my $l = shift; my $parch = shift; my $type = shift; pb_log(2,"Entering rbs_find_pkg with l=$l and parch=$parch\n"); # Find a href ref in first pos if ($l =~ /([^<>]*)<\/a>/i) { my $pkg = $1; my $desc = $2; pb_log(3,"Found desc URL $desc: "); # find an rpm package ref name-ver-tag.arch.rpm if (($type eq "pkg") && ($pkg =~ /(.+)-([^-]+)-([^-]+)\.(noarch|$parch)\.rpm$/)) { pb_log(3,"package ($1 + $2 + $3 + $4)\n"); my $url = $1; pb_log(2,"Exiting rbs_find_pkg with url=$url and desc=$desc\n"); return($url,$pkg); } elsif (($type eq "dir") && ($pkg =~ /([0-z])\//)) { my $url = $1; pb_log(3,"dir ($1)\n"); return($url,$1); } else { pb_log(3,"not a package\n"); } } pb_log(2,"Exiting rbs_find_pkg with undef\n"); return(undef,undef); } sub rbs_mirror_response { my $mirror = shift; pb_log(0,"Downloading package list from $mirror ...\n"); my $response = $ua->get($mirror); if (! $response->is_success) { if ($mirror =~ /i386/) { # Some distro have an i586 or i686 mirror dir instead for i386 warn "Unable to download package from $mirror for $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}.".$response->status_line; $mirror =~ s|/i386/|/i586/|; pb_log(0,"Downloading now package list from $mirror ...\n"); $response = $ua->get($mirror); if (! $response->is_success) { die "Unable to download package from $mirror for $pbos->{'name'}-$pbos->{'version'}-$pbos->{'arch'}".$response->status_line; } } } pb_log(3,"Mirror $mirror gave answer: ".Dumper($response->dump(maxlength => 0))."\n"); # Try to find where the repodata structure is for later usage my $repo = $mirror; my $found = 0; if (($pbos->{'install'} =~ /yum/) || ($pbos->{'install'} =~ /dnf/)) { my $response1; while ($found == 0) { $response1 = $ua->get("$repo/repodata"); pb_log(2,"REPO analyzed: $repo\n"); if (! $response1->is_success) { $repo = dirname($repo); # There is a limit to the loop, when / is reached and nothing found my ($scheme, $account, $host, $port, $path) = pb_get_uri($repo); die "Unable to find the repodata structure of the mirror $mirror\nPlease check the URL or warn the dev team.\n" if (($path =~ /^[\/]+$/) || ($path =~ /^$/)); # / not reached, so looping next; } else { # repodata found $repo is correct $found = 1; pb_log(2,"REPO found: $repo\n"); last; } } } return($repo,$response); }