Annotation of foxridge-archiver/archiver.pl, revision 1.1
1.1 ! casties 1: #!/usr/local/bin/perl -w
! 2:
! 3: use strict;
! 4:
! 5: use XML::LibXML;
! 6:
! 7: # MPIWG libraries
! 8: use lib '/usr/local/mpiwg/archive';
! 9: use MPIWGStor;
! 10:
! 11: # make output unbuffered
! 12: $|=1;
! 13:
! 14: #######################################################
! 15: # internal parameters
! 16: #
! 17:
! 18: # program version
! 19: my $version = "0.5 (15.1.2004)";
! 20:
! 21: # rewrite XML file (necessary for archive date!)
! 22: my $fix_xml = 1;
! 23: my $xml_changed = 0;
! 24: # XML namespace (not really implemented!)
! 25: my $namespace = "";
! 26:
! 27: # archive name (archive-path element, usually == $docdir)
! 28: my $archname;
! 29: # archive storage date (now)
! 30: my $archdate = stime(time);
! 31:
! 32: # delete "junk" files before archiving
! 33: my $delete_junk_files = 1;
! 34:
! 35: # delete data files after archiving
! 36: my $delete_data_files = 1;
! 37:
! 38:
! 39: #######################################################
! 40: # external programs
! 41: #
! 42: my $archprog = "/opt/tivoli/tsm/client/ba/bin/dsmc";
! 43: if (! -x $archprog) {
! 44: print "ABORT: TSM client program '$archprog' missing!!\n";
! 45: exit 1;
! 46: }
! 47: my $checkprog = "/usr/local/mpiwg/archive/metacheck";
! 48: if (! -x $checkprog) {
! 49: print "ABORT: meta data checking program '$checkprog' missing!!\n";
! 50: exit 1;
! 51: }
! 52: # log file for archiver
! 53: my $log_file = "/var/log/mpiwg-archiver.log";
! 54: if (! open LOG, ">>$log_file") {
! 55: print "ABORT: unable to write log file '$log_file'!!\n";
! 56: exit 1;
! 57: }
! 58:
! 59: #######################################################
! 60: # check parameters that were passed to the program
! 61: #
! 62: if ($#ARGV < 0) {
! 63: print "ABORT: no document directory given!\n";
! 64: exit 1;
! 65: }
! 66: my $docdir = $ARGV[0];
! 67: # strip trailing slashes
! 68: $docdir =~ s/\/$//;
! 69: if (! -d $docdir) {
! 70: print "ABORT: document directory \'$docdir\' doesn't exist!\n";
! 71: exit 1;
! 72: }
! 73: if (($#ARGV > 0)&&($ARGV[1] eq "-premigrate")) {
! 74: $delete_data_files = 0;
! 75: }
! 76:
! 77: my $metafile = "$docdir/index.meta";
! 78: if (! -f $metafile) {
! 79: print "ABORT: metadata index file \'$metafile\' doesn't exist!\n";
! 80: exit 1;
! 81: }
! 82:
! 83: #######################################################
! 84: # internal variables
! 85: #
! 86:
! 87: # number of errors
! 88: my $errcnt = 0;
! 89: # number of warnings
! 90: my $warncnt = 0;
! 91:
! 92: #######################################################
! 93: # subroutines
! 94: #
! 95:
! 96: #
! 97: # $files = read_resource_meta($rootnode)
! 98: #
! 99: # checks general resource meta information and reads the list of files
! 100: #
! 101: sub read_resource_meta {
! 102: my ($rootnode) = @_;
! 103: my %files;
! 104: #
! 105: # archive path
! 106: #
! 107: # get archive-path
! 108: $archname = MPIWGStor::sstrip($rootnode->findvalue('child::archive-path'));
! 109: if (! $archname) {
! 110: print "ABORT: archive-name element missing!!\n";
! 111: exit 1;
! 112: }
! 113:
! 114: #
! 115: # files
! 116: #
! 117: my @filenodes = $rootnode->findnodes('child::file');
! 118: foreach my $fn (@filenodes) {
! 119: my $name = MPIWGStor::sstrip($fn->findvalue('child::name'));
! 120: my $path = MPIWGStor::sstrip($fn->findvalue('child::path'));
! 121: print "FILE: ($path)$name\n";
! 122: my $f = ($path) ? "$path/$name" : "$name";
! 123: $files{$f} = $name;
! 124: }
! 125:
! 126: #
! 127: # archive-storage-date
! 128: #
! 129: my $stordatenode = ($rootnode->find('child::archive-storage-date'))->get_node(1);
! 130: if ($stordatenode) {
! 131: print "WARNING: archive storage date exists! Resource already archived?\n";
! 132: $warncnt++;
! 133: # delete old date
! 134: $stordatenode->removeChildNodes;
! 135: } else {
! 136: # create new storage date node
! 137: $stordatenode = $rootnode->addNewChild($namespace, "archive-storage-date");
! 138: # move after archive-path
! 139: $rootnode->insertAfter($stordatenode, ($rootnode->find('child::archive-path'))->get_node(1));
! 140: }
! 141: $stordatenode->appendTextNode($archdate);
! 142: $xml_changed++;
! 143: return \%files;
! 144: }
! 145:
! 146:
! 147: #
! 148: # $%files = run_archive
! 149: #
! 150: # runs the archiver program on $docdir and returns a list of archived files
! 151: #
! 152: sub run_archive {
! 153: my %files;
! 154: print LOG "START archiver $version $archdate\n";
! 155: my $archcmd = $archprog;
! 156: $archcmd .= " archive -archsymlinkasfile=no -subdir=yes";
! 157: $archcmd .= " -description='$archname'";
! 158: $archcmd .= " '$docdir/'";
! 159:
! 160: print LOG "CMD: $archcmd\n";
! 161: if (open ARCH, "$archcmd 2>&1 |") {
! 162: while (<ARCH>) {
! 163: chomp;
! 164: print LOG "ARCH: $_\n";
! 165: if (/Normal File-->\s+[\d,]+\s+(.*)\s+\[Sent\]/) {
! 166: print " ARCH: file '$1'\n";
! 167: $files{$1} = "ok";
! 168: }
! 169: if (/^Archive processing of .* finished without failure./) {
! 170: print " ARCH: OK\n";
! 171: }
! 172: }
! 173: } else {
! 174: print "ABORT: unable to start archive command '$archcmd'!!\n";
! 175: exit 1;
! 176: }
! 177:
! 178: return \%files;
! 179: }
! 180:
! 181:
! 182: #
! 183: # check_files(\%files_to_archive, \%archived_files)
! 184: #
! 185: # compares the list of archived and to be archived files
! 186: #
! 187: sub check_files {
! 188: my ($to_archive, $archived) = @_;
! 189:
! 190: my $nt = scalar keys %$to_archive;
! 191: my $na = scalar keys %$archived;
! 192:
! 193: foreach my $ft (sort keys %$to_archive) {
! 194: my $fp = "$docdir/$ft";
! 195: #print " fp: $fp\n";
! 196: if ($$archived{$fp}) {
! 197: print "DEBUG: $ft archived OK\n";
! 198: $$archived{$fp} = "OK";
! 199: } else {
! 200: print "ERROR: file '$ft' missing from archive!\n";
! 201: $errcnt++;
! 202: }
! 203: }
! 204:
! 205: foreach my $fa (sort keys %$archived) {
! 206: if ($$archived{$fa} ne "OK") {
! 207: my ($fn, $fp) = MPIWGStor::split_file_path($fa);
! 208: if ($MPIWGStor::index_files{$fn}) {
! 209: print "DEBUG: $fa ignored\n";
! 210: $na--;
! 211: } else {
! 212: print "WARNING: $fa archived but not in list!\n";
! 213: $warncnt++;
! 214: }
! 215: }
! 216: }
! 217:
! 218: if ($nt > $na) {
! 219: print "WARNING: less files were archived ($na vs. $nt)!\n";
! 220: } elsif ($na > $nt) {
! 221: print "WARNING: more files were archived ($na vs. $nt)!\n";
! 222: }
! 223:
! 224: }
! 225:
! 226:
! 227: #
! 228: # delete_files(\%files)
! 229: #
! 230: # deletes the files from the list (of absolute files) and their directories
! 231: # if they are empty
! 232: #
! 233: sub delete_files {
! 234: my ($files) = @_;
! 235: my %dirs;
! 236:
! 237: foreach my $f (sort keys %$files) {
! 238: my ($fn, $fp) = MPIWGStor::split_file_path($f);
! 239: # collect all unique directories
! 240: if ($fp && (! $dirs{$fp})) {
! 241: $dirs{$fp} = $fp;
! 242: }
! 243: # don't delete index files
! 244: next if ($MPIWGStor::index_files{$fn});
! 245: # no file no delete
! 246: next unless (-f $f);
! 247: # delete files
! 248: if (unlink $f) {
! 249: print "INFO: remove $f ($fn)\n";
! 250: } else {
! 251: print "ERROR: unable to delete $f!\n";
! 252: $errcnt++;
! 253: }
! 254: }
! 255: # try to delete all empty directories
! 256: my @dirkeys = sort keys %dirs;
! 257: # starting at the end to get to the subdirectories first
! 258: for (my $i = $#dirkeys; $i >= 0; $i--) {
! 259: my $d = $dirkeys[$i];
! 260: # dont't remove document dir (shouldn't be empty anyway)
! 261: next if ($d eq $docdir);
! 262: if (-d $d) {
! 263: print "INFO: remove dir $d\n";
! 264: rmdir $d;
! 265: }
! 266: }
! 267: }
! 268:
! 269:
! 270: #
! 271: # delete_all_files(\%files, $dir)
! 272: #
! 273: # deletes all files with names from the list %files
! 274: # in the directory $dir and its subdirectories
! 275: #
! 276: sub delete_all_files {
! 277: my ($files, $dir) = @_;
! 278:
! 279: if (! opendir DIR, $dir) {
! 280: print "ERROR: unable to read directory $dir!\n";
! 281: $errcnt++;
! 282: return;
! 283: }
! 284: my @fl = readdir DIR;
! 285: closedir DIR;
! 286:
! 287: foreach my $f (@fl) {
! 288: next if ($f =~ /^\.{1,2}$/);
! 289: if ($$files{$f}) {
! 290: # $f is in the file list
! 291: if (-f "$dir/$f") {
! 292: # $f is a file
! 293: if (unlink "$dir/$f") {
! 294: print "INFO: removed $f\n";
! 295: } else {
! 296: print "ERROR: unable to delete $f!\n";
! 297: $errcnt++;
! 298: }
! 299: } elsif (-d _) {
! 300: # $f is a directory (unlink won't work)
! 301: if ((system 'rm', '-r', "$dir/$f") == 0) {
! 302: print "INFO: removed directory $f\n";
! 303: } else {
! 304: print "ERROR: unable to delete directory $f!\n";
! 305: $errcnt++;
! 306: }
! 307: } else {
! 308: print "ERROR: funny object $dir/$f!\n";
! 309: $errcnt++;
! 310: }
! 311: } else {
! 312: # $f is not in the list
! 313: if (-d "$dir/$f") {
! 314: # recurse into directories
! 315: print "DEBUG: enter $dir/$f\n";
! 316: delete_all_files($files, "$dir/$f");
! 317: }
! 318: }
! 319: }
! 320: }
! 321:
! 322:
! 323: #######################################################
! 324: # main
! 325: #
! 326:
! 327: print "START: archiver $version at $archdate\n";
! 328:
! 329: # make shure the right user is running this program
! 330: my $user = getlogin;
! 331: #if (($user ne "archive")||($user ne "root")) {
! 332: # logger("ABORT", "you ($user) must be archive or root user to run this program!");
! 333: # exit 1;
! 334: #}
! 335:
! 336: # use metacheck first
! 337: if (system("$checkprog $docdir >/dev/null") == 0) {
! 338: print "INFO: resource '$docdir' check OK\n";
! 339: } else {
! 340: print "ABORT: resource '$docdir' check failed!!\n";
! 341: exit 1;
! 342: }
! 343:
! 344: # read index.meta file
! 345: my ($document, $rootnode) = MPIWGStor::read_xml($metafile);
! 346:
! 347: # check file and add archive date
! 348: my $files_to_archive = read_resource_meta($rootnode);
! 349:
! 350: print "INFO: ", scalar keys %$files_to_archive, " files to archive\n";
! 351:
! 352: # check for .archived file
! 353: if (-f "$docdir/.archived") {
! 354: if (unlink "$docdir/.archived") {
! 355: print "WARNING: existing .archived file has been removed! Resource already archived?\n";
! 356: $warncnt++;
! 357: } else {
! 358: print "ERROR: unable to remove existing .archived file!\n";
! 359: $errcnt++;
! 360: }
! 361: }
! 362:
! 363: # remove junk files
! 364: if ($delete_junk_files) {
! 365: delete_all_files(\%MPIWGStor::junk_files, $docdir);
! 366: }
! 367:
! 368: # write new index.meta
! 369: if ($errcnt > 0) {
! 370: print "ABORT: there were errors!\n";
! 371: exit 1;
! 372: } else {
! 373: if ($fix_xml) {
! 374: MPIWGStor::write_xml($document, $metafile);
! 375: }
! 376: }
! 377:
! 378: # start archiving
! 379: my $archived_files = run_archive;
! 380:
! 381: print "INFO: ", scalar keys %$archived_files, " files archived\n";
! 382:
! 383: # check list of archived files
! 384: check_files($files_to_archive, $archived_files);
! 385:
! 386: # delete files if all went OK
! 387: if ($errcnt == 0) {
! 388: system("touch", "$docdir/.archived");
! 389: # remove junk files (again)
! 390: if ($delete_junk_files) {
! 391: delete_all_files(\%MPIWGStor::junk_files, $docdir);
! 392: }
! 393: # remove archived files
! 394: if ($delete_data_files) {
! 395: delete_files($archived_files);
! 396: }
! 397: }
! 398:
! 399: print "INFO: $warncnt warnings\n";
! 400: print "INFO: $errcnt errors\n";
! 401: my $num_archfiles = %$archived_files + 1;
! 402: if ($errcnt > 0) {
! 403: print "ABORT: there were errors! ($num_archfiles files archived) at ", stime(time), "\n";
! 404: exit 1;
! 405: } else {
! 406: print "DONE: $num_archfiles files archived at ", stime(time), "\n";
! 407: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>