#!/usr/bin/perl # loncaparestoreconfigurations - restore data to new LON-CAPA conf files # # $Id: loncaparestoreconfigurations,v 1.16 2003/02/03 18:03:52 harris41 Exp $ # ### # This tool helps in updating a system. It restores information for # configuration files (.lpmlnew or other backup notations). # By default, the .lpmlsave suffix is used. # Alternatively, there can be two other invocations # Invocation #1: # ARGV[0]=suffix # ARGV[1]=.bak # Invocation #2: # ARGV[0]=lasttimestamp # The criteria for the lasttimestamp is that the # file suffix is a '.' followed by a 14-digit # time-stamp (YYYYMMDDhhmmss). # The time-stamp with the greatest value is # taken as the backup file. # --------------------------------------------- Define program version variable $VERSION = sprintf("%d.%02d", q$Revision: 1.16 $ =~ /(\d+)\.(\d+)/); # ---------------------------------------------- Process command-line arguments my $suffix='.lpmlsave'; my $suffixpragma=''; if ($ARGV[0] eq 'suffix') { $suffix=$ARGV[1] if $ARGV[1]=~/^[\.\w]+$/; } elsif ($ARGV[0] eq 'lasttimestamp') { $suffixpragma='lasttimestamp'; } use strict; # restrict unsafe and poorly coded constructs # ------------------------------------ Configuration files to be concerned with my @special_conf_files=( '/etc/httpd/conf/loncapa.conf', ); my %pvar; # store the PerlSetVar variable key/value combinations # --------------------------------------------- Process the configuration files # NOTE that I have structured this processing to make NO assumptions # about the processing of each configuration file. So, in terms # of keeping each file's processing algorithms self-contained, I am not # modularizing things (where it is obvious that they might be modularized.) CONFLOOP: foreach (@special_conf_files) { my $lpmlold; # holds information that needs to be read my $lpmlnew; # holds information that needs to be modified my $lpmlnew_file; # file location of information that needs to be modified # ---------------------------------------------------------------- loncapa.conf if (/^\/etc\/httpd\/conf\/loncapa.conf$/ and -e '/etc/httpd/conf/loncapa.conf') { if ($suffixpragma eq 'lasttimestamp' and -e '/etc/httpd/conf/loncapa.conf') { $suffix=&getsuffix('/etc/httpd/conf/loncapa.conf'); unless (-e '/etc/httpd/conf/loncapa.conf'.$suffix) { next CONFLOOP; } $lpmlold="\n".&readfile('/etc/httpd/conf/loncapa.conf'.$suffix); $lpmlnew_file='/etc/httpd/conf/loncapa.conf'; $lpmlnew=&readfile($lpmlnew_file); } else { $lpmlold="\n".&readfile('/etc/httpd/conf/loncapa.conf'); $lpmlnew_file='/etc/httpd/conf/loncapa.conf'.$suffix; unless (-e $lpmlnew_file) { next CONFLOOP; } $lpmlnew=&readfile($lpmlnew_file); } while($lpmlold=~/\n\s*PerlSetVar\s+(\S+)\s+(\S+)/mcg) { my $pkey=$1; my $pval=$2; $pvar{$pkey}=$pval; } foreach my $pkey (keys %pvar) { my $pval=$pvar{$pkey}; $lpmlnew=~s/(\n\s*PerlSetVar\s+$pkey\s+)\S+/$1$pval/; } open(OUT,'>'.$lpmlnew_file) or die('Cannot open '.$lpmlnew_file.' for output'."\n"); print(OUT $lpmlnew); close(OUT); } # ---------------------- smb.conf (probably will be deprecated in 2004 or 2005) elsif (/^\/etc\/smb.conf$/ and -e "/etc/smb.conf$suffix") { if ($suffixpragma eq 'lasttimestamp') { $suffix=&getsuffix('/etc/smb.conf'); unless (-e '/etc/httpd/conf/loncapa.conf'.$suffix) { next CONFLOOP; } $lpmlnew = &readfile('/etc/smb.conf'); $lpmlnew_file = '/etc/smb.conf'; } else { $lpmlnew = &readfile('/etc/smb.conf'.$suffix); $lpmlnew_file = '/etc/smb.conf'.$suffix; } $lpmlnew =~ s/\{\{\{\{\[(.*?)\]\}\}\}\}/$pvar{$1}/ge; open(OUT,'>'.$lpmlnew_file) or die('Cannot open '.$lpmlnew_file.' for output'."\n"); print(OUT $lpmlnew); close(OUT); } elsif (/^\/etc\/samba\/smb.conf$/ and -e "/etc/samba/smb.conf$suffix") { if ($suffixpragma eq 'lasttimestamp') { $suffix = &getsuffix('/etc/samba/smb.conf'); unless (-e '/etc/samba/smb.conf'.$suffix) { next CONFLOOP; } $lpmlnew = &readfile('/etc/samba/smb.conf'); $lpmlnew_file = '/etc/samba/smb.conf'; } else { $lpmlnew = &readfile('/etc/samba/smb.conf'.$suffix); $lpmlnew_file = '/etc/samba/smb.conf'.$suffix; } $lpmlnew =~ s/\{\{\{\{\[(.*?)\]\}\}\}\}/$pvar{$1}/ge; open(OUT,'>'.$lpmlnew_file) or die('Cannot open '.$lpmlnew_file.' for output'."\n"); print(OUT $lpmlnew); close(OUT); } } # --------------------------------- getsuffix: get the latest time stamp suffix # === INPUT: filename without suffix # === OUTPUT: the latest time stamp suffix; 14 digits YYYYMMDDhhmmss # === ERROR: cannot read the directory in which the filenames reside sub getsuffix ($) { my ($file) = @_; print("$file\n"); my $dir = $file; $dir =~ s/([^\/]+)$//; my $filename = $1; opendir(DIR,$dir) or die('Cannot open directory '.$dir.' for viewing'."\n"); my @a = grep {/$filename\.\d{14}/} readdir(DIR); closedir(DIR); map {s/$filename\.//;} @a; my @b = sort {$a<=>$b} @a; my $suffix = '.'.$b[$#b]; return($suffix); } # -------------------------- readfile: get the file contents in a scalar string # === INPUT: filename # === OUTPUT: the filename's contents # === ERROR: cannot read the file # === NOTE: big files will hog computer memory sub readfile ($) { my ($filename) = @_; my $contents = ''; open(IN,'<'.$filename) or die ('Cannot read '.$filename."\n"); while() {$contents .= $_;} close(IN); return($contents); } =pod =head1 NAME B - restore data to new LON-CAPA conf files =head1 SYNOPSIS perl loncaparestoreconfigurations suffix .lpmlnew =head1 DESCRIPTION During software upgrades, it is possible that configuration files will change. It is important to "intelligently" preserve the machine-specific configuration data. This script is meant to run B the software upgrade. For example, consider the configuration file F. During the software upgrade (not performed by by F), the following happens: loncapa.conf is NOT overwritten rather, a NEW file B is GENERATED (cp UPGRADEDIR/loncapa.conf SYSTEMDIR/loncapa.conf.lpmlnew) This script can be described as: =over 4 =item * modifying SYSTEMDIR/loncapa.conf.lpmlnew, and =item * the modification consists of reading values from the old loncapa.conf and placing them in loncapa.conf.lpmlnew. =back Regarding F, for backwards compatibility, this script tries to read values out of F. This script also currently works with F (a standard Linux configuration file associated with sharing the Linux filesystem with Windows machines). =head2 Working with the file suffix The script is designed to work according to two strategies. =over 4 =item * B In the aggressive update strategy, two things should happen: =over 4 =item * The configuration file should be replaced Therefore, the system administrator "trusts" the software update process and this script to handle everything correctly. =item * Information should never be lost Therefore, a backup copy should be made that is unique to the time the action is taken and is never overwritten or destroyed by the automated process. =back =item * B =over 4 =item * The configuration file should not be replaced The system administrator does not trust the software update process. She would rather have a new file "intelligently" generated, and, only by her direct approval, have the new file substitute the contents of the current configuration file. =item * The script should try to help the system administrator Therefore, a new copy is made with the suffix ".lpmlnew". This new copy is modified with data from the existing configuration file. The system administrator is prompted (by the rest of the software upgrade process) to resolve the new changes to the configuration file. =back =back Correspondingly, perl loncaparestoreconfigurations suffix .lpmlnew invokes this script in B mode; whereas perl loncaparestoreconfigurations lasttimestamp invokes this script in B mode. =head1 AUTHORS This script is free software; you can redistribute it and/or modify it under the same terms as LON-CAPA itself. =cut