#!/usr/bin/env perl BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } use lib "$::XCATROOT/lib/perl"; use File::Basename; use File::Path; use File::Copy qw/copy cp mv move/; use File::Find; use Getopt::Long; use Cwd qw(realpath); use xCAT::Utils; use xCAT::TableUtils; use File::Temp qw/mkdtemp/; use FindBin; use lib "$FindBin::Bin/../imgutils"; use imgutils; #use strict; Getopt::Long::Configure("bundling"); Getopt::Long::Configure("pass_through"); my $dracutmode; #Indicate whether this is a dracut style initrd my $dracutdir = "dracut"; # The default directory name of dracut my $prinic; #TODO be flexible on node primary nic my $othernics; #TODO be flexible on node primary nic my $netdriver; my @yumdirs; my $arch; my %libhash; my @filestoadd; my $profile; my $osver; my $pathtofiles=dirname($0); my $fullpath=realpath($pathtofiles); my $name = basename($0); my $onlyinitrd=0; #that this method of calling genimage is no longer used if ($name =~ /geninitrd/) { $onlyinitrd=1; } my $rootlimit; my $tmplimit; my $installroot = "/install"; my $kerneldir; my $kernelver = ""; #`uname -r`; my $basekernelver; # = $kernelver; my $customdir=$fullpath; $customdir =~ s/.*share\/xcat/$installroot\/custom/; my $imagename; my $pkglist; my $srcdir; my $destdir; my $srcdir_otherpkgs; my $otherpkgsdir_local; my $otherpkgsdir_internet; my $otherpkglist; my $postinstall_filename; my $rootimg_dir; my $permission; # the permission works only for statelite mode currently my $tempfile; my $prompt; sub xdie { system("rm -rf /tmp/xcatinitrd.$$"); umount_chroot($rootimg_dir); die @_; } $SIG{INT} = $SIG{TERM} = sub { xdie "Interrupted" }; GetOptions( 'a=s' => \$arch, 'p=s' => \$profile, 'o=s' => \$osver, 'n=s' => \$netdriver, 'i=s' => \$prinic, 'r=s' => \$othernics, 'l=s' => \$rootlimit, 't=s' => \$tmplimit, 'k=s' => \$kernelver, 'permission=s' => \$permission, 'kerneldir=s' => \$kerneldir, 'tempfile=s' =>\$tempfile, #internal flag 'pkglist=s' => \$pkglist, #internal flag 'srcdir=s' => \$srcdir, #internal flag 'otherpkgdir=s' => \$srcdir_otherpkgs, #internal flag 'otherpkglist=s' => \$otherpkglist, #internal flag 'postinstall=s' => \$postinstall_filename, #internal flag 'rootimgdir=s' => \$destdir, #internal flag 'interactive' =>\$prompt, 'onlyinitrd' =>\$onlyinitrd, ); if (@ARGV > 0) { $imagename=$ARGV[0]; } my %updates_os = (); # the hash for updating osimage table my %updates = (); # the hash for updating linuximage table $permission = "755" unless ($permission); $updates{'permission'} = $permission if ( $tempfile ); unless ($arch) { $arch = `uname -m`; chomp($arch); $arch = "x86" if ($arch =~ /i.86$/); } $srcdir="$installroot/$osver/$arch" unless ($srcdir); $updates{'pkgdir'} = $srcdir if ($tempfile); if ($srcdir_otherpkgs){ my @tempdirarray = split /,/, $srcdir_otherpkgs; foreach my $tempdir (@tempdirarray){ if ($tempdir =~ /^http.*/){ $otherpkgsdir_internet .= "deb " . $tempdir . "\n"; } else{ $otherpkgsdir_local = $tempdir; } } } $updates{'otherpkgdir'} = $srcdir_otherpkgs if ($tempfile); $destdir="$installroot/netboot/$osver/$arch/$profile" unless ($destdir); $updates{'rootimgdir'} = $destdir if ($tempfile); $rootimg_dir="$destdir/rootimg"; $kerneldir = "$installroot/kernels" unless ($kerneldir); # the default directory for 3rd-party kernel is "$installroot/kernels"; #$updates{'kerneldir'} = $kerneldir if ($tempfile); # Get the subchannels of the given interface my $subchn; my $readChn; my @chn; if ($arch eq "s390x") { $subchn = `cat /etc/sysconfig/network-scripts/ifcfg-$prinic | grep "SUBCHANNELS"`; if (!$subchn) { print "SUBCHANNELS need to be given in /etc/sysconfig/network-scripts/ifcfg-$prinic"; exit 1; } else { # Trim right $subchn =~ s/\s*$//; # Trim left $subchn =~ s/^\s*//; # Extract subchannels $subchn =~ s/SUBCHANNELS=//g; # Extract read channel @chn = split( ",", $subchn ); $readChn = @chn[0]; } } unless ($osver and $profile) { usage(); exit 1; } my @ndrivers; if ($netdriver) { if ( ($updates{'netdrivers'} ne $netdriver) and ($tempfile) ) { $updates{'netdrivers'} = $netdriver; } } else { if ($arch eq 'x86' or $arch eq 'x86_64') { @ndrivers = qw/tg3 bnx2 bnx2x e1000 e1000e igb mlx_en virtio_net/; } elsif ($arch eq 'ppc64') { @ndrivers = qw/e1000 e1000e igb ibmveth ehea/; } elsif ($arch eq 's390x') { @ndrivers = qw/qdio ccwgroup/; } } foreach (split /,/,$netdriver) { unless (/\.ko$/) { s/$/.ko/; } next if (/^$/); push @ndrivers, $_; } foreach (@ndrivers) { unless (/\.ko$/) { s/$/.ko/; } } my $uarch=$arch; $uarch="amd64" if ($arch eq x86_64); unless ($onlyinitrd) { @aptdirs=(); find(\&isaptdir, <$installroot/$osver/$arch/>); # Add the dir for kernel deb to be installed if ($kernelver) { find(\&isaptdir, <$kerneldir/>); if (!grep /$kerneldir/, @aptdirs) { print "The repository for $kerneldir should be created before running the geniamge. Try to run [createrepo $kerneldir].\n"; } } unless (scalar(@aptdirs)) { print "Need $installroot/$osver/$arch/ available from a system that has ran copycds on $osver $arch\n"; exit 1; } my $aptconfig; open($aptconfig,">","/tmp/genimage.$$.apt.list"); my $repnum=0; foreach $srcdir (@aptdirs) { print $aptconfig "deb file://$srcdir main stable\n\n"; $repnum += 1; } $repnum-=1; close($aptconfig); mkpath "$rootimg_dir/etc"; my $fd; open($fd,">>","$rootimg_dir/etc/fstab"); print $fd "#Dummy fstab for dpkg postscripts to see\n"; close($fd); my $non_interactive; if (!$prompt) { $non_interactive="-y"; } my @line=split(" ",`ls -lh $installroot/$osver/$arch/dists/ | grep dr`); my $dist = $line[@line-1]; my $aptgetcmd = "chroot $rootimg_dir apt-get update && chroot $rootimg_dir apt-get $non_interactive "; my $aptcachecmd = "chroot $rootimg_dir apt-get update && chroot $rootimg_dir apt-cache $non_interactive "; my $aptcmd1 = "debootstrap"; my $aptcmd2 = "--arch $uarch $dist $rootimg_dir file://$installroot/$osver/$arch/"; mkpath("$rootimg_dir/var/lib/dpkg"); mkpath("$rootimg_dir/var/lib/apt"); unless ($imagename) { $pkglist= imgutils::get_profile_def_filename($osver, $profile, $arch, $customdir, "pkglist"); unless ($pkglist) { $pkglist= imgutils::get_profile_def_filename($osver, $profile, $arch, $pathtofiles, "pkglist"); } } if ($pkglist) { $updates{'pkglist'} = $pkglist if ($tempfile); } else { print "Unable to find package list for $profile!"; exit 1; } my %pkg_hash=imgutils::get_package_names($pkglist); my $index=1; my $pass; foreach $pass (sort {$a <=> $b} (keys(%pkg_hash))) { my $pkgnames = ""; foreach (keys(%{$pkg_hash{$pass}})) { if (($_ eq "PRE_REMOVE") || ($_ eq "POST_REMOVE") || ($_ eq "ENVLIST")) { next;} my $pa=$pkg_hash{$pass}{$_}; my @npa = (); # replace the kernel package with the name has the specific version foreach my $p (@$pa) { print "$p\n"; if ($p =~ /^linux-image-server$/ && $kernelver) { my $kernelname = "linux-image-".$kernelver."-server"; my $searchkern = $aptcachecmd . " search $kernelname"; my @kernpkgs = `$searchkern`; my $found = 0; foreach my $k (@kernpkgs) { if ($k =~ /\s*linux-image-server[^\s]*\s+([\w\.-]+)/) { my $version = $1; my $relversion = $kernelver; $relversion =~ s/\.[^\.]+$//; if ($version == $relversion) { $found++; } } } if ($found eq 0) { print "Cannot find the kernel with version $kernelver.\n"; exit 1; } push @npa, $kernelname; } elsif ($p =~ /^@/) { push @npa, "\"$p\""; } else { push @npa, $p; } } $pkgnames .= join(',', @npa); } my $envlist; if(exists $pkg_hash{$pass}{ENVLIST}){ $envlist = join(',', @{$pkg_hash{$pass}{ENVLIST}}); } print "$envlist $aptcmd1 --include=$pkgnames $aptcmd2\n"; my $rc = system("$envlist $aptcmd1 --include=$pkgnames $aptcmd2"); if ($rc) { print "apt invocation failed\n"; exit 1; } } print("Mount /proc, /dev, /sys, pkgdir and otherpkgdir to the rootimg.\n"); mount_chroot($rootimg_dir, $otherpkgsdir_local, $srcdir); # Add the local repo from MN temporarily for apt-get update/upgrade open($aptconfig,">","$rootimg_dir/etc/apt/sources.list"); print $aptconfig "deb file:///mnt/pkgdir/ $dist main\n"; close($aptconfig); #add the other package directory to for apt-get install open ($aptconfig,">","$rootimg_dir/etc/apt/sources.list.d/genimage.apt.list"); if ($otherpkgsdir_local){ print $aptconfig "deb file://$otherpkgsdir_local ./\n"; } if ($otherpkgsdir_internet){ print $aptconfig $otherpkgsdir_internet; } close($aptconfig); #backup the /etc/hosts & /etc/resolv.conf move("$rootimg_dir/etc/hosts", "$rootimg_dir/etc/hosts.bak"); move("$rootimg_dir/etc/resolv.conf", "$rootimg_dir/etc/resolv.conf.bak"); #copy the mn's /etc/hosts & /etc/resolv.conf to the rootimage copy("/etc/hosts", "$rootimg_dir/etc/hosts"); copy("/etc/resolv.conf", "$rootimg_dir/etc/resolv.conf"); #Now let's handle extra packages unless ($imagename) { $otherpkglist = imgutils::get_profile_def_filename($osver, $profile, $arch, $customdir, "otherpkgs.pkglist"); unless ($otherpkglist) { $otherpkglist=imgutils::get_profile_def_filename($osver, $profile, $arch, $pathtofiles, "otherpkgs.pkglist"); } } my %extra_hash=(); if ($otherpkglist) { $updates{'otherpkglist'} = $otherpkglist if ($tempfile); %extra_hash = imgutils::get_package_names($otherpkglist); } my %extrapkgnames; if (keys(%extra_hash) > 0) { my $index=1; foreach $pass (sort {$a <=> $b} (keys(%extra_hash))) { foreach (keys(%{$extra_hash{$pass}})) { if (($_ eq "PRE_REMOVE") || ($_ eq "POST_REMOVE") || ($_ eq "ENVLIST")) { next;} $index++; my $pa=$extra_hash{$pass}{$_}; $extrapkgnames{$pass} .= " " . join(' ', @$pa); } } $index--; foreach $pass (sort {$a <=> $b} (keys(%extra_hash))) { my $envlist; if(exists($extra_hash{$pass}{ENVLIST})){ $envlist = join(' ', @{$extra_hash{$pass}{ENVLIST}}); } # remove the packages that are specified in the otherpkgs.list files with leading '-' my $aptgetcmd_remove= "$aptgetcmd remove "; if (exists ($extra_hash{$pass}{'PRE_REMOVE'})) { my $pa=$extra_hash{$pass}{'PRE_REMOVE'}; my $rm_packges= join(' ', @$pa); if ($rm_packges) { print "$envlist $aptgetcmd_remove $rm_packges\n"; $rc = system("$envlist $aptgetcmd_remove $rm_packges"); } } # mount /proc file system since several packages need it. # install extra packages my $aptgetcmd_base = $aptgetcmd; $aptgetcmd .= " install "; # append extra pkg names to yum command if ($extrapkgnames{$pass}) { $aptgetcmd .= " $extrapkgnames{$pass} "; $aptgetcmd =~ s/ $/\n/; # debug #print "aptgetcmd=$aptgetcmd\n"; #my $repo=`cat /tmp/genimage.$$.yum.conf`; #print "repo=$repo"; print "$envlist $aptgetcmd\n"; my $rc = system("$envlist $aptgetcmd"); if ($rc) { print "apt-get invocation failed\n"; exit 1; } } else { print "No Packages marked for install\n"; } # remove the packages that are specified in the otherpkgs.list files with leading '--' if (exists ($extra_hash{$pass}{'POST_REMOVE'})) { my $pa=$extra_hash{$pass}{'POST_REMOVE'}; my $rm_packges= join(' ', @$pa); if ($rm_packges) { print "$envlist $aptgetcmd_remove $rm_packges\n"; $rc = system("$envlist $aptgetcmd_remove $rm_packges"); } } $aptgetcmd = $aptgetcmd_base; } } # run apt-get upgrade to update any installed debs # needed when running genimage again after updating software in repositories my $aptgetcmd_update = $yumcmd_base . " upgrade "; $rc = system("$aptgetcmd_update"); print("Umount /proc, /dev, /sys, pkgdir and otherpkgdir to the rootimg.\n"); umount_chroot($rootimg_dir); # ignore any return code # Add the local repo from MN my $master = xCAT::TableUtils->get_site_Master(); open($aptconfig,">","$rootimg_dir/etc/apt/sources.list"); print $aptconfig "deb http://$master$installroot/$osver/$arch/ $dist main\n"; close($aptconfig); #recover the /etc/hosts & /etc/reslov.conf `cd $rootimg_dir/etc/;mv -f hosts.bak hosts;mv -f resolv.conf.bak resolv.conf`; postscripts(); #run 'postscripts' } # Default to the first kernel found in the install image if nothing specified explicitly. # A more accurate guess than whatever the image build server happens to be running # If specified, that takes precedence. # if image has one, that is used # if all else fails, resort to uname -r like this script did before # Kernel name for s390x should be the same: vmlinuz-2.6.18-164.el5 my @KVERS= <$rootimg_dir/boot/vmlinuz-*>; foreach (@KVERS) { s/vmlinuz-//; } @KVERS= <$rootimg_dir/lib/modules/*> unless (scalar(@KVERS)); $basekernelver = basename(pop @KVERS) if (scalar(@KVERS)); $basekernelver = `uname -r` unless ($basekernelver); $kernelver = $basekernelver unless ($kernelver); chomp($kernelver); #$updates{'kernelver'} = $kernelver if ($tempfile); # copy the kernel to $destdir if ( -e "$rootimg_dir/boot/vmlinux-$kernelver") { cp("$rootimg_dir/boot/vmlinux-$kernelver", "$destdir/kernel"); } elsif ( -e "$rootimg_dir/boot/vmlinuz-$kernelver") { cp("$rootimg_dir/boot/vmlinuz-$kernelver", "$destdir/kernel"); } elsif ( -e "$rootimg_dir/boot/image-$kernelver") { cp("$rootimg_dir/boot/image-$kernelver", "$destdir/kernel"); } else { xdie("couldn't find the kernel file matched $kernelver in $rootimg_dir/boot"); } # Load driver update disk, and copy them to the root image my @dd_drivers = &load_dd(); # Push the drivers into the @ndrivers base on the order my @new_order = (); foreach my $dd (@dd_drivers) { unless (grep { $_ eq $dd} @ndrivers) { push @new_order, $dd; } print "Added driver $dd from driver update disk.\n"; } @ndrivers = (@new_order, @ndrivers); open($moddeps,"<","$rootimg_dir/lib/modules/$kernelver/modules.dep"); my @moddeps = <$moddeps>; my @checkdeps = @ndrivers; while (scalar @checkdeps) { my $driver = pop @checkdeps; my @lines = grep /\/$driver:/,@moddeps; foreach (@lines) { chomp; s/.*://; s/^\s*//; my @deps = split /\s+/,$_; my $dep; foreach $dep (@deps) { $dep =~ s/.*\///; unless (grep { $_ eq $dep } @ndrivers) { #only add if not added unshift (@checkdeps,$dep); #recursively check dependencies unshift (@ndrivers,$dep); print "Added $dep as an autodetected depedency\n"; } } } } close($moddeps); if (-d "$rootimg_dir/usr/share/dracut") { $dracutmode = 1; # get dracut version my $dracutver = `chroot $rootimg_dir dpkg-query -W dracut | awk '{print \$2}'| aek -F- {print \$1}'`; if ($dracutver =~ /^\d\d\d$/) { if ($dracutver >= "009") { $dracutdir = "dracut_009"; } else { $dracutdir = "dracut"; # The default directory } } print "Enter the dracut mode. Dracut version: $dracutver. Dracut directory: $dracutdir.\n"; } #-- run postinstall script unless ($imagename) { $postinstall_filename= imgutils::get_profile_def_filename($osver, $profile, $arch, $customdir, "postinstall"); unless ($postinstall_filename) { $postinstall_filename= imgutils::get_profile_def_filename($osver, $profile, $arch, $pathtofiles, "postinstall"); } } if ( $postinstall_filename ) { $updates{'postinstall'} = $postinstall_filename if ($tempfile); foreach my $postinstall ( split /,/, $postinstall_filename ) { if ( !-x $postinstall ) { print "postinstall script $postinstall is not executable\n"; exit 1; } my $rc = system($postinstall, $rootimg_dir,$osver,$arch,$profile); if($rc) { print "postinstall script $postinstall failed\n"; exit 1; } } } # all the attributes have been gathered # now, update the linuximage and osimage tables # TODO: do statelite and stateless share the same attributes? #BEGIN: PLEASE DO NOT CHANGE THE FOLLOWING CODE, genimage PLUGIN NEEDS TO PARSE THR OUTPUT if ($tempfile) { open(FILE, ">>$tempfile"); if ($imagename) { if (keys(%updates) > 0) { print FILE "The output for table updates starts here\n"; print FILE "table::linuximage\n"; print FILE "imagename::$imagename\n"; my @a=%updates; print FILE join('::',@a) . "\n"; print FILE "The output for table updates ends here\n"; } } else { $updates_os{'profile'} = $profile; $updates_os{'imagetype'} = 'linux'; $updates_os{'provmethod'} = 'netboot'; $updates_os{'osname'} = 'Linux'; $updates_os{'osvers'} = $osver; $updates_os{'osarch'} = $arch; # update the imagename for stateless print FILE "The output for table updates starts here\n"; print FILE "table::osimage\n"; print FILE "imagename::$osver-$arch-netboot-$profile\n"; my @a=%updates_os; print FILE join('::',@a) . "\n"; print FILE "The output for table updates ends here\n"; print FILE "The output for table updates starts here\n"; print FILE "table::linuximage\n"; print FILE "imagename::$osver-$arch-netboot-$profile\n"; my @a=%updates; print FILE join('::',@a) . "\n"; print FILE "The output for table updates ends here\n"; # update the imagename for statelite $updates_os{'provmethod'} = 'statelite'; print FILE "The output for table updates starts here\n"; print FILE "table::osimage\n"; print FILE "imagename::$osver-$arch-statelite-$profile\n"; my @a=%updates_os; print FILE join('::',@a) . "\n"; print FILE "The output for table updates ends here\n"; print FILE "The output for table updates starts here\n"; print FILE "table::linuximage\n"; print FILE "imagename::$osver-$arch-statelite-$profile\n"; my @a=%updates; print FILE join('::',@a) . "\n"; print FILE "The output for table updates ends here\n"; } close FILE; } #END # statelite .statelite directory added here. # this is where tmpfs will be created. mkpath "$rootimg_dir/.statelite"; # create place for NFS mounts. # this script will get the directories. # TODO: the file is re-copied in liteimg.pm my $cwd = $FindBin::Bin; unless (-f "$cwd/../add-on/statelite/rc.statelite") { print "Can't find $cwd/../add-on/statelite/rc.statelite!\n"; exit 1; } system("cp $cwd/../add-on/statelite/rc.statelite $rootimg_dir/etc/init.d/statelite"); # also need to add this file: # may have already been made into a symbolic link, if so ignore it unless ($dracutmode) { #in dracut mode, we delegate all this activity unless (-l "$rootimg_dir/var/lib/dhclient" ) { mkpath "$rootimg_dir/var/lib/dhclient/"; system("touch $rootimg_dir/var/lib/dhclient/dhclient-$prinic.leases"); } unless (-l "$rootimg_dir/var/lib/dhcp" ) { mkpath "$rootimg_dir/var/lib/dhcp/"; system("touch $rootimg_dir/var/lib/dhcp/dhclient-$prinic.leases"); } } if ($dracutmode) { # modify etc/rc.sysinit, prevent remounting # TODO: need to find one way to prevent remounting my $SYSINITFILE; my $TMPSYSINITFILE; if (-f "$rootimg_dir/etc/rc.sysinit") { # backup etc/rc.sysinit file before modifing it system("cp -a $rootimg_dir/etc/rc.sysinit $rootimg_dir/etc/rc.sysinit.backup"); open($SYSINITFILE, "$rootimg_dir/etc/rc.sysinit"); open($TMPSYSINITFILE, '>', "/tmp/rc.sysinit.tmp"); # find the following lines, # if remount_needed ; then # action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw / # fi # and change "if remount_needed ; then" to "if false; then" while(<$SYSINITFILE>) { if ($_ eq "if remount_needed ; then\n") { $_ = "if false; then\n"; } print $TMPSYSINITFILE $_; } close($SYSINITFILE); close($TMPSYSINITFILE); cp("/tmp/rc.sysinit.tmp", "$rootimg_dir/etc/rc.sysinit"); } } # before mkinitrd, run depmod to generate modules.dep system("chroot $rootimg_dir depmod $kernelver"); #delete the apt cache system("rm -rf $rootimg_dir/var/cache/apt/*"); # for the genimage-enchement, need to create two initial ramdisks, # one is for stateless # the other one is for statelite if ($dracutmode) { mkinitrd_dracut("statelite"); mkinitrd_dracut("stateless"); } else { my @drivers; # backup of @ndrivers push @drivers, @ndrivers; mkinitrd("statelite"); @ndrivers=(); push @ndrivers, @drivers; mkinitrd("stateless"); } sub getlibs { my $file = shift; my $liblist = `chroot $rootimg_dir ldd $file`; my @libs = split/\n/,$liblist; my @return; foreach (@libs) { unless (/=>/) { (my $wjnk, my $lib,my $jnk) = split /\s+/,$_,3; $lib =~ s/^\///; $libhash{$lib}=1; next; } (my $temp1,my $temp2) = split />/,$_,2; (my $whitespace,$temp1,$temp2) = split /\s+/,$temp2,4; unless ($temp1 =~ /\//) { next; } $temp1 =~ s/^\///; $libhash{$temp1}=1; } } sub mkinitrd_dracut { my ($mode) = @_; # the mode is for statelite or stateless my $dracutmpath = "$rootimg_dir/usr/share/dracut/modules.d/97xcat"; mkpath($dracutmpath); my $perm = (stat("$fullpath/$dracutdir/check"))[2]; cp("$fullpath/$dracutdir/check", $dracutmpath); chmod($perm&07777, "$dracutmpath/check"); foreach (@ndrivers) { s/\.ko$//; } my $add_drivers = join(' ', @ndrivers); my $DRACUTCONF; if ($mode eq "statelite") { # for statelite cp("$fullpath/$dracutdir/install.statelite","$dracutmpath/install"); $perm = (stat("$fullpath/$dracutdir/install.statelite"))[2]; chmod($perm&07777, "$dracutmpath/install"); cp("$fullpath/$dracutdir/xcat-prepivot.sh",$dracutmpath); $perm = (stat("$fullpath/$dracutdir/xcat-prepivot.sh"))[2]; chmod($perm&07777, "$dracutmpath/xcat-prepivot.sh"); # update etc/dracut.conf open($DRACUTCONF, '>', "$rootimg_dir/etc/dracut.conf"); print $DRACUTCONF qq{dracutmodules+="xcat nfs base network kernel-modules"\n}; print $DRACUTCONF qq{add_drivers+="$add_drivers"\n}; print $DRACUTCONF qq{filesystems+="nfs"\n}; close $DRACUTCONF; } elsif ($mode eq "stateless") { cp("$fullpath/$dracutdir/install.netboot","$dracutmpath/install"); $perm = (stat("$fullpath/$dracutdir/install.netboot"))[2]; chmod($perm&07777, "$dracutmpath/install"); cp("$fullpath/$dracutdir/xcat-cmdline.sh","$dracutmpath/"); $perm = (stat("$fullpath/$dracutdir/xcat-cmdline.sh"))[2]; chmod($perm&07777, "$dracutmpath/xcat-cmdline.sh"); if ($prinic) { my $optspec; open($optspec,'>>',"$dracutmpath/xcat-cmdline.sh"); print $optspec "PRINIC=$prinic\n"; close $optspec; } cp("$fullpath/$dracutdir/xcatroot","$dracutmpath/"); $perm = (stat("$fullpath/$dracutdir/xcatroot"))[2]; chmod($perm&07777, "$dracutmpath/xcatroot"); cp("$fullpath/$dracutdir/installkernel", "$dracutmpath/"); $perm = (stat("$fullpath/$dracutdir/installkernel"))[2]; chmod($perm&07777, "$dracutmpath/installkernel"); # update etc/dracut.conf open($DRACUTCONF, '>', "$rootimg_dir/etc/dracut.conf"); print $DRACUTCONF qq{dracutmodules+="xcat nfs base network kernel-modules"\n}; print $DRACUTCONF qq{add_drivers+="$add_drivers"\n}; close $DRACUTCONF; } else { xdie "the mode: $mode is not supported by genimage"; } system("chroot $rootimg_dir dracut -f /tmp/initrd.$$.gz $kernelver"); print "the initial ramdisk for $mode is generated successfully.\n"; move("$rootimg_dir/tmp/initrd.$$.gz", "$destdir/initrd-$mode.gz"); } sub mkinitrd { my ($mode) = @_; # statelite or stateless if($mode eq "statelite") { push @ndrivers, "fscache.ko"; push @ndrivers, "sunrpc.ko"; push @ndrivers, "lockd.ko"; push @ndrivers, "nfs_acl.ko"; push @ndrivers, "auth_rpcgss.ko"; push @ndrivers, "nfs.ko"; # Additional modules needed on s390x if ($arch eq "s390x") { # The network drivers need to be loaded in this order unshift @ndrivers, "ccwgroup.ko"; unshift @ndrivers, "qdio.ko"; } } mkpath("/tmp/xcatinitrd.$$/bin"); symlink("bin","/tmp/xcatinitrd.$$/sbin"); mkpath("/tmp/xcatinitrd.$$/usr/bin"); mkpath("/tmp/xcatinitrd.$$/usr/sbin"); mkpath("/tmp/xcatinitrd.$$/usr/lib"); mkpath("/tmp/xcatinitrd.$$/usr/lib64"); mkpath("/tmp/xcatinitrd.$$/lib/firmware"); mkpath("/tmp/xcatinitrd.$$/lib64/firmware"); mkpath("/tmp/xcatinitrd.$$/proc"); mkpath("/tmp/xcatinitrd.$$/sys"); mkpath("/tmp/xcatinitrd.$$/dev/mapper"); mkpath("/tmp/xcatinitrd.$$/sysroot"); mkpath("/tmp/xcatinitrd.$$/etc/ld.so.conf.d"); mkpath("/tmp/xcatinitrd.$$/etc/udhcpc"); mkpath("/tmp/xcatinitrd.$$/usr/share/udhcpc"); mkpath("/tmp/xcatinitrd.$$/var/lib/dhclient"); mkpath("/tmp/xcatinitrd.$$/lib/modules/$kernelver"); my $inifile; # start writing to the init script. open($inifile,">","/tmp/xcatinitrd.$$/init"); print $inifile "#!/bin/busybox sh\n"; # add some functions print $inifile < <\\ \\____/ | \\ | /__/\\_ \\\\______ /\\____|__ /____| \\/ \\/ \\/ ' echo -e "\$RESET" } EOS1 print $inifile "busybox mount -t proc /proc /proc\n"; print $inifile "busybox --install\n"; print $inifile "mount -t sysfs /sys /sys\n"; print $inifile "mount -o mode=0755 -t tmpfs /dev /dev\n"; print $inifile "mkdir /dev/pts\n"; print $inifile "mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts\n"; print $inifile "mkdir /run\n"; print $inifile "mount -t tmpfs -o \"nosuid,size=20%,mode=0755\" tmpfs /run\n"; print $inifile "mkdir /dev/shm\n"; print $inifile "mkdir /dev/mapper\n"; print $inifile "mknod /dev/null c 1 3\n"; print $inifile "mknod /dev/zero c 1 5\n"; print $inifile "mknod /dev/systty c 4 0\n"; print $inifile "mknod /dev/tty c 5 0\n"; print $inifile "mknod /dev/console c 5 1\n"; print $inifile "mknod /dev/ptmx c 5 2\n"; print $inifile "mknod /dev/rtc c 10 135\n"; print $inifile "mknod /dev/tty0 c 4 0\n"; print $inifile "mknod /dev/tty1 c 4 1\n"; print $inifile "mknod /dev/tty2 c 4 2\n"; print $inifile "mknod /dev/tty3 c 4 3\n"; print $inifile "mknod /dev/tty4 c 4 4\n"; print $inifile "mknod /dev/tty5 c 4 5\n"; print $inifile "mknod /dev/tty6 c 4 6\n"; print $inifile "mknod /dev/tty7 c 4 7\n"; print $inifile "mknod /dev/tty8 c 4 8\n"; print $inifile "mknod /dev/tty9 c 4 9\n"; print $inifile "mknod /dev/tty10 c 4 10\n"; print $inifile "mknod /dev/tty11 c 4 11\n"; print $inifile "mknod /dev/tty12 c 4 12\n"; print $inifile "mknod /dev/ttyS0 c 4 64\n"; print $inifile "mknod /dev/ttyS1 c 4 65\n"; print $inifile "mknod /dev/ttyS2 c 4 66\n"; print $inifile "mknod /dev/ttyS3 c 4 67\n"; foreach (@ndrivers) { print $inifile "insmod /lib/$_\n"; } # Start udev print $inifile < /dev/null && export DEBUG=1 # check the kernel parameter at first # if one parameter for the booting device is there, we will use it # TODO # ( netdevice is recognized by SLES, ) # ( Dracut has one "network" module to handle the booting network devices, which use "ifname" ) # ( What should the other redhat versions use ? netdev= and BOOTIF= ) # besides this action, the following code is also used to get the XCAT= value, which is for XCAT server # TODO: does "anaconda.busybox sh" support "set " ? PRINIC=$prinic NODESTATUS='y' XCATIPORT="3002" for i in `cat /proc/cmdline`; do KEY=`echo \$i |awk -F= '{print \$1}'` if [ "\$KEY" == 'netdev' ]; then NETDEV=`echo \$i |awk -F= '{print \$2}'` elif [ "\$KEY" == 'BOOTIF' ]; then VALUE=`echo \$i |awk -F= '{print \$2}'|sed -e s/^01-// -e s/-/:/g` BOOTIF=`ifconfig -a|grep -i "hwaddr \$VALUE"|awk '{print \$1}'` elif [ "\$KEY" == 'XCAT' ]; then VALUE=`echo \$i |awk -F= '{print \$2}'` # format: XCAT=xcatmaster:3001 XCATSERVER=\$VALUE elif [ "\$KEY" == 'XCATIPORT' ]; then VALUE=`echo \$i |awk -F= '{print \$2}'` # format: XCAT=xcatmaster:3001 XCATIPORT=\$VALUE fi #if "nonodestatus" specified,do not update the nodestatus if [ \$i == 'nonodestatus' ]; then NODESTATUS='n' fi done if [ -z "\$IFACE" ]; then if [ ! -z "\$NETDEV" ]; then IFACE=\$NETDEV elif [ ! -z "\$BOOTIF" ]; then IFACE=\$BOOTIF elif [ ! -z "\$PRINIC" ]; then IFACE=\$PRINIC else echo "\${RED}Couldn't find the proper booting device, switch to shell...\${RESET}" shell exit fi fi export IFACE=\$IFACE netstart \$IFACE while ! ifconfig | grep 'inet addr'; do echo -e "\${RED}Failed to acquire address, retrying \${RESET}" sleep 5 netstart \$IFACE done ifconfig lo 127.0.0.1 ifconfig lo up XCATMASTER=`echo \$XCATSERVER|awk -F: '{print \$1}'` #update nodelist.nodestatus to "netbooting" if [ \$NODESTATUS != 'n' ]; then /tmp/updateflag \$XCATMASTER \$XCATIPORT "installstatus netbooting" fi cd / for i in `cat /proc/cmdline`; do KEY=`echo \$i |awk -F= '{print \$1}'` if [ "\$KEY" == 'imgurl' ]; then VALUE=`echo \$i |awk -F= '{print \$2}'` if [ "http" == "`echo \$VALUE|awk -F: '{print \$1}'`" ]; then #NOTE needs FT retry code to scale #NOTE: should prob have max count FILENAME=`echo \$VALUE|awk -F/ '{print \$NF}'` while [ ! -r "\$FILENAME" ]; do echo Getting \$VALUE... if ! wget \$VALUE; then ST=`expr \$RANDOM % 5` sleep \$ST rm -f \$FILENAME fi done fi if [ "nfs" == "`echo \$VALUE|awk -F: '{print \$1}'`" ]; then NFS=1 SERVER=`echo \$VALUE|awk -F/ '{print \$3}'` ROOTDIR=`echo \$VALUE|awk -F/ '{for(i=4;i<=NF;i++) printf "/%s",\$i}'` fi # for NFS root elif [ "\$KEY" == 'NFSROOT' ]; then NFSROOT=1 VALUE=`echo \$i |awk -F= '{print \$2}'` SERVER=`echo \$VALUE|awk -F: '{print \$1}'` ROOTDIR=`echo \$VALUE|awk -F/ '{for(i=2;i<=NF;i++) printf "/%s",\$i}'` elif [ "\$KEY" == 'STATEMNT' ]; then STATELITE=1 VALUE=`echo \$i |awk -F= '{print \$2}'` # the VALUE may be null if [ ! -z \$VALUE ]; then SNAPSHOTSERVER=`echo \$VALUE|awk -F: '{print \$1}'` SNAPSHOTROOT=`echo \$VALUE|awk -F/ '{for(i=2;i<=NF;i++) printf "/%s",\$i}'` # may be that there is not server and just a directory. if [ -z \$SNAPSHOTROOT ] then SNAPSHOTROOT=\$SNAPSHOTSERVER SNAPSHOTSERVER= fi fi fi done # show xCAT logo fancydisplay echo 0 > /proc/sys/vm/zone_reclaim_mode #Avoid kernel bug # STATELITE code here: if [ "\$STATELITE" = "1" ]; then echo Setting up Statelite # for loop back mouting capability! mknod /dev/loop0 b 7 0 mkdir -p \$NEWROOT MAXTRIES=5 ITER=0 ME=`hostname` if [ "\$NFSROOT" = "1" ]; then while ! mount.nfs \${SERVER}:\${ROOTDIR}/rootimg \$NEWROOT -r -n -o nolock,rsize=32768,tcp,nfsvers=3,timeo=14; do ITER=\$(expr \$ITER + 1) if [ "\$ITER" == "\$MAXTRIES" ]; then echo "You are dead. rpower \$ME boot to play again." echo "Possible problems: 1. This initrd wasn't craeted for the statelite node? 2. Is DNS set up? Maybe that's why I can't mount \${SERVER}. 3. The nfs modules aren't set right in this initfs?" shell exit fi echo -e "\${RED}Could not mount \$SERVER:\$ROOTDIR on \$NEWROOT \$RESET" RS=`expr \$RANDOM % 30` echo -e "Trying again in \$RS seconds" sleep \$RS done elif [ "\$NFS" = "1" ]; then echo -e "\${RED}The \"imgurl=\" value should not be nfs-type if statelite mode is enabled \$RESET" shell exit else # for statelite mode on top of the ramdisk EOMS print $inifile "if [ -r /rootimg-statelite.gz ]; then\n"; print $inifile "echo Setting up RAM-root tmpfs.\n"; if ($rootlimit) { print $inifile " mount -o size=$rootlimit,mode=755 -t tmpfs rootfs \$NEWROOT \n"; } else { print $inifile " mount -o mode=755 -t tmpfs rootfs \$NEWROOT\n"; } print $inifile </dev/null && shell echo 0x100 > /proc/sys/kernel/real-root-dev export keep_old_ip=yes mount -n --bind /dev/ \$NEWROOT/dev umount /sys umount /proc cp /etc/hostname /sysroot/etc/hostname cp /etc/resolv.conf /sysroot/etc/resolv.conf if ! exec /sbin/pivot_root -c /dev/console \$NEWROOT /sbin/init; then echo "" echo -e "\${RED}Couldn't pivot_root. Something must be wrong with the root image.\${RESET}" shell fi fi # END NFSROOT/Statelite code if [ -r /rootimg.sfs ]; then echo Setting up squashfs with ram overlay. mknod /dev/loop0 b 7 0 mkdir -p /ro mkdir -p /rw mount -t squashfs /rootimg.sfs /ro mount -t tmpfs rw /rw mount -t aufs -o dirs=/rw:/ro mergedroot \$NEWROOT mkdir -p \$NEWROOT/ro mkdir -p \$NEWROOT/rw mount --move /ro \$NEWROOT/ro mount --move /rw \$NEWROOT/rw EOMS print $inifile "elif [ -r /rootimg.gz ]; then\n"; print $inifile "echo Setting up RAM-root tmpfs.\n"; if ($rootlimit) { print $inifile " mount -o size=$rootlimit,mode=755 -t tmpfs rootfs \$NEWROOT\n"; } else { print $inifile " mount -o mode=755 -t tmpfs rootfs \$NEWROOT\n"; } print $inifile " cd \$NEWROOT\n"; print $inifile " echo -n \"Extracting root filesystem:\"\n"; print $inifile " if [ -x /bin/cpio ]; then\n"; print $inifile " zcat /rootimg.gz |/bin/cpio -idum\n"; print $inifile " else\n"; print $inifile " zcat /rootimg.gz |cpio -idum\n"; print $inifile " fi\n"; print $inifile " echo Done\n"; print $inifile "else\n"; print $inifile " echo -n Failed to download image, panicing in 5...\n"; print $inifile " for i in 4 3 2 1 0; do\n"; print $inifile " /bin/sleep 5\n"; print $inifile " echo -n \$i...\n"; print $inifile " done\n"; print $inifile " echo\n"; print $inifile <"."/tmp/xcatinitrd.$$/bin/netstart"); print $inifile "#!/sbin/sh\n"; print $inifile "udhcpc -n -q -i \${1}\n"; close($inifile); open($inifile,">"."/tmp/xcatinitrd.$$/usr/share/udhcpc/default.script"); print $inifile <<'EOF'; #!/bin/sh # udhcpc script edited by Tim Riker [ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1 RESOLV_CONF="/etc/resolv.conf" [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" [ -n "$subnet" ] && NETMASK="netmask $subnet" case "$1" in deconfig) /sbin/ifconfig $interface 0.0.0.0 ;; renew|bound) /sbin/ifconfig $interface $ip $BROADCAST $NETMASK if [ -n "$hostname" ] ; then hostname $hostname echo $hostname > /etc/hostname fi if [ -n "$router" ] ; then echo "deleting routers" while route del default gw 0.0.0.0 dev $interface ; do : done for i in $router ; do route add default gw $i dev $interface done fi echo -n > $RESOLV_CONF [ -n "$domain" ] && echo search $domain >> $RESOLV_CONF for i in $dns ; do echo adding dns $i echo nameserver $i >> $RESOLV_CONF done ;; esac exit 0 EOF close($inifile); #if "nonodestatus" specified,do not update the nodestatus system("mkdir -p /tmp/xcatinitrd.$$/tmp/"); open($inifile, ">","/tmp/xcatinitrd.$$/tmp/updateflag"); print $inifile < /tmp/ncarg nc \$1 \$2 -w 60 -e /tmp/updateflag else retrytimes=0 cmd="" while [ "\$cmd" != "done" ]; do retrytimes=`expr \$retrytimes + 1` if [ \$retrytimes -eq 60 ]; then break; fi read -t 60 cmd if [ "\$cmd" == "ready" ]; then head -n 1 /tmp/ncarg rm -rf /tmp/ncarg fi done fi EOMS close($inifile); chmod(0755,"/tmp/xcatinitrd.$$/usr/share/udhcpc/default.script"); chmod(0755,"/tmp/xcatinitrd.$$/init"); chmod(0755,"/tmp/xcatinitrd.$$/bin/netstart"); chmod(0755,"/tmp/xcatinitrd.$$/tmp/updateflag"); @filestoadd=(); foreach (@ndrivers) { if (-f "$customdir/$_") { push @filestoadd,[$_,"lib/$_"]; } elsif (-f "$pathtofiles/$_") { push @filestoadd,[$_,"lib/$_"]; } } # add rsync for statelite foreach ("bin/busybox","bin/bash", "sbin/mount.nfs", "usr/bin/rsync", "sbin/insmod", "sbin/udevd", "sbin/udevadm", "sbin/modprobe", "sbin/blkid", "sbin/depmod") { getlibs($_); push @filestoadd,$_; } # Additional binaries needed for udev on s390x if ($arch eq "s390x") { foreach ("sbin/udevsettle", "sbin/udevtrigger", "sbin/udevd", "sbin/depmod") { getlibs($_); push @filestoadd,$_; } } if ($arch =~ /x86_64/) { push @filestoadd,"lib64/libnss_dns.so.2"; push @filestoadd,"lib64/libresolv.so.2"; } else { push @filestoadd,"lib/libnss_dns.so.2"; } push @filestoadd,keys %libhash; find(\&isnetdriver, <$rootimg_dir/lib/modules/$kernelver/*>); foreach (@filestoadd) { if (ref($_)) { #print "$_->[0], $_->[1]\n"; my $srcpath = "$rootimg_dir/".$_->[0]; if (-f "$customdir/".$_->[0]) { $srcpath="$customdir/".$_->[0]; } elsif (-f "$pathtofiles/".$_->[0]) { $srcpath="$pathtofiles/".$_->[0]; } mkpath(dirname("/tmp/xcatinitrd.$$/".$_->[1])); copy($srcpath,"/tmp/xcatinitrd.$$/".$_->[1]); chmod 0755,"/tmp/xcatinitrd.$$/".$_->[1]; } else { #print "$_\n"; my $srcpath = "$rootimg_dir/$_"; if (-f "$customdir/$_") { $srcpath = "$customdir/$_"; } elsif (-f "$pathtofiles/$_") { $srcpath = "$pathtofiles/$_"; } mkpath(dirname("/tmp/xcatinitrd.$$/$_")); copy("$srcpath","/tmp/xcatinitrd.$$/$_"); chmod 0755,"/tmp/xcatinitrd.$$/".$_; } } if ( -d "$rootimg_dir/lib/firmware/" ){ system("cp -r $rootimg_dir/lib/firmware/* /tmp/xcatinitrd.$$/lib/firmware"); } system("chroot /tmp/xcatinitrd.$$/ depmod $kernelver"); # Copy udev and network scripts into initrd for s390x, which also works for other platforms # udev system("mkdir -p /tmp/xcatinitrd.$$/etc/udev"); system("cp -r $rootimg_dir/etc/udev/* /tmp/xcatinitrd.$$/etc/udev"); system("mkdir -p /tmp/xcatinitrd.$$/lib/udev"); system("cp -r $rootimg_dir/lib/udev/* /tmp/xcatinitrd.$$/lib/udev"); system("mkdir -p /tmp/xcatinitrd.$$/proc/self"); system("cp -r /proc/self/oom_adj /tmp/xcatinitrd.$$/proc/self"); # Network related scripts #system("echo $kernelver\n"); #system("mkdir -p /tmp/xcatinitrd.$$/sbin"); #system("cp -r $rootimg_dir/sbin/* /tmp/xcatinitrd.$$/sbin"); #system("mkdir -p /tmp/xcatinitrd.$$/lib/modules/$kernelver"); #system("cp -r $rootimg_dir/lib/modules/$kernelver/modules.dep /tmp/xcatinitrd.$$/lib/modules/$kernelver/modules.dep"); #system("mkdir -p /tmp/xcatinitrd.$$/etc/init.d"); #system("cp -r $rootimg_dir/etc/init.d/* /tmp/xcatinitrd.$$/etc/init.d"); #system("mkdir -p /tmp/xcatinitrd.$$/lib64"); #system("cp -r $rootimg_dir/lib64/* /tmp/xcatinitrd.$$/lib64"); #system("mkdir -p /tmp/xcatinitrd.$$/var/run/netreport"); symlink("busybox","/tmp/xcatinitrd.$$/bin/pivot_root"); #copy("$rootimg_dir/lib/modules/*d","/tmp/xcatinitrd.$$/$_"); system("cd /tmp/xcatinitrd.$$;find .|cpio -H newc -o|gzip -9 -c - > $destdir/initrd-$mode.gz"); system("rm -rf /tmp/xcatinitrd.$$"); } sub isaptdir { if ($File::Find::name =~ /\/Packages.gz$/) { my $location = $File::Find::name; $location =~ s/\/Packages.gz$//; push @aptdirs,$location; } } sub isnetdriver { foreach (@ndrivers) { if ($File::Find::name =~ /\/$_/) { my $filetoadd = $File::Find::name; $filetoadd =~ s!$rootimg_dir/!!; push @filestoadd,[$filetoadd,"lib/$_"]; } } } sub postscripts { generic_post(); # TODO: workaround for kdump on RHEL6 # add one fake command: fsck.nfs unless ( -x "$rootimg_dir/sbin/fsck.nfs" ) { system("echo true > $rootimg_dir/sbin/fsck.nfs; chmod a+x $rootimg_dir/sbin/fsck.nfs"); } if( ! -d "$rootimg_dir/opt/xcat/") { mkdir "$rootimg_dir/opt/xcat/"; } copy ("$installroot/postscripts/xcatdsklspost", "$rootimg_dir/opt/xcat/"); chmod '0755', "$rootimg_dir/opt/xcat/xcatdsklspost"; } sub generic_post { #This function is meant to leave the image in a state approximating a normal install my $cfgfile; unlink("$rootimg_dir/dev/null"); system("mknod $rootimg_dir/dev/null c 1 3"); open($cfgfile,">","$rootimg_dir/etc/fstab"); print $cfgfile "devpts /dev/pts devpts gid=5,mode=620 0 0\n"; print $cfgfile "tmpfs /dev/shm tmpfs defaults 0 0\n"; print $cfgfile "proc /proc proc defaults 0 0\n"; print $cfgfile "sysfs /sys sysfs defaults 0 0\n"; if ($tmplimit) { print $cfgfile "tmpfs /tmp tmpfs defaults,size=$tmplimit 0 2\n"; print $cfgfile "tmpfs /var/tmp tmpfs defaults,size=$tmplimit 0 2\n"; } else { print $cfgfile "tmpfs /tmp tmpfs defaults,size=10m 0 2\n"; print $cfgfile "tmpfs /var/tmp tmpfs defaults,size=10m 0 2\n"; } my $rootfs_name=$profile."_".$arch; print $cfgfile "$rootfs_name / tmpfs rw 0 1\n"; open($cfgfile,">","$rootimg_dir/etc/resolv.conf"); print $cfgfile "#Dummy resolv.conf to make boot cleaner"; close($cfgfile); # Create the ifcfg-x file for diskless node. But keep the ONBOOT=no # to skip the break of nfs-based boot if ($prinic) { open($cfgfile,">","$rootimg_dir/etc/network/interfaces"); print $cfgfile "auto $prinic\niface $prinic inet dhcp\n"; close($cfgfile); } foreach (split /,/,$othernics) { if (/^$/) { next; } open($cfgfile,">>","$rootimg_dir/etc/network/interfaces"); print $cfgfile "auto $_\niface $_ inet dhcp\n"; close($cfgfile); } # securetty not needed on s390x if ($arch ne "s390x") { open($cfgfile,">>","$rootimg_dir/etc/securetty"); print $cfgfile "ttyS0\n"; print $cfgfile "ttyS1\n"; close($cfgfile); } my @passwd; open($cfgfile,"<","$rootimg_dir/etc/passwd"); @passwd = <$cfgfile>; close($cfgfile); open($cfgfile,">","$rootimg_dir/etc/passwd"); foreach (@passwd) { if (/^root:/) { s/^root:\*/root:x/ } print $cfgfile $_; } close($cfgfile); foreach (<$rootimg_dir/etc/skel/.*>) { if (basename($_) eq '.' or basename($_) eq '..') { next; } copy $_,"$rootimg_dir/root/"; } unless ( -r <$rootimg_dir/etc/rc3.d/S??network>) { symlink "/etc/init.d/networking","$rootimg_dir/etc/rc3.d/S10networking"; } # setup the ttyS configure file open($cfgfile, ">", "$rootimg_dir/etc/init/ttyS.conf"); print $cfgfile "start on stopped rc RUNLEVEL=[2345] and "; print $cfgfile "(not-container or container container CONTAINER=lxc or container CONTAINER=lxc-libvirt) \n"; print $cfgfile "stop on runlevel [!2345] \n"; print $cfgfile "respawn \n"; print $cfgfile "script\n"; print $cfgfile " for i in `cat /proc/cmdline`; do\n"; print $cfgfile " KEY=`echo \$i|cut -d= -f 1` \n"; print $cfgfile " if [ \"\$KEY\" == \"console\" -a \"\$i\" != \"console=tty0\" ]; then \n"; print $cfgfile " VALUE=`echo \$i | cut -d= -f 2` \n"; print $cfgfile " COTTY=`echo \$VALUE|cut -d, -f 1` \n"; print $cfgfile " COSPEED=`echo \$VALUE|cut -d, -f 2|cut -dn -f 1` \n"; print $cfgfile " exec /sbin/getty -L \$COSPEED \$COTTY vt102 \n"; print $cfgfile " break \n"; print $cfgfile " fi \n"; print $cfgfile " done\n"; print $cfgfile "end script\n"; copy("$installroot/postscripts/xcatpostinit", "$rootimg_dir/etc/init.d/xcatpostinit"); #the ubuntu default run level is 2 chmod(0755, "$rootimg_dir/etc/init.d/xcatpostinit"); system("cd $rootimg_dir/etc/rc2.d; ln -sf ../init.d/xcatpostinit S61xcatpostinit"); #change the /bin/sh link to /bin/bash system("cd $rootimg_dir/bin/; ln -sf bash sh"); } my $driver_name; my $real_path; sub get_path () { if ($File::Find::name =~ /\/$driver_name/) { $real_path = $File::Find::name; } } #load the driver update disk, and return the driver names by loading order sub load_dd () { # Get the Driver Update Disk images, it can be .img or .iso if (! -d "$installroot/driverdisk/$osver/$arch") { return (); } my @dd_list = `find $installroot/driverdisk/$osver/$arch -type f`; chomp(@dd_list); if (! @dd_list) { return (); } # Create the work space for initrd hack my $dd_dir = mkdtemp("/tmp/ddtmpXXXXXXX"); mkpath "$dd_dir/mnt"; mkpath "$dd_dir/mods"; my @dd_drivers = (); #dirver name # Loading drivers from each Driver Disk foreach my $dd (@dd_list) { my $rc = system ("mount -o loop $dd $dd_dir/mnt"); if ($rc) { print "mount the Driver Disk $dd failed.\n"; next; } if (! (-f "$dd_dir/mnt/rhdd" || -f "$dd_dir/mnt/modinfo" || -f "$dd_dir/mnt/modules.dep" || -f "$dd_dir/mnt/modules.cgz")) { print "The Driver Disk $dd has not correct format.\n"; system ("umount -f $dd_dir/mnt"); next; } # Load the modinfo open($modinfo, "<", "$dd_dir/mnt/modinfo"); my @modinfo_lines = <$modinfo>; my $mod_ver = shift @modinfo_lines; chomp($mod_ver); if ($mod_ver !~ /^Version 0/) { print "The Driver Disk $dd has unknown version.\n"; system ("umount -f $dd_dir/mnt"); next; } foreach my $line (@modinfo_lines) { if ($line !~ /^Version/ && $line =~ /^(\w+)/) { chomp($line); if ($line =~ /^\s*$/) { next; } $line =~ s/$/\.ko/; push @dd_drivers, $line; } } close($modinfo); # Copy the firmware if (-d "$dd_dir/mnt/firmware") { system ("cp -rf $dd_dir/mnt/firmware $rootimg_dir/lib/firmware"); } # Load the modules.cgz system ("cd $dd_dir/mods; gunzip -c $dd_dir/mnt/modules.cgz |cpio -id"); if (! -d "$rootimg_dir/lib/modules/$kernelver/kernel/drivers/driverdisk") { mkpath "$rootimg_dir/lib/modules/$kernelver/kernel/drivers/driverdisk"; } # Copy the drivers to the root image my @drivers = `find $dd_dir/mods/$kernelver/$arch/ -type f`; foreach my $d (@drivers) { chomp($d); $driver_name = $d; $driver_name =~ s/.*\///; $real_path = ""; find (\&get_path, <$rootimg_dir/lib/modules/$kernelver/*>); if ($real_path eq "") { system ("cp $d $rootimg_dir/lib/modules/$kernelver/kernel/drivers/driverdisk"); } else { system ("cp $d $real_path"); } } rmtree "$dd_dir/mods/*"; my $rc = system ("umount -f $dd_dir/mnt"); if ($rc) { print "umount the directory $dd_dir/mnt failed\n"; exit 1; } } # Generate the dependency relationship system ("chroot '$rootimg_dir' depmod $kernelver"); # Clean the env rmtree "$dd_dir"; return @dd_drivers; } sub mount_chroot { my $rootimage_dir = shift; my $otherpkgdir = shift; my $pkgdir = shift; mkdir("$rootimage_dir/mnt/pkgdir"); mkdir("$rootimage_dir/mnt/otherpkgdir"); #system("mount -o bind /dev $rootimage_dir/dev"); #system("mount -o bind /proc $rootimage_dir/proc"); #system("mount -o bind /sys $rootimage_dir/sys"); system("mount -o bind $pkgdir $rootimage_dir/mnt/pkgdir"); if ($otherpkgdir){ system("mount -o bind $otherpkgdir $rootimage_dir/mnt/otherpkgdir"); } } sub umount_chroot { my $rootimage_dir = shift; #system("umount $rootimage_dir/dev"); #system("umount $rootimage_dir/proc"); #system("umount $rootimage_dir/sys"); system("umount $rootimage_dir/mnt/pkgdir"); system("umount $rootimage_dir/mnt/otherpkgdir"); rmdir("$rootimage_dir/mnt/pkgdir"); rmdir("$rootimage_dir/mnt/otherpkgdir"); } sub usage { print 'Usage: genimage [ -i ] [ -n ] [-r ] -o -p -k [--permission ] [--interactive]'."\n"; print " --permission only works with statelite mode\n"; print "Examples:\n"; print " genimage -i eth0 -n tg3 -o centos5.1 -p compute \n"; print " genimage -i eth0 -r eth1,eth2 -n tg3,bnx2 -o centos5.1 -p compute --interactive\n"; print " genimage -i eth0 -n igb,e1000e,e1000,bnx2,tg3 -o centos5.4 -p nfsroot\n"; print " genimage -i eth0 -n igb,e1000e,e1000,bnx2,tg3 -o centos5.4 -p nfsroot --permission 777\n"; return 0; }