File:  [LON-CAPA] / loncom / debugging_tools / modify_config_files.pl
Revision 1.27: download - view: text, annotated - select for diffs
Mon Jul 15 15:48:52 2024 UTC (5 weeks, 4 days ago) by raeburn
Branches: MAIN
CVS tags: HEAD
- set enable-bracketed-paste off added just for specific applications
  (R and amaxima) in /home/www/.inputrc

    1: #!/usr/bin/perl -w
    2: #
    3: # The LearningOnline Network
    4: #
    5: # $Id: modify_config_files.pl,v 1.27 2024/07/15 15:48:52 raeburn Exp $
    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: 
   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).
   51: 
   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: 
   56: =head1 DESCRIPTION
   57: 
   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 
   63: /etc/sysconfig/rhn/sources and /home/www/.inputrc to ensure 
   64: certain parameters are set properly.
   65: 
   66: The LON-CAPA yum repositories are added to /etc/yum.conf, 
   67: /etc/yum.repos.d/loncapa.repo, or /etc/sysconfig/rhn/sources
   68: and the LON-CAPA apt repositories are added to 
   69: /etc/apt/sources.list or /etc/apt/sources.list.d/loncapa.list.
   70: 
   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.
   75: 
   76: =cut
   77: 
   78: use strict;
   79: use File::Copy;
   80: use lib '/home/httpd/lib/perl/';
   81: use LONCAPA::Configuration;
   82: my $loncapa_config=LONCAPA::Configuration::read_conf('loncapa.conf');
   83: 
   84: open(DSH,"$$loncapa_config{'lonDaemons'}/distprobe |");
   85: my $dist = <DSH>;
   86: chomp($dist);
   87: close(DSH);
   88: 
   89: my $yum_status;
   90: my $loninst = 'http://install.loncapa.org';
   91: my $loninst_re = 'http://install\.loncapa\.org';
   92: if ($dist =~ /^fedora(\d+)$/) {
   93:     my $file = '/etc/yum.conf';
   94:     my $ver = $1;
   95:     my $gpgchk = '0';
   96:     my $gpg = "$loninst/versions/fedora/RPM-GPG-KEY-loncapa"; 
   97:     my $nobackup;
   98:     if ($ver > 6) {
   99:         $gpgchk = '1';
  100:     }
  101:     if ($ver >= 21) {
  102:         $file = '/etc/yum.repos.d/loncapa.repo';
  103:         $nobackup = 1;
  104:     }
  105:     $yum_status =  
  106:         &update_file($file,
  107:              [{section => 'loncapa-updates-basearch',
  108:                key     => 'name=',
  109:                value   => 'Fedora Core $releasever LON-CAPA $basearch Updates',
  110:            }, {section => 'loncapa-updates-basearch',
  111:                key     => 'baseurl=',
  112:                value   => $loninst.'/fedora/linux/loncapa/$releasever/$basearch',
  113:            }, {section => 'loncapa-updates-basearch',
  114:                key     => 'gpgcheck=',
  115:                value   =>  $gpgchk,
  116:            }, {section => 'loncapa-updates-basearch',
  117:                key     => 'gpgkey=',
  118:                value   => $gpg,
  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=',
  124:                value   => $loninst.'/fedora/linux/loncapa/$releasever/noarch',
  125:            }, {section => 'loncapa-updates-noarch',
  126:                key     => 'gpgcheck=',
  127:                value   => $gpgchk,
  128:            }, {section => 'loncapa-updates-noarch',
  129:                key     => 'gpgkey=',
  130:                value   => $gpg,
  131:            }],$nobackup);
  132: } elsif ($dist =~ /^(rhes|centos|scientific|oracle|rocky|alma)(\d+)(|\-stream)$/) {
  133:     my $type = $1;
  134:     my $ver = $2;
  135:     my $stream = $3;
  136:     my $longver = $ver;
  137:     my $nobackup;
  138:     if ($type eq 'rhes') {
  139:         if ($ver == 4) {
  140:             $longver = '4ES';
  141:         } elsif ($ver == 5) {
  142:             $longver = '5Server';
  143:         }
  144:     } elsif ($type eq 'centos') {
  145:         $type .= $stream;
  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:                                },
  166:                  oracle => {
  167:                              title => 'Oracle Linux',
  168:                              path => 'oracle/loncapa',
  169:                              gpg => 'versions/oracle/RPM-GPG-KEY-loncapa',
  170:                              gpgchk => 1,
  171:                            },
  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:                           },
  184:                  'centos-stream' => {
  185:                                       title => 'CentOS Stream',
  186:                                       path  => 'centos/loncapa',
  187:                                       gpg => 'versions/centos/RPM-GPG-KEY-loncapa',
  188:                                       gpgchk => 1, 
  189:                                     },
  190:                );
  191:     if (ref($info{$type}) eq 'HASH') {
  192:         if ($ver > 4) {
  193:             my $file = '/etc/yum.conf';
  194:             if (($ver > 7) || ($type eq 'oracle') || ($type eq 'rocky') || 
  195:                 ($type eq 'alma') || ($type eq 'centos-stream')) {
  196:                 $file = '/etc/yum.repos.d/loncapa.repo';
  197:                 $nobackup = 1;
  198:             }
  199:             my $release = '$releasever';
  200:             if ($type eq 'centos-stream') {
  201:                 $release .= '-stream';
  202:             }
  203:             $yum_status =
  204:                 &update_file($file,
  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=',
  210:                           value   => "$loninst/$info{$type}{path}/$release/".'$basearch',
  211:                       }, {section => 'loncapa-updates-basearch',
  212:                           key     => 'gpgcheck=',
  213:                           value   => $info{$type}{gpgchk},
  214:                       }, {section => 'loncapa-updates-basearch',
  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=',
  222:                           value   => "$loninst/$info{$type}{path}/$release/noarch",
  223:                       }, {section => 'loncapa-updates-noarch',
  224:                           key     => 'gpgcheck=',
  225:                           value   => $info{$type}{gpgchk},
  226:                       }, {section => 'loncapa-updates-noarch',
  227:                           key     => 'gpgkey=',
  228:                           value   => "$loninst/$info{$type}{gpg}",
  229:                       }],$nobackup);
  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:     }
  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:     }
  251:     my %apt_get_source = (
  252:                            debian5 => {
  253:                                         regexp => '\s*deb\s+'.$loninst_re.'/debian/?\s+lenny\s+main',
  254:                                         text   => "deb $loninst/debian lenny main",
  255:                                       },
  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: 
  273:                            ubuntu6 => {
  274:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+dapper\s+main',
  275:                                         text   => "deb $loninst/ubuntu dapper main",
  276:                                       },
  277:                            ubuntu8 => {
  278:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+hardy\s+main',
  279:                                         text   => "deb $loninst/ubuntu hardy main",
  280:                                       },
  281:                            ubuntu10 => {
  282:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+lucid\s+main',
  283:                                         text   => "deb $loninst/ubuntu lucid main",
  284:                                        },
  285:                            ubuntu12 => {
  286:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+precise\s+main',
  287:                                         text   => "deb $loninst/ubuntu precise main",
  288:                                        },
  289:                            ubuntu14 => {
  290:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+trusty\s+main',
  291:                                         text   => "deb $loninst/ubuntu trusty main",
  292:                                        },
  293:                            ubuntu16 => {
  294:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+xenial\s+main',
  295:                                         text   => "deb $loninst/ubuntu xenial main",
  296:                                        },
  297:                            ubuntu18 => {
  298:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+bionic\s+main',
  299:                                         text   => "deb $loninst/ubuntu bionic main",
  300:                                        },
  301:                            ubuntu20 => {
  302:                                         regexp => '\s*deb\s+'.$loninst_re.'/ubuntu/?\s+focal\s+main',
  303:                                         text   => "deb $loninst/ubuntu focal main",
  304:                                        },
  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:                                        },
  313:                          );
  314:     my $apt_status;
  315:     if (defined($apt_get_source{$dist})) {
  316:         $apt_status = &update_apt_source($distname,$distver,$apt_get_source{$dist});
  317:     }
  318: }
  319: 
  320: my $mysqlfile = '/etc/my.cnf';
  321: my $mysqlconf = [{section =>'mysqld',
  322:                   key     =>'wait_timeout=',
  323:                   value   =>'31536000'}];
  324: my $nomysqlbackup;
  325: if ($dist =~ /^ubuntu(\d+)$/) {
  326:     my $version = $1;
  327:     $mysqlfile = '/etc/mysql/my.cnf';
  328:     if ($version > 14) {
  329:         $nomysqlbackup = 1;
  330:         $mysqlfile = '/etc/mysql/mysql.conf.d/mysqld.cnf';
  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:         }
  342:     }
  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:     }
  349: }
  350: 
  351: my $mysql_global_status = &update_file($mysqlfile,$mysqlconf,$nomysqlbackup);
  352: 
  353: my $local_my_cnf = '/home/www/.my.cnf';
  354: if (! -e $local_my_cnf) {
  355:     # Create a file so we can do something with it...
  356:     system("touch $local_my_cnf");
  357: }
  358: my $mysql_www_status =
  359:     &update_file($local_my_cnf,
  360:              [{section =>'client',
  361:                key     =>'user=',
  362:                value   =>'www',},
  363:               {section =>'client',
  364:                key     =>'password=',
  365:                value   =>$loncapa_config->{'lonSqlAccess'}},]);
  366: 
  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:     }
  376: } elsif ($dist =~ /^(?:redhat|oracle|alma|rocky|centos-stream)(\d+)$/) {
  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)) {
  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
  400:             close($fh);
  401:         } else {
  402:             warn "**** Error: could not open $bash_www_cnf to add 'set enable-bracketed-paste to off'";
  403:         }
  404:         my $wwwuid = getpwnam('www');
  405:         my $wwwgid = getgrnam('www');
  406:         if ($wwwuid!=$<) {
  407:             chown($wwwuid,$wwwgid,$bash_www_cnf);
  408:         }
  409:     } else {
  410:         my (%bracketed_paste_on,%bracketed_paste_off,@preserve,$condition);
  411:         $condition = '';
  412:         if (open(my $fh,'<',$bash_www_cnf)) {
  413:             while (my $line=<$fh>) {
  414:                 chomp($line);
  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:                 }
  426:                 if ($line =~ /^\s*set\s+enable\-bracketed\-paste\s+(off|on)\s*$/) {
  427:                     if ($1 eq 'off') {
  428:                         if ($condition ne '') {
  429:                             $bracketed_paste_off{$condition} = 1;
  430:                         } else {
  431:                             $bracketed_paste_off{all} = 1;
  432:                         }
  433:                         push(@preserve,$line);
  434:                     } else {
  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:                         }
  446:                     }
  447:                 } else {
  448:                     push(@preserve,$line);
  449:                 }
  450:             }
  451:             close($fh);
  452:         }
  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}))) {
  456:             if (open(my $fh,'>',$bash_www_cnf)) {
  457:                 if (@preserve) {
  458:                     foreach my $entry (@preserve) {
  459:                         print $fh "$entry\n";
  460:                     }
  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
  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: 
  494: my $exitvalue = 0;
  495: 
  496: if ($mysql_global_status) { $exitvalue = 1; }
  497: 
  498: exit $exitvalue;
  499: 
  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: 
  528: 
  529: sub update_file {
  530:     my ($file,$newdata,$nobackup) = @_;
  531:     return 1 if (! -e $file);
  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:         }
  538:     }
  539:     my ($filedata) = &parse_config_file($file);
  540:     if (! ref($filedata)) { warn "**** Error: $filedata"; return 0;}
  541:     my $modified = 0;
  542:     foreach my $data (@$newdata) {
  543:         my $section = $data->{'section'};
  544:         my $key = $data->{'key'};
  545:         my $value = $data->{'value'};
  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; }
  552:     }
  553:     return $modified;
  554: }
  555: 
  556: #################################################################
  557: #################################################################
  558: 
  559: =pod
  560: 
  561: =over 4
  562: 
  563: =item &parse_config_file()
  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: 
  571: =back 
  572: 
  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)) {
  590:                 chomp($line);
  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: 
  611: =over 4
  612: 
  613: =item &write_config_file()
  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: 
  622: =back
  623: 
  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:     }
  634:     open(OUTPUT,'>',$file) || return('Unable to open '.$file.' for writing');
  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: 
  665: =over 4
  666: 
  667: =item &modify_config_file()
  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: 
  679: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
  680: 
  681: =back 
  682: 
  683: =cut
  684: 
  685: #################################################################
  686: #################################################################
  687: sub modify_config_file {
  688:     my ($filedata,$section,$newkey,$newvalue)=@_;
  689:     my $modified = 0;    # returned value - set to true if the file is modified
  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/) {
  712:             if ($target->[$i] ne $newline) {
  713:                 $target->[$i]=$newline;
  714:                 $modified = 1;
  715:             }
  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.
  725:             if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
  726:                 $target->[-1] = $newline;
  727:                 $modified = 1;
  728:             } else {
  729:                 push(@$target,$newline);
  730:                 $modified = 1;
  731:             }
  732:         }
  733:     }
  734:     return $modified;
  735: }
  736: 
  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;
  777:     if (open($fh,'<',$file)) {
  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) {
  799:             if (open($fh,'>>',$file)) {
  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: }
  816: 
  817: #################################################################
  818: #################################################################
  819: 
  820: =pod
  821: 
  822: =over 4
  823: 
  824: =item &update_apt_source()
  825: 
  826: Modifies either the sources.list or sources.list.d/loncapa.list 
  827: file which include repositories used by apt-get.
  828: 
  829: Inputs:
  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.
  835: 
  836: Returns: 0 or 1, indicating if the file was modified(1) or not(0).
  837: 
  838: =back
  839: 
  840: =cut
  841: 
  842: #################################################################
  843: #################################################################
  844: sub update_apt_source {
  845:     my ($distname,$distver,$deb_row) = @_;
  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';
  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:     }
  855:     return 0 if (! -e $file);
  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:         }
  862:     }
  863:     my $result = 0;
  864:     my $fh;
  865:     if (open($fh,'<',$file)) {
  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) {
  876:             if (open($fh,'>>',$file)) {
  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>