#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/bin/cdat/cdat-archive.pl 1.6 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2010,2011 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)20 1.6 src/bos/usr/bin/cdat/cdat-archive.pl, cdat, bos720 7/14/11 17:05:07 use strict; use warnings; use File::Temp; use Getopt::Long; use Fcntl ':flock'; # LOCK_* constants use XML::LibXML; use cdat; use messages; # # Constants. # my $XMLFILE = 'cdat.xml'; my $CDAT = '/usr/bin/cdat'; my $TAR = '/usr/bin/tar'; my $COMPRESS = '/usr/bin/compress'; # # Globals. # my ($path, $filename); my @collects; ###################################################################### # Function: usage # Purpose: Display usage. # Tasks: Print usage and exit. # Input: None # Output: None ###################################################################### sub usage { printf(STDERR catgets(MSG_CDAT_ARCHIVE_USAGE, "Usage: cdat archive -h\n". " cdat archive [-f File] -p PMR\n". " cdat archive -f File Id\n")); exit(1); } ###################################################################### # Function: archive_id # Purpose: Archive collect for the specified collect id. # Tasks: Archive collect. # Input: collect id # Output: None ###################################################################### sub archive_id { my ($id) = @_; my $found = 0; foreach my $collect (@collects) { my $attr = $collect->getAttribute('id'); if (defined($attr) && $id eq $attr) { return 1 if (archive_collect($collect) != 0); $found = 1; last; # there can be only 1 collect with that id } } if (!$found) { printf(catgets(MSG_NO_COLLECT_FOUND_FOR_ID, "No collect found for id %s.\n"), $id); return 1; } } ###################################################################### # Function: archive_pmr # Purpose: Archive collect for the specified PMR. # Tasks: Archive collect. # Input: PMR number # Output: None ###################################################################### sub archive_pmr { my ($pmr) = @_; my $found = 0; foreach my $collect (@collects) { my @pmrs = $collect->getElementsByTagName('pmr'); next if (@pmrs == 0); # no pmr tag for this collect, skip # retrieve value of first pmr tag my $val = $pmrs[0]->textContent; # skip if it does not match specified PMR number next if ($pmr ne $val); return 1 if (archive_collect($collect) != 0); $found = 1; # NB: there can be several collects for a given PMR } if (!$found) { printf(catgets(MSG_NO_COLLECT_FOUND_FOR_PMR, "No collect found for PMR %s.\n"), $pmr); return 1; } } ###################################################################### # Function: archive_collect # Purpose: Archive a collect. # Tasks: Create a compressed archive of a collect. # Input: collect XML element # Output: None ###################################################################### sub archive_collect { my ($collect) = @_; my @locations = $collect->getElementsByTagName('location'); if (@locations) { my $location = $locations[0]->textContent; # add the collect directory to the archive DEBUG(1, "$TAR -rf $filename -C $path '$location'\n"); system("$TAR -rf $filename -C $path '$location'"); if ($? != 0) { printf(STDERR catgets(MSG_CANNOT_ARCHIVE, "Cannot archive %s.\n"), "$path/$location"); return 1; } } } ###################################################################### # Function: main # Purpose: Entry point of the archive subcommand. # Tasks: Parse command line and archive collects matching the # query. # Input: None # Output: None ###################################################################### sub main { my ($rc, $pmr, $node, $id); # Parse command line options Getopt::Long::Configure('bundling', 'no_ignore_case'); $rc = GetOptions( 'h' => \&usage, 'f=s' => \$filename, 'p=s' => \$pmr, ); if (!$rc) { usage(); } if (!defined($pmr)) { # -p not specified # check that a collectid is specified usage if (@ARGV == 0); $id = shift @ARGV; # check that a filename is specified too usage if (!defined($filename)); } # make sure there are no extra arguments usage if (@ARGV != 0); # validate PMR number if (defined($pmr) && !($pmr =~ m/\d{5,}(,[0-9A-Za-z]{3,}){2}/)) { printf(STDERR catgets(MSG_INVALID_PMR, "Invalid PMR '%s', format should be 'PMR#,BRANCH#,COUNTRY#'.\n"), $pmr); exit(1); } $path = cdat::odm_get_path(); if (!defined($path)) { printf(STDERR catgets(MSG_DIR_NOT_DEFINED, "The cdat directory path is not defined.\n". "Please, run 'cdat init' first.\n")); exit(2); } my $fh; if (!open($fh, "<", "$path/$XMLFILE")) { printf(STDERR catgets(MSG_CANNOT_OPEN, "Cannot open %s.\n"), "$path/$XMLFILE"); exit(2); } # Try to acquire read-only access to the XML file (but do not block) if (!flock($fh, LOCK_SH | LOCK_NB)) { printf(STDERR catgets(MSG_BUSY, "Another instance of the cdat command is running.\n". "Please wait until this instance terminates.\n")); exit(2); } my $parser = XML::LibXML->new(); if (!defined($parser)) { printf(STDERR catgets(MSG_CANNOT_CREATE_XML_PARSER, "Cannot create XML parser.\n")); exit(2); } if (!defined($filename)) { # implies -p # generate a filename based on the PMR number $filename = "$path/$pmr.tar"; } else { # append ".tar" suffix $filename .= '.tar'; } my $tempdir = File::Temp::tempdir(CLEANUP => 1); # generate the README file which is the output of "show -v" if (defined($pmr)) { system("$CDAT show -v -p $pmr > $tempdir/README"); } else { system("$CDAT show -v $id > $tempdir/README"); } if ($? != 0) { printf(STDERR catgets(MSG_CANNOT_CREATE_README, "Cannot create README file.\n")); exit(2); } # add the README file to the archive DEBUG(1, "$TAR -cf $filename -C $tempdir README\n"); system("$TAR -cf $filename -C $tempdir README"); if ($? != 0) { printf(STDERR catgets(MSG_CANNOT_ARCHIVE, "Cannot archive %s.\n"), "$tempdir/README"); exit(2); } unlink("$tempdir/README"); my $tree = $parser->parse_fh($fh); if (!defined($tree)) { printf(STDERR catgets(MSG_CANNOT_PARSE, "Cannot parse %s.\n"), "$path/$XMLFILE"); exit(2); } my $root = $tree->getDocumentElement; @collects = $root->getElementsByTagName('collect'); my $status; if (defined($pmr)) { # -p is specified, archive all collects for specified PMR number $status = archive_pmr($pmr); } else { # archive collect by id $status = archive_id($id); } if ($status != 0) { unlink($filename); exit(2); } # we can release the cdat.xml lock at that point close($fh); # finally, compress the archive DEBUG(1, "$COMPRESS -F $filename\n"); system("$COMPRESS -F $filename"); if ($? != 0) { printf(STDERR catgets(MSG_CANNOT_COMPRESS, "Cannot compress %s.\n"), "$filename"); unlink($filename); exit(2); } printf(catgets(MSG_ARCHIVE_LOC, "Compressed archive successfully created at %s.\n"), "$filename.Z"); } main;