#!/usr/bin/perl -w
#
# The LearningOnline Network
#
# $Id: modify_config_files.pl,v 1.29 2024/07/31 03:39:20 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<modify_config_files.pl>
=head1 SYNOPSIS
This script modifies local MySQL configuration file(s), which will be:
/home/www/.my.cnf and, depending on distro/version also one of:
/etc/my.cnf, /etc/mysql/my.cnf, /etc/mysql/mysql.conf.d/mysqld.cnf,
or /etc/mysql/mariadb.conf.d/50-server.cnf, and also the file used to
store information about the LON-CAPA package repositories located at
install.loncapa.org. which provide rpm or deb packages created for the
Linux distro/version being used. The file to modify will be one of:
/etc/yum.conf (for CentOS/Scientific Linux/RHEL >=5 and <8),
/etc/apt/sources.list (for Debian < 10 and Ubuntu < 22), or
/etc/apt/sources.list.d/loncapa.list (for Debian >= 10 and Ubuntu > 20),
/etc/sysconfig/rhn/sources (for RHEL4), or /etc/yum.repos.d/loncapa.repo
(for Fedora >= 21; Oracle Linux; AlmaLinux; RockyLinux; CentOS/RHEL >= 8).
The script also modifies /home/www/.inputrc on Linux distros which have
readline 8.1 or newer, i.e., CentOS/Scientific Linux/RHEL >= 9,
Ubuntu >= 22, Debian >= 12, and Fedora >= 34.
=head1 DESCRIPTION
This script will modify /etc/my.cnf, /etc/mysql/my.cnf,
/etc/mysql/mysql.conf.d/mysqld.cnf, or
/etc/mysql/mariadb.conf.d/50-server.cnf,
and /etc/yum.conf, /etc/yum.repos.d/loncapa.repo,
/etc/apt/sources.list, /etc/apt/sources.list.d/loncapa.list or
/etc/sysconfig/rhn/sources and /home/www/.inputrc to ensure
certain parameters are set properly.
The LON-CAPA yum repositories are added to /etc/yum.conf,
/etc/yum.repos.d/loncapa.repo, or /etc/sysconfig/rhn/sources
and the LON-CAPA apt repositories are added to
/etc/apt/sources.list or /etc/apt/sources.list.d/loncapa.list.
The /etc/my.cnf, /etc/mysql/my.cnf /etc/mysql/mysql.conf.d/mysqld.cnf
or /etc/mysql/mariadb.conf.d/50-server.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 = <DSH>;
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 $file = '/etc/yum.conf';
my $ver = $1;
my $gpgchk = '0';
my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa";
my $nobackup;
if ($ver > 6) {
$gpgchk = '1';
}
if ($ver >= 21) {
$file = '/etc/yum.repos.d/loncapa.repo';
$nobackup = 1;
}
$yum_status =
&update_file($file,
[{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 => 'gpgkey=',
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 => 'gpgkey=',
value => $gpg,
}],$nobackup);
} elsif ($dist =~ /^(rhes|centos|scientific|oracle|rocky|alma)(\d+)(|\-stream)$/) {
my $type = $1;
my $ver = $2;
my $stream = $3;
my $longver = $ver;
my $nobackup;
if ($type eq 'rhes') {
if ($ver == 4) {
$longver = '4ES';
} elsif ($ver == 5) {
$longver = '5Server';
}
} elsif ($type eq 'centos') {
$type .= $stream;
}
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,
},
oracle => {
title => 'Oracle Linux',
path => 'oracle/loncapa',
gpg => 'versions/oracle/RPM-GPG-KEY-loncapa',
gpgchk => 1,
},
rocky => {
title => 'Rocky Linux',
path => 'rocky/loncapa',
gpg => 'versions/rocky/RPM-GPG-KEY-loncapa',
gpgchk => 1,
},
alma => {
title => 'AlmaLinux',
path => 'alma/loncapa',
gpg => 'versions/alma/RPM-GPG-KEY-loncapa',
gpgchk => 1,
},
'centos-stream' => {
title => 'CentOS Stream',
path => 'centos/loncapa',
gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
gpgchk => 1,
},
);
if (ref($info{$type}) eq 'HASH') {
if ($ver > 4) {
my $file = '/etc/yum.conf';
if (($ver > 7) || ($type eq 'oracle') || ($type eq 'rocky') ||
($type eq 'alma') || ($type eq 'centos-stream')) {
$file = '/etc/yum.repos.d/loncapa.repo';
$nobackup = 1;
}
my $release = '$releasever';
if ($type eq 'centos-stream') {
$release .= '-stream';
}
$yum_status =
&update_file($file,
[{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}/$release/".'$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}/$release/noarch",
}, {section => 'loncapa-updates-noarch',
key => 'gpgcheck=',
value => $info{$type}{gpgchk},
}, {section => 'loncapa-updates-noarch',
key => 'gpgkey=',
value => "$loninst/$info{$type}{gpg}",
}],$nobackup);
} 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 ($distname,$distver) = ($1,$2);
if ((($distname eq 'ubuntu') && ($distver > 20)) ||
(($distname eq 'debian') && ($distver >= 10))) {
$loninst = 'https://install.loncapa.org';
$loninst_re = 'https://install\.loncapa\.org';
}
my %apt_get_source = (
debian5 => {
regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+lenny\s+main',
text => "deb $loninst/debian lenny main",
},
debian6 => {
regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+squeeze\s+main',
text => "deb $loninst/debian squeeze main",
},
debian10 => {
regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/debian/?\s+buster\s+main',
text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/debian buster main",
},
debian11 => {
regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/debian/?\s+bullseye\s+main',
text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/debian bullseye main",
},
debian12 => {
regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/debian/?\s+bookworm\s+main',
text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/debian bookworm 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",
},
ubuntu10 => {
regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+lucid\s+main',
text => "deb $loninst/ubuntu lucid main",
},
ubuntu12 => {
regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+precise\s+main',
text => "deb $loninst/ubuntu precise main",
},
ubuntu14 => {
regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+trusty\s+main',
text => "deb $loninst/ubuntu trusty main",
},
ubuntu16 => {
regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+xenial\s+main',
text => "deb $loninst/ubuntu xenial main",
},
ubuntu18 => {
regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+bionic\s+main',
text => "deb $loninst/ubuntu bionic main",
},
ubuntu20 => {
regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+focal\s+main',
text => "deb $loninst/ubuntu focal main",
},
ubuntu22 => {
regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/ubuntu/?\s+jammy\s+main',
text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/ubuntu jammy main",
},
ubuntu24 => {
regexp => '\s*deb\s+\[signed\-by=/etc/apt/keyrings/loncapa\.gpg\]\s+'.$loninst_re.'/ubuntu/?\s+noble\s+main',
text => "deb [signed-by=/etc/apt/keyrings/loncapa.gpg] $loninst/ubuntu noble main",
},
);
my $apt_status;
if (defined($apt_get_source{$dist})) {
$apt_status = &update_apt_source($distname,$distver,$apt_get_source{$dist});
}
}
my $mysqlfile = '/etc/my.cnf';
my $mysqlconf = [{section =>'mysqld',
key =>'wait_timeout=',
value =>'31536000'}];
my $nomysqlbackup;
if ($dist =~ /^ubuntu(\d+)$/) {
my $version = $1;
$mysqlfile = '/etc/mysql/my.cnf';
if ($version > 14) {
$nomysqlbackup = 1;
$mysqlfile = '/etc/mysql/mysql.conf.d/mysqld.cnf';
if ($version < 20) {
push(@{$mysqlconf},
{section =>'mysqld',
key =>'sql_mode=',
value =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"'});
} else {
push(@{$mysqlconf},
{section =>'mysqld',
key =>'sql_mode=',
value =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"'});
}
}
} elsif ($dist =~ /^debian(\d+)$/) {
my $version = $1;
if ($version >= 10) {
$mysqlfile = '/etc/mysql/mariadb.conf.d/50-server.cnf';
$nomysqlbackup = 1;
}
}
my $mysql_global_status = &update_file($mysqlfile,$mysqlconf,$nomysqlbackup);
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 $needs_inputrc_check;
if ($dist =~ /^debian(\d+)$/) {
if ($1 >= 12) {
$needs_inputrc_check = 1;
}
} elsif ($dist =~ /^ubuntu(\d+)$/) {
if ($1 >= 22) {
$needs_inputrc_check = 1;
}
} elsif ($dist =~ /^(?:rhes|oracle|alma|rocky|centos)(\d+)(?:|\-stream)$/) {
if ($1 >= 9) {
$needs_inputrc_check = 1;
}
} elsif ($dist =~ /^fedora(\d+)$/) {
if ($1 >= 34) {
$needs_inputrc_check = 1;
}
}
if ($needs_inputrc_check) {
my $bash_www_cnf = '/home/www/.inputrc';
if (!-e $bash_www_cnf) {
system("touch $bash_www_cnf");
if (open(my $fh,'>',$bash_www_cnf)) {
print $fh <<'END';
$if R
set enable-bracketed-paste off
$endif
$if maxima
set enable-bracketed-paste off
$endif
END
close($fh);
} else {
warn "**** Error: could not open $bash_www_cnf to add 'set enable-bracketed-paste to off'";
}
my $wwwuid = getpwnam('www');
my $wwwgid = getgrnam('www');
if ($wwwuid!=$<) {
chown($wwwuid,$wwwgid,$bash_www_cnf);
}
} else {
my (%bracketed_paste_on,%bracketed_paste_off,@preserve,$condition);
$condition = '';
if (open(my $fh,'<',$bash_www_cnf)) {
while (my $line=<$fh>) {
chomp($line);
if ($line =~ /^\$if\s+(\w+)\s*$/) {
if ($1 eq 'R') {
$condition = 'r';
} elsif ($1 eq 'maxima') {
$condition = 'maxima';
} else {
$condition = 'other';
}
} elsif ($line =~ /^\$endif\s*$/) {
$condition = '';
}
if ($line =~ /^\s*set\s+enable\-bracketed\-paste\s+(off|on)\s*$/) {
if ($1 eq 'off') {
if ($condition ne '') {
$bracketed_paste_off{$condition} = 1;
} else {
$bracketed_paste_off{all} = 1;
}
push(@preserve,$line);
} else {
if ($condition ne '') {
$bracketed_paste_on{$condition} = 1;
if (($condition eq 'r') || ($condition eq 'maxima')) {
push(@preserve,' set enable-bracketed-paste off');
} else {
push(@preserve,$line);
}
} else {
$bracketed_paste_on{all} = 1;
push(@preserve,$line);
}
}
} else {
push(@preserve,$line);
}
}
close($fh);
}
if (($bracketed_paste_on{r} || $bracketed_paste_on{maxima}) ||
(!exists($bracketed_paste_off{r}) && !exists($bracketed_paste_on{r}) &&
!exists($bracketed_paste_off{maxima}) && !exists($bracketed_paste_on{maxima}))) {
if (open(my $fh,'>',$bash_www_cnf)) {
if (@preserve) {
foreach my $entry (@preserve) {
print $fh "$entry\n";
}
if (!exists($bracketed_paste_off{r}) && !exists($bracketed_paste_on{r})) {
print $fh <<'END';
$if R
set enable-bracketed-paste off
$endif
END
}
if (!exists($bracketed_paste_off{r}) && !exists($bracketed_paste_on{r})) {
print $fh <<'END';
$if maxima
set enable-bracketed-paste off
$endif
END
}
} else {
print $fh <<'END';
$if R
set enable-bracketed-paste off
$endif
$if maxima
set enable-bracketed-paste off
$endif
END
}
close($fh);
} else {
warn "**** Error: could not open $bash_www_cnf to add 'set enable-bracketed-paste to off'";
}
}
}
}
my $exitvalue = 0;
if ($mysql_global_status) { $exitvalue = 1; }
exit $exitvalue;
#################################################################
#################################################################
=pod
=over 4
=item &update_file()
Calls &parse_config_file for a file and then sends the
retrieved data to &modify_config_file, and checks if
modificatione were made.
Inputs: filename, newdata (reference to an array of hashed),
nobackup 1, if no backup of existing file (.backup
appended to filename) should be made.
Output: 0 or 1; o if no modifications exist (and hence no file
needed to be saved, or 1 if modifications made, and call to
&write_config_file to save file, or if filename does not exist.
=back
=cut
#################################################################
#################################################################
sub update_file {
my ($file,$newdata,$nobackup) = @_;
return 1 if (! -e $file);
unless ($nobackup) {
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 = <INFILE>;
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_config_file()
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<scalar(@$structure);$i++) {
my $line = $structure->[$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<scalar(@$target);$i++) {
if ($target->[$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 either the sources.list or sources.list.d/loncapa.list
file which include repositories used by apt-get.
Inputs:
$distname - distro (without version): debian or ubuntu
$distver - distro version, e.g., 12 or 24
$deb_row - a reference to 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 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 ($distname,$distver,$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';
my $nobackup;
if ((($distname eq 'ubuntu') && ($distver > 20)) ||
(($distname eq 'debian') && ($distver >= 10))) {
$file = '/etc/apt/sources.list.d/loncapa.list';
$nobackup = 1;
}
return 0 if (! -e $file);
unless ($nobackup) {
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;
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>