自动化安装ISO制作流程

此文档参考了《Building a custom CentOS 7 kickstart disc》的内容,原文链接
说明:此文档仅用于制作CentOS7.2版本的ISO镜像,其他CentOS版本制作ISO步骤可能与此文档中有所差别。

构建基础环境

  1. 正常运行的CentOS7.2操作系统,虚拟机或物理机均可,作为ISO生产系统,此处使用CentOS7.2的最小化安装系统

  2. 下载CentOS7.2ISO镜像文件,用于提供制作ISO镜像时的RPM包及一些制作ISO镜像时需要的文件

  3. 将下载的CentOS7.2的ISO镜像上传到生产系统中,并将其挂载到生产系统中,此文档中将ISO系统挂载到/mnt目录:mount -o loop /root/CentOS-7-x86_64-DVD-1511.iso /mnt

  4. /home/test/目录下创建以下目录,目录结构如下所示:

    ~/BuildISO
    ├── all_rpms     #用于存放所有的RPM包
    ├── ISO      #制作ISO所需的主要目录
    │   ├── EFI
    │   ├── images
    │   ├── isolinux
    │   ├── LiveOS
    │   ├── Packages
    │   └── repodata
    └── utils            #用于存放制作ISO需要的脚本
    
  5. /mnt挂载目录下拷贝CentOS_buildTag EFI EULA GPL RPM-GPG-KEY-CentOS-7 RPM-GPG-KEY-CentOS-Testing-7 TRANS.TBL文件到~/BuildISO/ISO/目录

  6. 拷贝/mnt/images/目录下的所有内容到~/BuildISO/ISO/images/,拷贝/mnt/isolinux/下的所有内容到~/BuildISO/ISO/isolinux/目录,拷贝/mnt/LiveOS/目录下所有内容到~/BuildISO/ISO/LiveOS目录中。

  7. 拷贝/mnt/repodata/3eda3fefdbaf4777fcab430c80bc438293c512f22fd706b12c6567d535b2142a-c7-x86_64-comps.xml~/BuildISO/目录,并重命名为comps.xml

  8. 拷贝/mnt/Packages/目录下的所有RPM包到~/BuildISO/all_rpms目录中

  9. 拷贝生产系统中/root/anaconda-ks.cfg~/BuildISO/isolinux/目录,并重命名为ks.cfg,并对其内容进行修改,修改后内容如下代码所示:

    #version=DEVEL
    # System authorization information
    auth --enableshadow --passalgo=sha512
    
    install
    # Use CDROM installation media
    cdrom
    
    # Use graphical install
    graphical
    
    # Run the Setup Agent on first boot
    firstboot --enable
    ignoredisk --only-use=sda
    # Keyboard layouts
    keyboard --vckeymap=us --xlayouts='us'
    # System language
    lang en_US.UTF-8
    
    # System timezone
    timezone Asia/Shanghai --isUtc --nontp
    
    firewall --service=ssh
    text
    firstboot --disable
    logging --level=info
    reboot
    
    # Network information
    network  --bootproto=dhcp --device=eth0 --onboot=off --ipv6=auto
    network  --bootproto=dhcp --device=eth1 --onboot=off --ipv6=auto
    network  --bootproto=dhcp --device=eth2 --onboot=off --ipv6=auto
    network  --bootproto=dhcp --device=eth3 --onboot=off --ipv6=auto
    network  --bootproto=dhcp --device=eth4 --onboot=off --ipv6=auto
    network  --device=lo --hostname=localhost.localdomain
    
    # Root password
    rootpw --iscrypted $6$308MAGXkalXkxfpo$WYIl1IlurMy.47E0bmMOSi2yOgXEDTOT3zdVX5CCoOfSSCQg5ik9bE/ysn3p52SVzsKGJYqsgvBefw0bqbOlg/
    user --name=cloudmap --password=$6$yB9wJt.qmRy6aNYf$krIYwnA4gGibrmPanO6Ycfl0g8yeQlS0QUihYeuIcVjRcpJQR4MIZSze1rJdc.cnbApAfKoWRqyAsutFnkMy31 --iscrypted --gecos="cloudmap"
    
    # System bootloader configuration
    bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=sda
    zerombr
    
    autopart --type=lvm
    # Partition clearing information
    # 如果用此ISO安装多系统,需要将'--all'参数去掉。
    clearpart --drives=sda --all --initlabel
    
    %packages
    @core
    @base
    kexec-tools
    
    %end
    
    %addon com_redhat_kdump --enable --reserve-mb='auto'
    
    %end
    

    注意:如果目标安装介质不支持'sda',支持'vda',则此文件中所有的'sda'需要修改为'vda',其他不用修改

确定需要安装的软件包

  1. ~/BuildISO/comps.xml文件中定义了很多软件组,每个软件组中则包含了此软件组中需要安装的软件包。我们可以根据需要来选择~/BuildISO/comps.xml中定义的软件组来构建我们的ISO。
    在此次构建ISO中,选择安装core base development additional-devel debugging java-platform network-file-system-client performance perl-runtime,并将以上的组写入到ks.cfg文件的%packages后面,并以@开头,如@core @base等。修改后的ks.cfg文件%packages之后的内容如下所示:

    %packages
    @core
    @base
    @development
    @additional-devel
    @debugging
    @java-platform
    @network-file-system-client
    @performance
    @perl-runtime
    kexec-tools
    
    %end
    
  2. 选择以上软件包组之后,则需要根据~/BuildISO/comps.xml文件中的内容将所选择的软件包组所需的软件软件包拷贝到~/BuildISO/ISO/Packages目录之中,例如core软件包所需软件包在comps.xml中如下所示:

    <group>
       <id>core</id>
       <name>Core</name>
       ...
       <packagelist>
         <packagereq type="mandatory">Red_Hat_Enterprise_Linux-Release_Notes-7-en-US</packagereq>
         <packagereq type="mandatory">audit</packagereq>
         <packagereq type="mandatory">basesystem</packagereq>
         <packagereq type="mandatory">bash</packagereq>
         <packagereq type="mandatory">biosdevname</packagereq>
         <packagereq type="mandatory">btrfs-progs</packagereq>
         <packagereq type="mandatory">coreutils</packagereq>
         <packagereq type="mandatory">cronie</packagereq>
         <packagereq type="mandatory">curl</packagereq>
         <packagereq type="mandatory">dhclient</packagereq>
         <packagereq type="mandatory">e2fsprogs</packagereq>
         ...
       </packagelist>
    </group>
    

    上面代码中在<group>标签内的<packagereq type="mandatory"><packagereq type="default">条目即是core软件组需要的RPM包的名称。

  3. 为方便拷贝所有组的所有软件包,可以通过运行~/BuildISO/utils/gather_packages.pl脚本来拷贝所有软件包。gather_packages.pl脚本是Perl写的,所以需要在系统上安装一些运行此脚本依赖的软件包。
    安装运行gather_packages.pl脚本所需的软件包:

    $ cd ~/BuildISO/all_rpms
    $ sudo rpm -Uvh perl-5*-*.el7.x86_64.rpm \
    perl-Business-ISBN-*.el7.noarch.rpm   \
    perl-Carp-*.el7.noarch.rpm   \
    perl-Compress-Raw-Bzip2-*.el7.x86_64.rpm \
    perl-Compress-Raw-Zlib-*.el7.x86_64.rpm   \
    perl-constant-*.el7.noarch.rpm   \
    perl-Data-Dumper-*.el7.x86_64.rpm   \
    perl-devel-*.el7.x86_64.rpm   \
    perl-Digest-*.el7.noarch.rpm   \
    perl-Digest-MD5-*.el7.x86_64.rpm   \
    perl-Digest-SHA-*.el7.x86_64.rpm   \
    perl-Encode-*.el7.x86_64.rpm   \
    perl-Encode-Locale-*.el7.noarch.rpm   \
    perl-Exporter-*.el7.noarch.rpm   \
    perl-ExtUtils-Install-*.el7.noarch.rpm   \
    perl-ExtUtils-MakeMaker-*.el7.noarch.rpm   \
    perl-ExtUtils-Manifest-*.el7.noarch.rpm   \
    perl-ExtUtils-ParseXS-*.el7.noarch.rpm   \
    perl-File-Listing-*.el7.noarch.rpm   \
    perl-File-Path-*.el7.noarch.rpm   \
    perl-File-Temp-*.el7.noarch.rpm   \
    perl-Filter-*.el7.x86_64.rpm   \
    perl-Getopt-Long-*.el7.noarch.rpm   \
    perl-HTML-Parser-*.el7.x86_64.rpm   \
    perl-HTML-Tagset-*.el7.noarch.rpm   \
    perl-HTTP-Cookies-*.el7.noarch.rpm   \
    perl-HTTP-Daemon-*.el7.noarch.rpm   \
    perl-HTTP-Date-*.el7.noarch.rpm   \
    perl-HTTP-Message-*.el7.noarch.rpm   \
    perl-HTTP-Negotiate-*.el7.noarch.rpm   \
    perl-HTTP-Tiny-*.el7.noarch.rpm   \
    perl-IO-Compress-*.el7.noarch.rpm   \
    perl-IO-HTML-*.el7.noarch.rpm   \
    perl-IO-Socket-IP-*.el7.noarch.rpm   \
    perl-IO-Socket-SSL-*.el7.noarch.rpm   \
    perl-libs-*.el7.x86_64.rpm   \
    perl-libwww-perl-*.el7.noarch.rpm   \
    perl-LWP-MediaTypes-*.el7.noarch.rpm   \
    perl-macros-*.el7.x86_64.rpm   \
    perl-Net-HTTP-*.el7.noarch.rpm   \
    perl-Net-LibIDN-*.el7.x86_64.rpm   \
    perl-Net-SSLeay-*.el7.x86_64.rpm   \
    perl-parent-*.el7.noarch.rpm   \
    perl-PathTools-*.el7.x86_64.rpm   \
    perl-Pod-Escapes-*.el7.noarch.rpm   \
    perl-Pod-Perldoc-*.el7.noarch.rpm   \
    perl-Pod-Simple-*.el7.noarch.rpm   \
    perl-Pod-Usage-*.el7.noarch.rpm   \
    perl-podlators-*.el7.noarch.rpm   \
    perl-Scalar-List-Utils-*.el7.x86_64.rpm   \
    perl-Socket-*.el7.x86_64.rpm   \
    perl-srpm-macros-*.el7.noarch.rpm   \
    perl-Storable-*.el7.x86_64.rpm   \
    perl-Test-Harness-*.el7.noarch.rpm   \
    perl-Text-ParseWords-*.el7.noarch.rpm   \
    perl-Thread-Queue-*.el7.noarch.rpm   \
    perl-threads-*.el7.x86_64.rpm   \
    perl-Time-Local-*.el7.noarch.rpm   \
    perl-TimeDate-*.el7.noarch.rpm   \
    perl-URI-*.el7.noarch.rpm   \
    perl-WWW-RobotRules-*.el7.noarch.rpm   \
    perl-XML-Filter-BufferText-*.el7.noarch.rpm   \
    perl-XML-NamespaceSupport-*.el7.noarch.rpm  \
    perl-XML-Parser-*.el7.x86_64.rpm   \
    perl-XML-SAX-*.el7.noarch.rpm   \
    perl-XML-Simple-*.el7.noarch.rpm   \
    gdbm-devel-*.x86_64.rpm   \
    glibc-devel-*.x86_64.rpm   \
    glibc-headers-*.x86_64.rpm   \
    kernel-headers-*.x86_64.rpm   \
    libdb-devel-*.x86_64.rpm   \
    systemtap-sdt-devel-*.x86_64.rpm   \
    mailcap-*.noarch.rpm perl-Time-HiRes-1.9725-3.el7.x86_64.rpm \
    pyparsing-1.5.6-9.el7.noarch.rpm 
    
  4. 运行gather_packages.pl脚本:

    ~/BuildISO/utils/gather_packages.pl ~/BuildISO/comps.xml ~/BuildISO/all_rpms \
    ~/BuildISO/ISO/Packages x86_64 development additional-devel debugging \
    java-platform network-file-system-client performance perl-runtime
    

    注: gather_packages.pl脚本默认手机corebase两个组的软件包,所以此处不需要再次添加corebase两个组。

解决RPM依赖问题

  1. 现在已经将所有需要的组的RPM包拷贝到了~/BuildISO/ISO/Packages目录中,接下来就要检查此目录中的RPM包是否还缺少依赖的RPM包。我们可以通过脚本~/BuildISO/utils/resove_deps.pl来完成检查拷贝工作。

    ~/BuildISO/utils/resolve_deps.pl ~/BuildISO/all_rpms \
        ~/BuildISO/ISO/Packages x86_64
    
  2. 现在我们已经得到了所需要的RPM包,现在需要测试一下RPM包的依赖关系

    cd ~/BuildISO/ISO/Packages
    mkdir /tmp/testdb
    rpm --initdb --dbpath /tmp/testdb
    rpm --test --dbpath /tmp/testdb -Uvh *.rpm
    

    命令执行完成后,输出如下信息:

    warning: abattis-cantarell-fonts-0.0.16-3.el7.noarch.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
    error: Failed dependencies:
            /usr/sbin/cgrulesengd is needed by cgdcbxd-1.0.2-5.el7.x86_64
            /usr/bin/fipscheck is needed by fipscheck-lib-1.4.1-5.el7.x86_64
            /usr/bin/db_stat is needed by rpm-4.11.3-17.el7.x86_64
    

    说明还缺少一些依赖,可以通过yum provides cgrulesengd来查找所需的RPM包
    fipscheckfipscheck-1.4.1-5.el7.x86_64.rpm提供
    db_statlibdb-utils-5.3.21-19.el7.x86_64.rpm提供
    cgrulesengdlibcgroup-tools-0.41-8.el7.x86_64.rpm提供
    ~/BuildISO/all_rpms目录拷贝以上三个文件到~/BuildISO/ISO/Packages目录下。如果~/BuildISO/all_rpms目录下不含有这些RPM包,可以到163镜像源网站的/centos/7.2.1511/os/x86_64/Packages//centos/7.2.1511/updates/x86_64/Packages/两个目录中查找并下载。再次执行rpm --test --dbpath /tmp/testdb -Uvh *.rpm,发现依赖已经解决。

注意:注意检查软件包中是否包含kernel-*相关的rpm包,如果没有这些RPM包,系统安装完成后无法进入系统

生成RPM repository

  1. 为了生成repository,需要createrepo工具,由于生产系统为最小化安装系统,所以需要安装createrepo

    $ cd ~/BuildISO/all_rpms
    $ sudo rpm -Uvh \
          createrepo-*.el7.noarch.rpm \
          deltarpm-*.el7.x86_64.rpm \
          python-deltarpm-*.el7.x86_64.rpm \
          libxml2-python-*.el7.x86_64.rpm
    
  2. 创建repository

    $ cd ~/BuildISO/ISO/
    $ createrepo -g ~/BuildISO/comps.xml .
    

注意:在CentOS下需要根据'.discinfo'来设置'baseurl'(declare -x discinfo=head -1 .discinfo; createrepo -u "media://$discinfo"...); 在CentOS7中不再需要如此做,实际上如果在CentOS7中执行了这个命令,在安装的过程中,可能会报错"RepoError after 10 retries: Insufficient space in download directory /run/install/repo/Packages"

生成ISO镜像

  1. 制作ISO需要mkisofs工具,需要安装genisoimage包:

    $ cd ~/BuildISO/all_rpms
    $ sudo rpm -Uvh \
      genisoimage-*.el7.x86_64.rpm \
      libusal-*.el7.x86_64.rpm
    
  2. 修改~/BuildISO/ISO/isolinux/isolinux.cfg如下:

    label linux
      menu label ^Install CentOS 7
      kernel vmlinuz
      # 去掉quiet,增加inst.ks=cdrom:/dev/cdrom:/isolinux/ks.cfg内容
    #  append initrd=initrd.img inst.stage2=hd:LABEL=CentOS\x207\x20x86_64 quiet
     append initrd=initrd.img inst.stage2=hd:LABEL=CentOS\x207\x20x86_64 \
               inst.ks=cdrom:/dev/cdrom:/isolinux/ks.cfg
    
  3. 制作ISO镜像

    mkisofs -U -r -v -T -J -joliet-long \
        -V "CentOS 7 x86_64" \
        -volset "CentOS 7 x86_64" \
        -A "CentOS 7 x86_64" \
        -input-charset utf-8 \
        -b isolinux/isolinux.bin \
        -c isolinux/boot.cat -no-emul-boot \
        -boot-load-size 4 -boot-info-table \
        -eltorito-alt-boot -e images/efiboot.img \
        -no-emul-boot -o /root/ISO.iso \
        ~/BuildISO/ISO/
    

测试ISO镜像

将制作好的ISO镜像用VMware安装或者在Ovirt中安装测试,确认制作的ISO能够正常运行。

定制自己的功能并制作ISO

在上面已经创建出了能够正常运行的ISO镜像,下面就是在上述ISO中添加自己的功能。

为添加自己定制的功能,我们需要使用postinstall script,即在ks.cfg中增加%post区域。

ks.cfg配置文件中,%post域的命令在anaconda安装完成后开始执行。默认情况下,%post区域的命令运行在一个chroot环境下,此时/mnt/sysimage作为/目录,这样允许用户像访问正常目录一样进行访问,例如:如果要使用/etc目录,则应该使用/etc而不是/mnt/sysimage/etc。在chroot环境下最主要的缺点是无法访问安装介质。

为了解决这个问题,这里将postinstall script分两个阶段来处理:

  • 在第一阶段:告诉anaconda不要去chroot,将需要的文件从安装介质(ISO)中拷贝到磁盘中:

    %post --nochroot
    
    #!/bin/bash
    
    set -x -v
    exec 1> /mnt/sysimage/root/kickstart-stage1.log 2>&1
    
    echo "==> copying files from media to install drive..."
    
    cp -r /run/install/repo/postinstall /mnt/sysimage/root
    
    %end
    

    此次ISO镜像中定制安装文件放到了~/BuildISO/ISO/目录下的postinstall目录中。制作ISO镜像时的~/BuildISO/ISO/对应于安装介质的根目录,同时安装介质挂载在/run/install/repo目录下。所以~/BuildISO/ISO/postinstall可以通过/run/install/repo/postinstall获取。我们从安装介质上拷贝postinstall目录到新系统硬盘的/root/postinstall目录

  • 第二阶段:安装定制的功能

    %post
    #!/bin/bash
    
    set -x -v
    
    exec 1>/root/kickstart-stage2.log 2>&1
    
    ls -l /root/postinstall
    
    echo "===> install test..."
    %end
    

具体操作流程:

  1. ~/BuildISO/ISO中创建postinstall目录,并在其下创建相关目录:

    mkdir -p ~/BuildISO/ISO/postinstall/app/test
    
  2. 将test相关RPM包上传到test目录中
  3. 修改ks.cfg,通过两个%post来实现RPM包拷贝和RPM包的安装,具体如下:

    %post --nochroot
    
    #!/bin/bash
    
    set -x -v
    exec 1> /mnt/sysimage/root/kickstart-stage1.log 2>&1
    
    echo "==> copying files from media to install drive..."
    
    cp -r /run/install/repo/postinstall /mnt/sysimage/root
    
    %end
    
    %post
    #!/bin/bash
    
    set -x -v
    
    exec 1>/root/kickstart-stage2.log 2>&1
    
    ls -l /root/postinstall
    
    echo "===> install test..."
    yum install /root/postinstall/test/test.rpm    
    
    %end
    
  4. 制作ISO镜像

    mkisofs -U -r -v -T -J -joliet-long \
        -V "CentOS 7 x86_64" \
        -volset "CentOS 7 x86_64" \
        -A "CentOS 7 x86_64" \
        -input-charset utf-8 \
        -b isolinux/isolinux.bin \
        -c isolinux/boot.cat -no-emul-boot \
        -boot-load-size 4 -boot-info-table \
        -eltorito-alt-boot -e images/efiboot.img \
        -no-emul-boot -o /root/ISO-CM.iso \
        ~/BuildISO/ISO/
    

注意:在定制自己的功能模块时,最好是在先前已经安装好的ISO上测试一下能否安装成功,安装成功不缺少依赖的情况下再按以上步骤实施。

测试ISO镜像

安装测试ISO,并测试定制安装的功能是否能正常工作。

附注

gather_packets.pl

#!/usr/bin/perl

use XML::Simple;

my ($comps_file, $rpm_src_path, $rpm_dst_path, $arch, @extra_groups_and_packages) = @ARGV;

if (!-e $comps_file)
{
    print_usage ("Can't find '$comps_file'");
}
if (!-e $rpm_src_path)
{
    print_usage ("RPM source path '$rpm_src_path' does not exist");
}
if (!-e $rpm_dst_path)
{
    print_usage ("RPM destination path '$rpm_dst_path' does not exist");
}
if (!$arch)
{
    print_usage ("Architecture not specified");
}

#### we always gather core and base; note that for CentOS 7, we also need
#### to include the grub2 package, or installation will fail
@desired_groups = ('core', 'base', 'grub2');
foreach (@extra_groups_and_packages)
{
    push (@desired_groups, $_);
}

$regex = '^(' . join ('|', @desired_groups) . ')$';

print "reading $comps_file...\n";
print "getting RPMs from $rpm_src_path...\n";

$xml = new XML::Simple;
$comps = $xml->XMLin($comps_file);

$cmd = "rm $rpm_dst_path/*";
print "$cmd\n";
`$cmd`;

%copied_groups = {};
%copied_packages = {};

foreach $group (@{$comps->{group}})
{
    $id = $group->{id};
    if ($id !~ m#$regex#)
    {
        next;
    }

    print "#### group \@$id\n";
    $packagelist = $group->{packagelist};
    foreach $pr (@{$packagelist->{packagereq}})
    {
        if ($pr->{type} eq 'optional' || $pr->{type} eq 'conditional')
        {
            next;
        }

        $cmd = "cp $rpm_src_path/" . $pr->{content} . "-[0-9]*.$arch.rpm"
                . " $rpm_src_path/" . $pr->{content} . "-[0-9]*.noarch.rpm $rpm_dst_path";
        print "$cmd\n";
        `$cmd 2>&1`;

        $copied_packages{$pr->{content}} = 1;
    }

    $copied_groups{$group} = 1;
}

#### assume that any strings that weren't matched in the comps file's group list
#### are actually packages

foreach $group (@desired_groups)
{
    if ($copied_groups{$group})
    {
        next;
    }

    $cmd = "cp $rpm_src_path/" . $group . "-[0-9]*.$arch.rpm"
            . " $rpm_src_path/" . $group . "-[0-9]*.noarch.rpm $rpm_dst_path";
    print "$cmd\n";
    `$cmd 2>&1`;
}

sub print_usage
{
    my ($msg) = @_;

    ($msg) && print "$msg\n\n";

    print <<__TEXT__;

parse_comps.pl comps_file rpm_src_path arch [xtra_grps_and_pkgs]

    comps_file           the full path to the comps.xml file (as provided 
                         in the original distro

    rpm_src_path         the full path to the directory of all RPMs from 
                         the distro

    rpm_dst_path         the full path to the directory where you want
                         to save the RPMs for your kickstart

    arch                 the target system architecture (e.g. x86_64)

    xtra_grps_and_pkgs   a list of extra groups and packages, separated by spaces


__TEXT__

    exit;
}

resolve_deps.pl

#!/usr/bin/perl

my ($rpm_src_path, $rpm_dst_path, $arch) = @ARGV;

if (!-e $rpm_src_path)
{
    print_usage ("RPM source path '$rpm_src_path' does not exist");
}
if (!-e $rpm_dst_path)
{
    print_usage ("RPM destination path '$rpm_dst_path' does not exist");
}
if (!$arch)
{
    print_usage ("Architecture not specified");
}

print "Scanning all RPMs for capabilities provided...\n";
%providers = {};
open(my $fh_providers, '>/tmp/providers.txt');
foreach (<$rpm_src_path/*.rpm>)
{
    if (!m#(noarch|$arch)\.rpm$#)
    {
        next;
    }

    $rpm = $_;

    print ".";
    print $fh_providers "$rpm\n";

    $cmd = "rpm -q --provides -p $rpm 2>/dev/null";
    $output = `$cmd`;

    @lines = split ("\n", $output);

    foreach (@lines)
    {
        if (m#(.+)\s+=\s+\d#)
        {
            $capability = $1;
        }
        else
        {
            $capability = $_;
        }

        $rpm =~ m#([^/]+$)#;
        $rpm = $1;

        if ($providers{$capability} && ($providers{$capability} != $rpm))
        {
            print "WARNING: $capability is provided by " . $providers{$capability} . " and $rpm\n";
        }

        print $fh_providers "  $capability\n";
        $providers{$capability} = $rpm;
    }
}
close $fh_providers;

print "\n";

@queue = ();
%copied_packages = {};
foreach (<$rpm_dst_path/*rpm>)
{
    push (@queue, $_);
    my ($filename) = (m#/([^/]+)$#);
    my ($package_name) = ($filename =~ m#/(.+?)-\d#);
    $copied_packages{$package_name} = 1;
}

while (@queue)
{
    $rpm_name = pop (@queue);

    print "checking $rpm_name...\n";
    $cmd = "rpm -qRp $rpm_name 2>/dev/null | sort | uniq";
    #print "$cmd\n";
    @output = `$cmd`;

    foreach (@output)
    {
        s/^\s+//;
        s/\s+$//;
        s/\s+[<>=].+$//;  # strip off stuff like " >= 2003a"

        if ($providers{$_})
        {
            $new_path = "$rpm_dst_path/" . $providers{$_};

            if (-e $new_path)
            {
                #### already have this RPM in the directory...
                next;
            }
            print " requires $_ ==> " . $providers{$_} . "\n";

            push (@queue, $new_path);

            $newrpm = "$rpm_src_path/" . $providers{$_};
            $cmd = "cp $newrpm $rpm_dst_path";
            print "  $cmd\n";
            `$cmd 2>&1`;
        }
    }
}

sub print_usage
{
    my ($msg) = @_;

    ($msg) && print "$msg\n\n";

    print <<__TEXT__;
follow_deps.pl rpm_src_path rpm_dst_path arch

    rpm_src_path    the full path to the directory of all RPMs from the distro

    rpm_dst_path    the full path to the directory where you want to copy
                    the RPMs for your kickstart

    arch            the target system architecture (e.g. x86_64)


__TEXT__

    exit;
}