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

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

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