# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT_plugin::copycds; use strict; use warnings; use Storable qw(dclone); use xCAT::Table; use Thread qw(yield); use Data::Dumper; use Getopt::Long; use File::Basename; use File::Spec; use Digest::MD5 qw(md5_hex); use Cwd; Getopt::Long::Configure("bundling"); Getopt::Long::Configure("pass_through"); my $processed = 0; my $callback; sub handled_commands { return { copycds => "copycds", } } my $identified; sub take_answer { #TODO: Intelligently filter and decide things my $resp = shift; $callback->($resp); $identified = 1; } sub process_request { my $request = shift; $callback = shift; my $doreq = shift; my $distname = undef; my $arch = undef; my $help = undef; my $inspection = undef; my $path = undef; my $noosimage = undef; my $nonoverwrite = undef; my $specific = undef; $identified = 0; $::CDMOUNTPATH = "/var/run/xcat/mountpoint"; my $existdir = getcwd; if ($request->{arg}) { @ARGV = @{ $request->{arg} }; } GetOptions( 'n|name|osver=s' => \$distname, 'a|arch=s' => \$arch, 'h|help' => \$help, 'i|inspection' => \$inspection, 'p|path=s' => \$path, 'o|noosimage' => \$noosimage, 's|specific' => \$specific, 'w|nonoverwrite' => \$nonoverwrite, ); if ($help) { $callback->({ info => "copycds [{-p|--path}=path] [{-n|--name|--osver}=distroname] [{-a|--arch}=architecture] [-i|--inspection] [{-o|--noosimage}] [{-w|--nonoverwrite}] 1st.iso [2nd.iso ...]." }); return; } if ($arch and $arch =~ /i.86/) { $arch = 'x86'; } my @args = @ARGV; #copy ARGV unless ($#args >= 0) { $callback->({ error => "copycds needs at least one full path to ISO currently.", errorcode => [1] }); return; } my $file; foreach (@args) { $identified = 0; unless (/^\//) { #If not an absolute path, concatenate with client specified cwd s/^/$request->{cwd}->[0]\//; } # /dev/cdrom is a symlink on some systems. We need to be able to determine # if the arg points to a block device. if (-l $_) { my $link = readlink($_); # Symlinks can be relative, i.e., "../../foo" if ($link =~ m{^/}) { $file = $link; } else { $file = dirname($_) . "/" . $link; } # Unix can handle "/foo/../bar" } else { $file = $_; } # handle the copycds for tar file # if the source file is tar format, call the 'copytar' command to handle it. # currently it's used for Xeon Phi (mic) support if (-r $file) { my @filestat = `file $file`; if (grep /tar archive/, @filestat) { # this is a tar file, call the 'copytar' to generate the image my $newreq = dclone($request); $newreq->{command} = ['copytar']; #Note the singular, it's different $newreq->{arg} = [ "-f", $file, "-n", $distname ]; $doreq->($newreq, $callback); return; } } my $mntopts = "-t udf,iso9660"; #Prefer udf formate to iso when media supports both, like MS media if (-r $file and -b $file) # Block device? { $mntopts .= " -o ro"; } elsif (-r $file and -f $file) # Assume ISO file { $mntopts .= " -o ro,loop"; } else { $callback->({ error => "The management server was unable to find/read $file. Ensure that file exists on the server at the specified location.", errorcode => [1] }); return; } #let the MD5 Digest of isofullpath as the default mount point of the iso my $isofullpath = File::Spec->rel2abs($file); my $mntpath = File::Spec->catpath("", $::CDMOUNTPATH, md5_hex($isofullpath)); system("mkdir -p $mntpath"); system("umount $mntpath >/dev/null 2>&1"); if (system("mount $mntopts '$file' $mntpath")) { eval { $callback->({ error => "copycds was unable to mount $file to $mntpath.", errorcode => [1] }) }; chdir("/"); system("umount $mntpath"); return; } eval { my $newreq = dclone($request); $newreq->{command} = ['copycd']; #Note the singular, it's different $newreq->{arg} = [ "-m", $mntpath ]; if ($path) { if(-e $path) { $path=Cwd::realpath($path); } unless((substr($path,0,length("/install/")) eq "/install/") or ($path eq "/install")){ $callback->({ warning => "copycds: the specified path \"$path\" is not a subdirectory under /install. Make sure this path is configured for httpd/apache, otherwise, the provisioning with this iso will fail!" }); } push @{ $newreq->{arg} }, ("-p", $path); } if ($specific) { push @{ $newreq->{arg} }, ("-s"); } if ($inspection) { push @{ $newreq->{arg} }, ("-i"); $callback->({ info => "OS Image:" . $_ }); } if ($distname) { if ($inspection) { $callback->({ warning => "copycds: option --inspection specified, argument specified with option --name is ignored" }); } else { push @{ $newreq->{arg} }, ("-n", $distname); } } if ($arch) { if ($inspection) { $callback->({ warning => "copycds: option --inspection specified, argument specified with option --arch is ignored" }); } else { push @{ $newreq->{arg} }, ("-a", $arch); } } if (!-l $file) { push @{ $newreq->{arg} }, ("-f", $file); } if ($noosimage) { push @{ $newreq->{arg} }, ("-o"); } if ($nonoverwrite) { push @{ $newreq->{arg} }, ("-w"); } $doreq->($newreq, \&take_answer); #$::CDMOUNTPATH=""; chdir($existdir); while (wait() > 0) { yield(); } #Make sure all children exit before trying umount }; chdir("/"); system("umount $mntpath"); system("rm -rf $mntpath"); unless ($identified) { $callback->({ error => ["copycds could not identify the ISO supplied, you may wish to try -n "], errorcode => [1] }); } } } 1; # vim: set ts=2 sts=2 sw=2 et ai: