Annotation of loncom/debugging_tools/modify_config_files.pl, revision 1.23

1.1       matthew     1: #!/usr/bin/perl -w
                      2: #
                      3: # The LearningOnline Network
                      4: #
1.23    ! raeburn     5: # $Id: modify_config_files.pl,v 1.22 2021/12/21 13:57:47 raeburn Exp $
1.1       matthew     6: #
                      7: # Copyright Michigan State University Board of Trustees
                      8: #
                      9: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     10: #
                     11: # LON-CAPA is free software; you can redistribute it and/or modify
                     12: # it under the terms of the GNU General Public License as published by
                     13: # the Free Software Foundation; either version 2 of the License, or
                     14: # (at your option) any later version.
                     15: #
                     16: # LON-CAPA is distributed in the hope that it will be useful,
                     17: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     18: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     19: # GNU General Public License for more details.
                     20: #
                     21: # You should have received a copy of the GNU General Public License
                     22: # along with LON-CAPA; if not, write to the Free Software
                     23: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     24: #
                     25: # /home/httpd/html/adm/gpl.txt
                     26: #
                     27: # http://www.lon-capa.org/
                     28: #
                     29: ###
                     30: 
                     31: =pod
                     32: 
                     33: =head1 NAME
                     34: 
                     35: B<modify_config_files.pl>
                     36: 
                     37: =head1 SYNOPSIS
                     38: 
1.9       raeburn    39: This script modifies /etc/my.cnf and one of: /etc/yum.conf 
1.16      raeburn    40: (for CentOS/Scientific Linux/RHEL >=5 and <8), /etc/apt/sources.list
1.13      raeburn    41: (for Debian/Ubuntu), /etc/sysconfig/rhn/sources (for RHEL4),
1.16      raeburn    42: and /etc/yum.repos.d/loncapa.repo (Fedora >= 21; Oracle Linux; 
                     43: CentOS/RHEL >= 8).
1.1       matthew    44: 
                     45: =head1 DESCRIPTION
                     46: 
1.13      raeburn    47: This script modifies /etc/my.cnf, /etc/yum.conf, /etc/yum.repos.d/loncapa.repo,
                     48: /etc/apt/sources, or /etc/sysconfig/rhn/sources to ensure certain
                     49: parameters are set properly.
                     50: 
                     51: The LON-CAPA yum repositories are added to /etc/yum.conf, 
                     52: /etc/yum.repos.d/loncapa.repo, /etc/sysconfig/rhn/sources
                     53: and the LON-CAPA apt repositories are added to 
1.9       raeburn    54: /etc/apt/sources.list.
                     55: 
1.1       matthew    56: The /etc/my.cnf file is modified to set the wait_timeout to 1 year.  Backup
1.9       raeburn    57: copies of each file are made in /etc, /etc/apt, and /etc/sysconfig/rhn, as 
                     58: appropriate.
1.1       matthew    59: 
                     60: =cut
                     61: 
                     62: use strict;
                     63: use File::Copy;
1.3       matthew    64: use lib '/home/httpd/lib/perl/';
                     65: use LONCAPA::Configuration;
                     66: my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf');
1.1       matthew    67: 
1.6       raeburn    68: open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |");
                     69: my $dist = <DSH>;
                     70: chomp($dist);
                     71: close(DSH);
                     72: 
                     73: my $yum_status;
1.9       raeburn    74: my $loninst = 'http://install.loncapa.org';
                     75: my $loninst_re = 'http://install\.loncapa\.org';
                     76: if ($dist =~ /^fedora(\d+)$/) {
1.13      raeburn    77:     my $file = '/etc/yum.conf';
1.9       raeburn    78:     my $ver = $1;
1.10      raeburn    79:     my $gpgchk = '0';
1.9       raeburn    80:     my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa"; 
1.13      raeburn    81:     my $nobackup;
1.9       raeburn    82:     if ($ver > 6) {
1.10      raeburn    83:         $gpgchk = '1';
1.9       raeburn    84:     }
1.13      raeburn    85:     if ($ver >= 21) {
                     86:         $file = '/etc/yum.repos.d/loncapa.repo';
                     87:         $nobackup = 1;
                     88:     }
1.6       raeburn    89:     $yum_status =  
1.13      raeburn    90:         &update_file($file,
1.10      raeburn    91:              [{section => 'loncapa-updates-basearch',
1.1       matthew    92:                key     => 'name=',
1.6       raeburn    93:                value   => 'Fedora Core $releasever LON-CAPA $basearch Updates',
1.10      raeburn    94:            }, {section => 'loncapa-updates-basearch',
1.1       matthew    95:                key     => 'baseurl=',
1.9       raeburn    96:                value   => $loninst.'/fedora/linux/loncapa/$releasever/$basearch',
1.10      raeburn    97:            }, {section => 'loncapa-updates-basearch',
1.5       matthew    98:                key     => 'gpgcheck=',
1.9       raeburn    99:                value   =>  $gpgchk,
1.10      raeburn   100:            }, {section => 'loncapa-updates-basearch',
1.13      raeburn   101:                key     => 'gpgkey=',
1.9       raeburn   102:                value   => $gpg,
1.1       matthew   103:            }, {section => 'loncapa-updates-noarch',
                    104:                key     => 'name=',
                    105:                value   => 'Fedora Core $releasever LON-CAPA noarch Updates',
                    106:            }, {section => 'loncapa-updates-noarch',
                    107:                key     => 'baseurl=',
1.9       raeburn   108:                value   => $loninst.'/fedora/linux/loncapa/$releasever/noarch',
1.5       matthew   109:            }, {section => 'loncapa-updates-noarch',
                    110:                key     => 'gpgcheck=',
1.9       raeburn   111:                value   => $gpgchk,
                    112:            }, {section => 'loncapa-updates-noarch',
1.13      raeburn   113:                key     => 'gpgkey=',
1.9       raeburn   114:                value   => $gpg,
1.13      raeburn   115:            }],$nobackup);
1.22      raeburn   116: } elsif ($dist =~ /^(rhes|centos|scientific|oracle|rocky|alma)(\d+)(|\-stream)$/) {
1.9       raeburn   117:     my $type = $1;
                    118:     my $ver = $2;
1.22      raeburn   119:     my $stream = $3;
1.9       raeburn   120:     my $longver = $ver;
1.16      raeburn   121:     my $nobackup;
1.9       raeburn   122:     if ($type eq 'rhes') {
                    123:         if ($ver == 4) {
                    124:             $longver = '4ES';
                    125:         } elsif ($ver == 5) {
                    126:             $longver = '5Server';
                    127:         }
1.22      raeburn   128:     } elsif ($type eq 'centos') {
                    129:         $type .= $stream;
1.9       raeburn   130:     }
                    131:     my %info = (
                    132:                  rhes => {
                    133:                            title => 'RHEL',
                    134:                            path => 'redhat/linux/enterprise/loncapa',
                    135:                            gpg => 'versions/redhat/RPM-GPG-KEY-loncapa',
                    136:                            gpgchk => 1,
                    137:                          },
                    138:                  centos => {
                    139:                              title => 'CentOS',
                    140:                              path => 'centos/loncapa',
                    141:                              gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
                    142:                              gpgchk => 1,
                    143:                            },
                    144:                  scientific => {
                    145:                                  title => 'Scientific Linux',
                    146:                                  path => 'scientific/loncapa',
                    147:                                  gpg => 'versions/scientific/RPM-GPG-KEY-loncapa',
                    148:                                  gpgchk => 1,
                    149:                                },
1.15      raeburn   150:                  oracle => {
                    151:                              title => 'Oracle Linux',
                    152:                              path => 'oracle/loncapa',
                    153:                              gpg => 'versions/oracle/RPM-GPG-KEY-loncapa',
                    154:                              gpgchk => 1,
                    155:                            },
1.21      raeburn   156:                  rocky => {
                    157:                              title => 'Rocky Linux',
                    158:                              path => 'rocky/loncapa',
                    159:                              gpg => 'versions/rocky/RPM-GPG-KEY-loncapa',
                    160:                              gpgchk => 1,
                    161:                           },
                    162:                  alma => {
                    163:                              title => 'AlmaLinux',
                    164:                              path => 'alma/loncapa',
                    165:                              gpg => 'versions/alma/RPM-GPG-KEY-loncapa',
                    166:                              gpgchk => 1,
                    167:                           },
1.23    ! raeburn   168:                  'centos-stream' => {
1.22      raeburn   169:                                       title => 'CentOS Stream',
                    170:                                       path  => 'centos/loncapa',
                    171:                                       gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
                    172:                                       gpgchk => 1, 
1.23    ! raeburn   173:                                     },
1.9       raeburn   174:                );
                    175:     if (ref($info{$type}) eq 'HASH') {
                    176:         if ($ver > 4) {
1.16      raeburn   177:             my $file = '/etc/yum.conf';
1.22      raeburn   178:             if (($ver > 7) || ($type eq 'oracle') || ($type eq 'rocky') || 
                    179:                 ($type eq 'alma') || ($type eq 'centos-stream')) {
1.16      raeburn   180:                 $file = '/etc/yum.repos.d/loncapa.repo';
                    181:                 $nobackup = 1;
                    182:             }
1.22      raeburn   183:             my $release = '$releasever';
                    184:             if ($type eq 'centos-stream') {
                    185:                 $release .= '-stream';
                    186:             }
1.9       raeburn   187:             $yum_status =
1.16      raeburn   188:                 &update_file($file,
1.9       raeburn   189:                      [{section => 'loncapa-updates-basearch',
                    190:                        key     => 'name=',
                    191:                        value   => $info{$type}{title}.' $releasever LON-CAPA $basearch Updates',
                    192:                       }, {section => "loncapa-updates-basearch",
                    193:                           key     => 'baseurl=',
1.22      raeburn   194:                           value   => "$loninst/$info{$type}{path}/$release/".'$basearch',
1.9       raeburn   195:                       }, {section => 'loncapa-updates-basearch',
                    196:                           key     => 'gpgcheck=',
1.11      raeburn   197:                           value   => $info{$type}{gpgchk},
1.10      raeburn   198:                       }, {section => 'loncapa-updates-basearch',
1.9       raeburn   199:                           key     => 'gpgkey=',
                    200:                           value   => "$loninst/$info{$type}{gpg}",
                    201:                       }, {section => 'loncapa-updates-noarch',
                    202:                           key     => 'name=',
                    203:                           value   => $info{$type}{title}.' $releasever LON-CAPA noarch Updates',
                    204:                       }, {section => 'loncapa-updates-noarch',
                    205:                           key     => 'baseurl=',
1.22      raeburn   206:                           value   => "$loninst/$info{$type}{path}/$release/noarch",
1.9       raeburn   207:                       }, {section => 'loncapa-updates-noarch',
                    208:                           key     => 'gpgcheck=',
1.11      raeburn   209:                           value   => $info{$type}{gpgchk},
1.9       raeburn   210:                       }, {section => 'loncapa-updates-noarch',
                    211:                           key     => 'gpgkey=',
                    212:                           value   => "$loninst/$info{$type}{gpg}",
1.16      raeburn   213:                       }],$nobackup);
1.9       raeburn   214:         } elsif (($type eq 'rhes') && ($ver == 4)) {
                    215:             my %rhn = (
                    216:                         basearch => { 
                    217:                             regexp => '\s*yum\s+loncapa\-updates\-basearch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/\$ARCH',
                    218:                             text => "yum loncapa-updates-basearch $loninst/$info{$type}{path}/$longver/".'$ARCH',
                    219:                                     },
                    220:                         noarch =>  {
                    221:                             regexp => '\s*yum\s+loncapa\-updates\-noarch\s+'.$loninst_re.'/'.$info{$type}{path}.'/'.$longver.'/noarch',
                    222:                             text => "yum loncapa-updates-noarch $loninst/$info{$type}{path}/$longver/noarch",
                    223:                                    },
                    224:                       );
                    225:             $yum_status = &update_rhn_source(\%rhn); 
                    226:         }
                    227:     }
                    228: } elsif ($dist =~ /^(debian|ubuntu)\d+$/) {
                    229:     my %apt_get_source = (
                    230:                            debian5 => {
1.18      raeburn   231:                                         regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+lenny\s+main',
                    232:                                         text   => "deb $loninst/debian lenny main",
1.9       raeburn   233:                                       },
                    234:                            ubuntu6 => {
1.18      raeburn   235:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+dapper\s+main',
                    236:                                         text   => "deb $loninst/ubuntu dapper main",
1.9       raeburn   237:                                       },
                    238:                            ubuntu8 => {
1.18      raeburn   239:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+hardy\s+main',
                    240:                                         text   => "deb $loninst/ubuntu hardy main",
1.9       raeburn   241:                                       },
1.14      raeburn   242:                            ubuntu10 => {
1.18      raeburn   243:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+lucid\s+main',
                    244:                                         text   => "deb $loninst/ubuntu lucid main",
1.14      raeburn   245:                                        },
                    246:                            ubuntu12 => {
1.18      raeburn   247:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+precise\s+main',
                    248:                                         text   => "deb $loninst/ubuntu precise main",
1.14      raeburn   249:                                        },
                    250:                            ubuntu14 => {
1.18      raeburn   251:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+trusty\s+main',
                    252:                                         text   => "deb $loninst/ubuntu trusty main",
1.14      raeburn   253:                                        },
                    254:                            ubuntu16 => {
1.18      raeburn   255:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+xenial\s+main',
                    256:                                         text   => "deb $loninst/ubuntu xenial main",
1.14      raeburn   257:                                        },
                    258:                            ubuntu18 => {
1.18      raeburn   259:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+bionic\s+main',
                    260:                                         text   => "deb $loninst/ubuntu bionic main",
1.14      raeburn   261:                                        },
1.17      raeburn   262:                            ubuntu20 => {
1.18      raeburn   263:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+focal\s+main',
                    264:                                         text   => "deb $loninst/ubuntu focal main",
1.17      raeburn   265:                                        },
1.9       raeburn   266:                          );
                    267:     my $apt_status;
                    268:     if (defined($apt_get_source{$dist})) {
                    269:         $apt_status = &update_apt_source($apt_get_source{$dist},);
1.6       raeburn   270:     }
                    271: }
1.1       matthew   272: 
1.19      raeburn   273: my $mysqlfile = '/etc/my.cnf';
1.20      raeburn   274: my $mysqlconf = [{section =>'mysqld',
                    275:                   key     =>'wait_timeout=',
                    276:                   value   =>'31536000'}];
1.19      raeburn   277: if ($dist =~ /^ubuntu(\d+)$/) {
                    278:     my $version = $1;
                    279:     $mysqlfile = '/etc/mysql/my.cnf';
                    280:     if ($version > 14) {
                    281:         $mysqlfile = '/etc/mysql/mysql.conf.d/mysqld.cnf';
1.20      raeburn   282:         if ($version < 20) {
                    283:             push(@{$mysqlconf},
                    284:                  {section =>'mysqld',
                    285:                   key     =>'sql_mode=',
                    286:                   value   =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"'});
                    287:         } else {
                    288:             push(@{$mysqlconf},
                    289:                  {section =>'mysqld',
                    290:                   key     =>'sql_mode=',
                    291:                   value   =>'"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"'});
                    292:         }
1.19      raeburn   293:     }
                    294: }
                    295: 
1.20      raeburn   296: my $mysql_global_status = &update_file($mysqlfile,$mysqlconf);
1.1       matthew   297: 
1.3       matthew   298: my $local_my_cnf = '/home/www/.my.cnf';
                    299: if (! -e $local_my_cnf) {
1.4       matthew   300:     # Create a file so we can do something with it...
1.3       matthew   301:     system("touch $local_my_cnf");
                    302: }
1.4       matthew   303: my $mysql_www_status =
                    304:     &update_file($local_my_cnf,
1.3       matthew   305:              [{section =>'client',
                    306:                key     =>'user=',
                    307:                value   =>'www',},
                    308:               {section =>'client',
                    309:                key     =>'password=',
                    310:                value   =>$loncapa_config->{'lonSqlAccess'}},]);
                    311: 
1.4       matthew   312: my $exitvalue = 0;
                    313: 
                    314: if ($mysql_global_status) { $exitvalue = 1; }
                    315: 
                    316: exit $exitvalue;
1.1       matthew   317: 
                    318: 
                    319: sub update_file {
1.13      raeburn   320:     my ($file,$newdata,$nobackup) = @_;
1.1       matthew   321:     return 1 if (! -e $file);
1.13      raeburn   322:     unless ($nobackup) {
                    323:         my $backup = $file.'.backup';
                    324:         if (! copy($file,$backup)) {
                    325:             warn "**** Error: Unable to make backup of $file";
                    326:             return 0;
                    327:         }
1.1       matthew   328:     }
                    329:     my ($filedata) = &parse_config_file($file);
1.4       matthew   330:     if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
                    331:     my $modified = 0;
1.1       matthew   332:     foreach my $data (@$newdata) {
                    333:         my $section = $data->{'section'};
                    334:         my $key = $data->{'key'};
                    335:         my $value = $data->{'value'};
1.4       matthew   336:         my $result = &modify_config_file($filedata,$section,$key,$value);
                    337:         if ($result) { $modified = 1; }
                    338:     }
                    339:     if ($modified) {
                    340:         my $result = &write_config_file($file,$filedata);
                    341:         if (defined($result)) { warn 'Error:'.$result; return 0; }
1.1       matthew   342:     }
1.4       matthew   343:     return $modified;
1.1       matthew   344: }
                    345: 
                    346: #################################################################
                    347: #################################################################
                    348: 
                    349: =pod
                    350: 
1.9       raeburn   351: =over 4
                    352: 
                    353: =item &parse_config_file()
1.1       matthew   354: 
                    355: Read a configuration file in and parse it into an internal data structure.
                    356: 
                    357: Input: filename
                    358: 
                    359: Output: array ref $filedata  OR  scalar error message
                    360: 
1.9       raeburn   361: =back 
                    362: 
1.1       matthew   363: =cut
                    364: 
                    365: #################################################################
                    366: #################################################################
                    367: sub parse_config_file {
                    368:     my ($file) = @_;
                    369:     open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
                    370:     my @Input = <INFILE>;
                    371:     close(INFILE);
                    372:     my @Structure;
                    373:     my %Sections;
                    374:     while (my $line = shift(@Input)) {
                    375:         chomp($line);
                    376:         if ($line =~ /^\[([^\]]*)\]/) {
                    377:             my $section_id = $1;
                    378:             push(@Structure,'__section__'.$section_id);
                    379:             while ($line = shift(@Input)) {
1.4       matthew   380:                 chomp($line);
1.1       matthew   381:                 if ($line =~ /^\[([^\]]*)\]/) {
                    382:                     unshift(@Input,$line);
                    383:                     last;
                    384:                 } else {
                    385:                     push(@{$Sections{$section_id}},$line);
                    386:                 }
                    387:             }
                    388:         } else {
                    389:             push(@Structure,$line);
                    390:         }
                    391:     }
                    392:     my $filedata = [\@Structure,\%Sections];
                    393:     return $filedata;
                    394: }
                    395: 
                    396: #################################################################
                    397: #################################################################
                    398: 
                    399: =pod
                    400: 
1.9       raeburn   401: =over 4
                    402: 
1.1       matthew   403: =item
                    404: 
                    405: Write a configuration file out based on the internal data structure returned
                    406: by &parse_config_file
                    407: 
                    408: Inputs: filename, $filedata (the return value of &parse_config_file
                    409: 
                    410: Returns: undef on success, scalar error message on failure.
                    411: 
1.9       raeburn   412: =back
                    413: 
1.1       matthew   414: =cut
                    415: 
                    416: #################################################################
                    417: #################################################################
                    418: sub write_config_file {
                    419:     my ($file,$filedata) = @_;
                    420:     my ($structure,$sections) = @$filedata;
                    421:     if (! defined($structure) || ! ref($structure)) {
                    422:         return 'Bad subroutine inputs';
                    423:     }
1.18      raeburn   424:     open(OUTPUT,'>',$file) || return('Unable to open '.$file.' for writing');
1.1       matthew   425:     for (my $i=0;$i<scalar(@$structure);$i++) {
                    426:         my $line = $structure->[$i];
                    427:         chomp($line);
                    428:         if ($line =~ /^__section__(.*)$/) {
                    429:             my $section_id = $1;
                    430:             print OUTPUT ('['.$section_id.']'.$/);
                    431:             foreach my $section_line (@{$sections->{$section_id}}) {
                    432:                 chomp($section_line);
                    433:                 print OUTPUT $section_line.$/;
                    434:             }
                    435:             # Deal with blank lines
                    436:             if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
                    437:                 # No need to output a blank line at the end if there is one 
                    438:                 # already
                    439:             } else {
                    440:                 print OUTPUT $/;
                    441:             }
                    442:         } else {
                    443:             print OUTPUT $line.$/;
                    444:         }
                    445:     }
                    446:     close OUTPUT;
                    447:     return undef;
                    448: }
                    449: 
                    450: #################################################################
                    451: #################################################################
                    452: 
                    453: =pod
                    454: 
1.9       raeburn   455: =over 4
                    456: 
                    457: =item &modify_config_file()
1.1       matthew   458: 
                    459: Modifies the internal data structure of a configuration file to include new
                    460: sections and/or new configuration directives.
                    461: 
                    462: Inputs: $filedata (see &parse_config_file
                    463: $section, the [section] the new entry is to reside in.  A value of undef will
                    464: cause the "outer" section (as in yum.conf) to be updated (or have the new
                    465: value prepended).
                    466: $newkey: A line which matches this will be replaced with $newkey.$newvalue
                    467: $newvalue: The new value to be placed with the new key.
                    468: 
1.4       matthew   469: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
                    470: 
1.9       raeburn   471: =back 
1.4       matthew   472: 
1.1       matthew   473: =cut
                    474: 
                    475: #################################################################
                    476: #################################################################
                    477: sub modify_config_file {
                    478:     my ($filedata,$section,$newkey,$newvalue)=@_;
1.4       matthew   479:     my $modified = 0;    # returned value - set to true if the file is modified
1.1       matthew   480:     my ($structure,$sections) = @$filedata;
                    481:     if (! defined($newvalue)) {
                    482:         $newvalue = '';
                    483:     }
                    484:     my $newline = $newkey.$newvalue;
                    485:     #
                    486:     # Determine which array ref gets the item
                    487:     my $target;
                    488:     if (defined($section)) {
                    489:         if (! exists($sections->{$section})) {
                    490:             push(@$structure,'__section__'.$section);
                    491:             $sections->{$section}=[];
                    492:         }
                    493:         $target = $sections->{$section};
                    494:     } else {
                    495:         $target = $structure;
                    496:     }
                    497:     #
                    498:     # Put the item in or update it.
                    499:     my $key_is_new = 1;
                    500:     for (my $i=0;$i<scalar(@$target);$i++) {
                    501:         if ($target->[$i] =~/^$newkey/) {
1.4       matthew   502:             if ($target->[$i] ne $newline) {
                    503:                 $target->[$i]=$newline;
                    504:                 $modified = 1;
                    505:             }
1.1       matthew   506:             $key_is_new = 0;
                    507:             last;
                    508:         }
                    509:     }
                    510:     if ($key_is_new) {
                    511:         if (! defined($section)) {
                    512:             unshift(@$target,$newline);
                    513:         } else {
                    514:             # No need to put things after a blank line.
1.2       matthew   515:             if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
1.1       matthew   516:                 $target->[-1] = $newline;
1.4       matthew   517:                 $modified = 1;
1.1       matthew   518:             } else {
                    519:                 push(@$target,$newline);
1.4       matthew   520:                 $modified = 1;
1.1       matthew   521:             }
                    522:         }
                    523:     }
1.4       matthew   524:     return $modified;
1.1       matthew   525: }
                    526: 
1.9       raeburn   527: #################################################################
                    528: #################################################################
                    529: 
                    530: =pod
                    531: 
                    532: =over 4
                    533: 
                    534: =item &update_rhn_source()
                    535: 
                    536: Modifies the Red Hat 4 sources file which includes repositories used by up2date 
                    537: 
                    538: Inputs: 
                    539: $rhn_items - a reference to hash of a hash containing the regular expression
                    540: to test for, and the text string to append to the file, if an entry for the 
                    541: LON-CAPA RHEL repository is missing for two cases:
                    542: 
                    543: (a) basearch
                    544: (b) noarch 
                    545: 
                    546: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
                    547: 
                    548: =back
                    549: 
                    550: =cut
                    551: 
                    552: #################################################################
                    553: #################################################################
                    554: sub update_rhn_source {
                    555:     my ($rhn_items) = @_;
                    556:     return 0 if (ref($rhn_items) ne 'HASH');
                    557:     return 0 if ((ref($rhn_items->{basearch}) ne 'HASH') || (ref($rhn_items->{noarch}) ne 'HASH'));
                    558:     my $file = '/etc/sysconfig/rhn/sources';
                    559:     return 0 if (! -e $file);
                    560:     my $backup = $file.'.backup';
                    561:     if (! copy($file,$backup)) {
                    562:         warn "**** Error: Unable to make backup of $file";
                    563:         return 0;
                    564:     }
                    565:     my $result = 0;
                    566:     my $fh;
1.18      raeburn   567:     if (open($fh,'<',$file)) {
1.9       raeburn   568:         my $total = 0;
                    569:         my %found;
                    570:         foreach my $item (keys(%{$rhn_items})) {
                    571:             $found{$item} = 0;
                    572:         }
                    573:         while(<$fh>) {
                    574:             foreach my $item (keys(%{$rhn_items})) {
                    575:                 if (ref($rhn_items->{$item}) eq 'HASH') {
                    576:                     my $pattern = $rhn_items->{$item}->{regexp};
                    577:                     if ($pattern ne '') { 
                    578:                         if (m{^$pattern}) {
                    579:                             $found{$item} = 1;
                    580:                             $total ++;
                    581:                         }
                    582:                     }
                    583:                 }
                    584:             }
                    585:             last if $total == 2;
                    586:         }
                    587:         close($fh);
                    588:         if ($total < 2) {
1.18      raeburn   589:             if (open($fh,'>>',$file)) {
1.9       raeburn   590:                 foreach my $item (keys(%{$rhn_items})) {
                    591:                     unless ($found{$item}) {
                    592:                         if (ref($rhn_items->{$item}) eq 'HASH') {
                    593:                             if ($rhn_items->{$item}->{text} ne '') {
                    594:                                 print $fh "\n".$rhn_items->{$item}->{text}."\n";
                    595:                                 $result = 1;
                    596:                             }
                    597:                         }
                    598:                     }
                    599:                 }
                    600:                 close($fh);
                    601:             }
                    602:         }
                    603:     }
                    604:     return $result;
                    605: }
1.1       matthew   606: 
                    607: #################################################################
                    608: #################################################################
                    609: 
                    610: =pod
                    611: 
1.9       raeburn   612: =over 4
                    613: 
                    614: =item &update_apt_source()
                    615: 
                    616: Modifies the source.list file which includes repositories used by apt-get
                    617: 
                    618: Inputs:
                    619: $deb_row - a reference to containing the regular expression
                    620: to test for, and the text string to append to the file, if an entry for the
                    621: LON-CAPA Debian/ or Ubuntu repository is missing.
                    622: 
                    623: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
                    624: 
1.1       matthew   625: =back
                    626: 
                    627: =cut
                    628: 
                    629: #################################################################
                    630: #################################################################
1.9       raeburn   631: sub update_apt_source {
                    632:     my ($deb_row) = @_;
                    633:     return 0 if (ref($deb_row) ne 'HASH');
                    634:     return 0 if (($deb_row->{regexp} eq '') || ($deb_row->{text} eq ''));
                    635:     my $file = '/etc/apt/sources.list';
                    636:     return 0 if (! -e $file);
                    637:     my $backup = $file.'.backup';
                    638:     if (! copy($file,$backup)) {
                    639:         warn "**** Error: Unable to make backup of $file";
                    640:         return 0;
                    641:     }
                    642:     my $result = 0;
                    643:     my $fh;
1.18      raeburn   644:     if (open($fh,'<',$file)) {
1.9       raeburn   645:         my $found = 0;
                    646:         my $pattern = $deb_row->{regexp};
                    647:         while(<$fh>) {
                    648:             if (m{^$pattern}) {
                    649:                 $found = 1;
                    650:                 last;
                    651:             }
                    652:         }
                    653:         close($fh);
                    654:         if (!$found) {
1.18      raeburn   655:             if (open($fh,'>>',$file)) {
1.9       raeburn   656:                 print $fh "\n".$deb_row->{text}."\n";
                    657:                 close($fh);
                    658:                 $result = 1;
                    659:             }
                    660:         }
                    661:     }
                    662:     return $result;
                    663: }
                    664: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>