--- loncom/build/loncaparestoreconfigurations 2000/10/26 00:09:58 1.1 +++ loncom/build/loncaparestoreconfigurations 2002/07/27 22:39:56 1.14 @@ -1,32 +1,317 @@ #!/usr/bin/perl -# loncaparestoreconfigurations +# loncaparestoreconfigurations - restore data to new LON-CAPA conf files +# +# $Id: loncaparestoreconfigurations,v 1.14 2002/07/27 22:39:56 harris41 Exp $ +# +# YEAR=2000 +# 10/25, 12/14 Scott Harrison +# YEAR=2002 +# Scott Harrison, 05/15 +# +### -# This tool helps in updating a system. It takes a list of -# .rpmsave files and restores them. +# This tool helps in updating a system. It restores information for +# configuration files (.lpmlsave or other backup notations). -# Scott Harrison, 10/25/2000 +# 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 -use strict; +# 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.14 $ =~ /(\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/access.conf" + '/etc/httpd/conf/loncapa.conf', + '/etc/httpd/conf/access.conf', ); -my @generic_conf_files=( - "/home/httpd/lonTabs/hosts.tab", - "/home/httpd/lonTabs/spare.tab", - "/etc/krb.conf", - "/etc/ntp.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 -foreach (@special_conf_files) { - if (/^/etc/httpd/conf/access.conf$/) { - my @perlsetvars=("lonHostID","lonRole","lonAdmEMail","lonDefDomain","lonLoadLim","lonExpire"); + 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); + } + 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); + } + 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; + } + } + +# ---------------------------------------------------------------- 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/; + } + open(OUT,'>'.$lpmlnew_file) or + die('Cannot open '.$lpmlnew_file.' for output'."\n"); + print(OUT $lpmlnew); + close(OUT); + } + +# -------------------------------------------------------------------- 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); + } + 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); } } -foreach (@generic_conf_files) { - `/bin/mv $_ $_.template`; - `/bin/mv $_.rpmsave $_`; +# --------------------------------- 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 + +Scott Harrison + +This module is free software; you can redistribute it +and/or modify it under the same terms as LON-CAPA itself. + +=cut