#!/usr/bin/perl -w # # The LearningOnline Network # # $Id: modify_config_files.pl,v 1.11 2009/07/21 20:02:47 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # ### =pod =head1 NAME B =head1 SYNOPSIS This script modifies /etc/my.cnf and one of: /etc/yum.conf (for Fedora/CentOS/Scientific Linux/RHEL5), /etc/apt/sources.list (for Debian/Ubuntu) and /etc/sysconfig/rhn/sources (for RHEL4). =head1 DESCRIPTION This script modifies /etc/my.cnf and /etc/yum.conf or /etc/apt/sources or /etc/sysconfig/rhn/sources to ensure certain parameters are set properly. The LON-CAPA yum repositories are added to /etc/yum.conf or /etc/sysconfig/rhn/sources and the LON-CAPA apt repositories are added to /etc/apt/sources.list. The /etc/my.cnf file is modified to set the wait_timeout to 1 year. Backup copies of each file are made in /etc, /etc/apt, and /etc/sysconfig/rhn, as appropriate. =cut use strict; use File::Copy; use lib '/home/httpd/lib/perl/'; use LONCAPA::Configuration; my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf'); open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |"); my $dist = ; chomp($dist); close(DSH); my $yum_status; my $loninst = 'http://install.loncapa.org'; my $loninst_re = 'http://install\.loncapa\.org'; if ($dist =~ /^fedora(\d+)$/) { my $ver = $1; my $gpgchk = '0'; my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa"; if ($ver > 6) { $gpgchk = '1'; } $yum_status = &update_file('/etc/yum.conf', [{section => 'loncapa-updates-basearch', key => 'name=', value => 'Fedora Core $releasever LON-CAPA $basearch Updates', }, {section => 'loncapa-updates-basearch', key => 'baseurl=', value => $loninst.'/fedora/linux/loncapa/$releasever/$basearch', }, {section => 'loncapa-updates-basearch', key => 'gpgcheck=', value => $gpgchk, }, {section => 'loncapa-updates-basearch', key => 'gpg=', value => $gpg, }, {section => 'loncapa-updates-noarch', key => 'name=', value => 'Fedora Core $releasever LON-CAPA noarch Updates', }, {section => 'loncapa-updates-noarch', key => 'baseurl=', value => $loninst.'/fedora/linux/loncapa/$releasever/noarch', }, {section => 'loncapa-updates-noarch', key => 'gpgcheck=', value => $gpgchk, }, {section => 'loncapa-updates-noarch', key => 'gpg=', value => $gpg, }]); } elsif ($dist =~ /^(rhes|centos|scientific)(\d+)$/) { my $type = $1; my $ver = $2; my $longver = $ver; if ($type eq 'rhes') { if ($ver == 4) { $longver = '4ES'; } elsif ($ver == 5) { $longver = '5Server'; } } my %info = ( rhes => { title => 'RHEL', path => 'redhat/linux/enterprise/loncapa', gpg => 'versions/redhat/RPM-GPG-KEY-loncapa', gpgchk => 1, }, centos => { title => 'CentOS', path => 'centos/loncapa', gpg => 'versions/centos/RPM-GPG-KEY-loncapa', gpgchk => 1, }, scientific => { title => 'Scientific Linux', path => 'scientific/loncapa', gpg => 'versions/scientific/RPM-GPG-KEY-loncapa', gpgchk => 1, }, ); if (ref($info{$type}) eq 'HASH') { if ($ver > 4) { $yum_status = &update_file('/etc/yum.conf', [{section => 'loncapa-updates-basearch', key => 'name=', value => $info{$type}{title}.' $releasever LON-CAPA $basearch Updates', }, {section => "loncapa-updates-basearch", key => 'baseurl=', value => "$loninst/$info{$type}{path}/".'$releasever/$basearch', }, {section => 'loncapa-updates-basearch', key => 'gpgcheck=', value => $info{$type}{gpgchk}, }, {section => 'loncapa-updates-basearch', key => 'gpgkey=', value => "$loninst/$info{$type}{gpg}", }, {section => 'loncapa-updates-noarch', key => 'name=', value => $info{$type}{title}.' $releasever LON-CAPA noarch Updates', }, {section => 'loncapa-updates-noarch', key => 'baseurl=', value => "$loninst/$info{$type}{path}/".'$releasever/noarch', }, {section => 'loncapa-updates-noarch', key => 'gpgcheck=', value => $info{$type}{gpgchk}, }, {section => 'loncapa-updates-noarch', key => 'gpgkey=', value => "$loninst/$info{$type}{gpg}", }]); } elsif (($type eq 'rhes') && ($ver == 4)) { my %rhn = ( basearch => { regexp => '\s*yum\s+loncapa\-updates\-basearch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/\$ARCH', text => "yum loncapa-updates-basearch $loninst/$info{$type}{path}/$longver/".'$ARCH', }, noarch => { regexp => '\s*yum\s+loncapa\-updates\-noarch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/noarch', text => "yum loncapa-updates-noarch $loninst/$info{$type}{path}/$longver/noarch", }, ); $yum_status = &update_rhn_source(\%rhn); } } } elsif ($dist =~ /^(debian|ubuntu)\d+$/) { my %apt_get_source = ( debian5 => { regexp => '\s*deb\s+'.$loninst_re.'/debian/\s+lenny\s+main', text => "deb $loninst/debian/ lenny main", }, ubuntu6 => { regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+dapper\s+main', text => "deb $loninst/ubuntu/ dapper main", }, ubuntu8 => { regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/\s+hardy\s+main', text => "deb $loninst/ubuntu/ hardy main", }, ); my $apt_status; if (defined($apt_get_source{$dist})) { $apt_status = &update_apt_source($apt_get_source{$dist},); } } my $mysql_global_status = &update_file('/etc/my.cnf', [{section =>'mysqld', key =>'set-variable=wait_timeout=', value =>'31536000', }]); my $local_my_cnf = '/home/www/.my.cnf'; if (! -e $local_my_cnf) { # Create a file so we can do something with it... system("touch $local_my_cnf"); } my $mysql_www_status = &update_file($local_my_cnf, [{section =>'client', key =>'user=', value =>'www',}, {section =>'client', key =>'password=', value =>$loncapa_config->{'lonSqlAccess'}},]); my $exitvalue = 0; if ($mysql_global_status) { $exitvalue = 1; } exit $exitvalue; sub update_file { my ($file,$newdata) = @_; return 1 if (! -e $file); my $backup = $file.'.backup'; if (! copy($file,$backup)) { warn "**** Error: Unable to make backup of $file"; return 0; } my ($filedata) = &parse_config_file($file); if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;} my $modified = 0; foreach my $data (@$newdata) { my $section = $data->{'section'}; my $key = $data->{'key'}; my $value = $data->{'value'}; my $result = &modify_config_file($filedata,$section,$key,$value); if ($result) { $modified = 1; } } if ($modified) { my $result = &write_config_file($file,$filedata); if (defined($result)) { warn 'Error:'.$result; return 0; } } return $modified; } ################################################################# ################################################################# =pod =over 4 =item &parse_config_file() Read a configuration file in and parse it into an internal data structure. Input: filename Output: array ref $filedata OR scalar error message =back =cut ################################################################# ################################################################# sub parse_config_file { my ($file) = @_; open(INFILE,$file) || return ('Unable to open '.$file.' for reading'); my @Input = ; close(INFILE); my @Structure; my %Sections; while (my $line = shift(@Input)) { chomp($line); if ($line =~ /^\[([^\]]*)\]/) { my $section_id = $1; push(@Structure,'__section__'.$section_id); while ($line = shift(@Input)) { chomp($line); if ($line =~ /^\[([^\]]*)\]/) { unshift(@Input,$line); last; } else { push(@{$Sections{$section_id}},$line); } } } else { push(@Structure,$line); } } my $filedata = [\@Structure,\%Sections]; return $filedata; } ################################################################# ################################################################# =pod =over 4 =item Write a configuration file out based on the internal data structure returned by &parse_config_file Inputs: filename, $filedata (the return value of &parse_config_file Returns: undef on success, scalar error message on failure. =back =cut ################################################################# ################################################################# sub write_config_file { my ($file,$filedata) = @_; my ($structure,$sections) = @$filedata; if (! defined($structure) || ! ref($structure)) { return 'Bad subroutine inputs'; } open(OUTPUT,'>'.$file) || return('Unable to open '.$file.' for writing'); for (my $i=0;$i[$i]; chomp($line); if ($line =~ /^__section__(.*)$/) { my $section_id = $1; print OUTPUT ('['.$section_id.']'.$/); foreach my $section_line (@{$sections->{$section_id}}) { chomp($section_line); print OUTPUT $section_line.$/; } # Deal with blank lines if ($sections->{$section_id}->[-1] =~ /^\s*$/) { # No need to output a blank line at the end if there is one # already } else { print OUTPUT $/; } } else { print OUTPUT $line.$/; } } close OUTPUT; return undef; } ################################################################# ################################################################# =pod =over 4 =item &modify_config_file() Modifies the internal data structure of a configuration file to include new sections and/or new configuration directives. Inputs: $filedata (see &parse_config_file $section, the [section] the new entry is to reside in. A value of undef will cause the "outer" section (as in yum.conf) to be updated (or have the new value prepended). $newkey: A line which matches this will be replaced with $newkey.$newvalue $newvalue: The new value to be placed with the new key. Returns: 0 or 1, indicating if the file was modified(1) or not(0). =back =cut ################################################################# ################################################################# sub modify_config_file { my ($filedata,$section,$newkey,$newvalue)=@_; my $modified = 0; # returned value - set to true if the file is modified my ($structure,$sections) = @$filedata; if (! defined($newvalue)) { $newvalue = ''; } my $newline = $newkey.$newvalue; # # Determine which array ref gets the item my $target; if (defined($section)) { if (! exists($sections->{$section})) { push(@$structure,'__section__'.$section); $sections->{$section}=[]; } $target = $sections->{$section}; } else { $target = $structure; } # # Put the item in or update it. my $key_is_new = 1; for (my $i=0;$i[$i] =~/^$newkey/) { if ($target->[$i] ne $newline) { $target->[$i]=$newline; $modified = 1; } $key_is_new = 0; last; } } if ($key_is_new) { if (! defined($section)) { unshift(@$target,$newline); } else { # No need to put things after a blank line. if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) { $target->[-1] = $newline; $modified = 1; } else { push(@$target,$newline); $modified = 1; } } } return $modified; } ################################################################# ################################################################# =pod =over 4 =item &update_rhn_source() Modifies the Red Hat 4 sources file which includes repositories used by up2date Inputs: $rhn_items - a reference to hash of a hash containing the regular expression to test for, and the text string to append to the file, if an entry for the LON-CAPA RHEL repository is missing for two cases: (a) basearch (b) noarch Returns: 0 or 1, indicating if the file was modified(1) or not(0). =back =cut ################################################################# ################################################################# sub update_rhn_source { my ($rhn_items) = @_; return 0 if (ref($rhn_items) ne 'HASH'); return 0 if ((ref($rhn_items->{basearch}) ne 'HASH') || (ref($rhn_items->{noarch}) ne 'HASH')); my $file = '/etc/sysconfig/rhn/sources'; return 0 if (! -e $file); my $backup = $file.'.backup'; if (! copy($file,$backup)) { warn "**** Error: Unable to make backup of $file"; return 0; } my $result = 0; my $fh; if (open($fh,"<$file")) { my $total = 0; my %found; foreach my $item (keys(%{$rhn_items})) { $found{$item} = 0; } while(<$fh>) { foreach my $item (keys(%{$rhn_items})) { if (ref($rhn_items->{$item}) eq 'HASH') { my $pattern = $rhn_items->{$item}->{regexp}; if ($pattern ne '') { if (m{^$pattern}) { $found{$item} = 1; $total ++; } } } } last if $total == 2; } close($fh); if ($total < 2) { if (open($fh,">>$file")) { foreach my $item (keys(%{$rhn_items})) { unless ($found{$item}) { if (ref($rhn_items->{$item}) eq 'HASH') { if ($rhn_items->{$item}->{text} ne '') { print $fh "\n".$rhn_items->{$item}->{text}."\n"; $result = 1; } } } } close($fh); } } } return $result; } ################################################################# ################################################################# =pod =over 4 =item &update_apt_source() Modifies the source.list file which includes repositories used by apt-get Inputs: $deb_row - a reference to containing the regular expression to test for, and the text string to append to the file, if an entry for the LON-CAPA Debian/ or Ubuntu repository is missing. Returns: 0 or 1, indicating if the file was modified(1) or not(0). =back =cut ################################################################# ################################################################# sub update_apt_source { my ($deb_row) = @_; return 0 if (ref($deb_row) ne 'HASH'); return 0 if (($deb_row->{regexp} eq '') || ($deb_row->{text} eq '')); my $file = '/etc/apt/sources.list'; return 0 if (! -e $file); my $backup = $file.'.backup'; if (! copy($file,$backup)) { warn "**** Error: Unable to make backup of $file"; return 0; } my $result = 0; my $fh; if (open($fh,"<$file")) { my $found = 0; my $pattern = $deb_row->{regexp}; while(<$fh>) { if (m{^$pattern}) { $found = 1; last; } } close($fh); if (!$found) { if (open($fh,">>$file")) { print $fh "\n".$deb_row->{text}."\n"; close($fh); $result = 1; } } } return $result; }