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

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

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