--- loncom/build/loncaparestoreconfigurations 2002/03/03 00:21:23 1.12 +++ loncom/build/loncaparestoreconfigurations 2002/05/16 00:20:30 1.13 @@ -1,14 +1,20 @@ #!/usr/bin/perl -# loncaparestoreconfigurations +# loncaparestoreconfigurations - restore data to new LON-CAPA conf files +# +# $Id: loncaparestoreconfigurations,v 1.13 2002/05/16 00:20:30 harris41 Exp $ +# +# YEAR=2000 +# 10/25, 12/14 Scott Harrison +# YEAR=2002 +# Scott Harrison, 05/15 +# +### -# Scott Harrison, 10/25/2000 -# Scott Harrison, 12/14/2000 +# This tool helps in updating a system. It restores information for +# configuration files (.lpmlsave or other backup notations). -# This tool helps in updating a system. It restores backed-up -# configuration files (.rpmsave or other backup notations). - -# By default, the .rpmsave suffix is used. +# By default, the .lpmlsave suffix is used. # Alternatively, there can be two other invocations # Invocation #1: # ARGV[0]=suffix @@ -22,104 +28,292 @@ # The time-stamp with the greatest value is # taken as the backup file. -my $suffix=".rpmsave"; -my $suffixpragma=""; +# --------------------------------------------- Define program version variable +$VERSION = sprintf("%d.%02d", q$Revision: 1.13 $ =~ /(\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"; + $suffixpragma='lasttimestamp'; } +use strict; # restrict unsafe and poorly coded constructs -use strict; - +# ------------------------------------ Configuration files to be concerned with my @special_conf_files=( - "/etc/httpd/conf/access.conf", - "/etc/smb.conf", - "/etc/samba/smb.conf" + '/etc/httpd/conf/loncapa.conf', + '/etc/httpd/conf/access.conf', + '/etc/smb.conf', + '/etc/samba/smb.conf' ); -my @generic_conf_files=( - "/home/httpd/lonTabs/hosts.tab", - "/home/httpd/lonTabs/spare.tab", - "/etc/krb.conf", - "/etc/ntp.conf", - "/etc/httpd/conf/srm.conf", - "/etc/httpd/conf/httpd.conf", - ); +my %pvar; # store the PerlSetVar variable key/value combinations -my @perlsetvars=("lonHostID","lonRole","lonAdmEMail","lonDefDomain","lonLoadLim","lonExpire","lonReceipt","lonSqlAccess"); -my %pvar; -foreach (@special_conf_files) { - if (/^\/etc\/httpd\/conf\/access.conf$/) { - if ($suffixpragma eq 'lasttimestamp') { - $suffix=getsuffix('/etc/httpd/conf/access.conf'); +# --------------------------------------------- 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 + +# ------------------------------------------- access.conf (becoming deprecated) + if (/^\/etc\/httpd\/conf\/access.conf$/ and + -e '/etc/httpd/conf/access.conf') { + if ($suffixpragma eq 'lasttimestamp' and + -e '/etc/httpd/conf/access.conf'.$suffix) { + $suffix=&getsuffix('/etc/httpd/conf/access.conf'); + unless (-e '/etc/httpd/conf/access.conf'.$suffix) { + next CONFLOOP; + } + $lpmlold="\n".&readfile('/etc/httpd/conf/access.conf'.$suffix); + $lpmlnew_file='/etc/httpd/conf/access.conf'; + $lpmlnew=&readfile($lpmlnew_file); } - my $template=`/bin/cat /etc/httpd/conf/access.conf`; - my $lpmlnew=`/bin/cat /etc/httpd/conf/access.conf$suffix`; -# `/bin/mv /etc/httpd/conf/access.conf /etc/httpd/conf/access.conf.template`; - foreach my $psv (@perlsetvars) { - if ($template=~/\nPerlSetVar\s+$psv\s+(\S+)/) { - my $pval=$1; - $lpmlnew=~s/(\nPerlSetVar\s+$psv\s+)\S+/$1$pval/; - $pvar{$psv}=$pval; + else { + $lpmlold="\n".&readfile('/etc/httpd/conf/access.conf'); + $lpmlnew_file='/etc/httpd/conf/access.conf'.$suffix; + unless (-e $lpmlnew_file) { + next CONFLOOP; } + $lpmlnew=&readfile($lpmlnew_file); } - open OUT,">/etc/httpd/conf/access.conf$suffix"; - print OUT $lpmlnew; - close OUT; - } - if (/^\/etc\/smb.conf$/ and -e "/etc/smb.conf$suffix") { - if ($suffixpragma eq 'lasttimestamp') { - $suffix=getsuffix('/etc/smb.conf'); + while($lpmlold=~/\n\s*PerlSetVar\s+(\S+)\s+(\S+)/mcg) { + my $pkey=$1; my $pval=$2; + $lpmlnew=~s/(\n\s*PerlSetVar\s+$pkey\s+)\S+/$1$pval/; + $pvar{$pkey}=$pval; } - my $template=`/bin/cat /etc/smb.conf$suffix`; - foreach my $psv (@perlsetvars) { - $template=~s/\{\{\{\{\[(.*?)\]\}\}\}\}/$pvar{$1}/ge; - } - open OUT,">/etc/smb.conf$suffix"; - print OUT $template; - close OUT; } - if (/^\/etc\/samba\/smb.conf$/ and -e "/etc/samba/smb.conf$suffix") { - if ($suffixpragma eq 'lasttimestamp') { - $suffix=getsuffix('/etc/samba/smb.conf'); + +# ---------------------------------------------------------------- loncapa.conf + elsif (/^\/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/; } - my $template=`/bin/cat /etc/samba/smb.conf$suffix`; - foreach my $psv (@perlsetvars) { - $template=~s/\{\{\{\{\[(.*?)\]\}\}\}\}/$pvar{$1}/ge; - } - open OUT,">/etc/samba/smb.conf$suffix"; - print OUT $template; - close OUT; + open(OUT,'>'.$lpmlnew_file) or + die('Cannot open '.$lpmlnew_file.' for output'."\n"); + print(OUT $lpmlnew); + close(OUT); } -} - -exit; # Just because this is only about restoring configuration to - # new files -foreach (@generic_conf_files) { - my $file=$_; - if ($suffixpragma eq 'lasttimestamp') { - $suffix=getsuffix($file); +# -------------------------------------------------------------------- smb.conf + 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); } - if (-e "$file$suffix") { - `/bin/mv $file $_.template`; - `/bin/cp $file$suffix $file`; + 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"; + print("$file\n"); my $dir=$file; $dir=~s/([^\/]+)$//; my $filename=$1; - opendir(DIR,$dir); - my @a=grep {/$filename\.\d{14}/} readdir DIR; - closedir DIR; + 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; + 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 + +Scott Harrison + +This module is free software; you can redistribute it +and/or modify it under the same terms as LON-CAPA itself. + +=cut