Annotation of doc/install/linux/install.pl, revision 1.45.2.23

1.1       raeburn     1: #!/usr/bin/perl
                      2: # The LearningOnline Network 
                      3: # Pre-installation script for LON-CAPA
                      4: #
                      5: # Copyright Michigan State University Board of Trustees
                      6: #
                      7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                      8: #
                      9: # LON-CAPA is free software; you can redistribute it and/or modify
                     10: # it under the terms of the GNU General Public License as published by
                     11: # the Free Software Foundation; either version 2 of the License, or
                     12: # (at your option) any later version.
                     13: #
                     14: # LON-CAPA is distributed in the hope that it will be useful,
                     15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     17: # GNU General Public License for more details.
                     18: #
                     19: # You should have received a copy of the GNU General Public License
                     20: # along with LON-CAPA; if not, write to the Free Software
                     21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     22: #
                     23: # http://www.lon-capa.org/
                     24: #
                     25: 
                     26: use strict;
                     27: use File::Copy;
                     28: use Term::ReadKey;
                     29: use DBI;
1.45.2.11  raeburn    30: use File::Spec;
1.43      raeburn    31: use Cwd();
                     32: use File::Basename();
                     33: use lib File::Basename::dirname(Cwd::abs_path($0));
1.1       raeburn    34: use LCLocalization::localize;
                     35: 
                     36: # ========================================================= The language handle
                     37: 
                     38: my %languages = (
                     39:                   ar => 'Arabic', 
                     40:                   de => 'German',
                     41:                   en => 'English',
                     42:                   es => 'Spanish (Castellan)',
                     43:                   fa => 'Persian',
                     44:                   fr => 'French', 
                     45:                   he => 'Hebrew', 
                     46:                   ja => 'Japanese',
                     47:                   pt => 'Portuguese',
                     48:                   ru => 'Russian',
                     49:                   tr => 'Turkish',
                     50:                   zh => 'Chinese Simplified'
                     51:                ); 
                     52: 
                     53: use vars qw($lh $lang);
                     54: $lang = 'en';
                     55: if (@ARGV > 0) {
                     56:     foreach my $poss (keys(%languages)) {
                     57:         if ($ARGV[0] eq $poss) {
                     58:             $lang = $ARGV[0]; 
                     59:         }
                     60:     }
                     61: }
                     62: 
                     63: &get_language_handle($lang);
                     64: 
                     65: # Check user has root privs
                     66: if (0 != $<) {
                     67:     print &mt('This script must be run as root.')."\n".
                     68:           &mt('Stopping execution.')."\n";
                     69:     exit;
                     70: }
                     71: 
                     72: 
                     73: # Globals: filehandle LOG is global.
                     74: if (!open(LOG,">>loncapa_install.log")) {
                     75:     print &mt('Unable to open log file.')."\n".
                     76:           &mt('Stopping execution.')."\n";
                     77:     exit;
                     78: } else {
1.45.2.23! raeburn    79:     print LOG '$Id: install.pl,v 1.45.2.22 2024/08/01 12:57:23 raeburn Exp $'."\n";
1.1       raeburn    80: }
                     81: 
                     82: #
1.2       raeburn    83: # Helper routines and routines to establish recommended actions
1.1       raeburn    84: #
                     85: 
                     86: sub get_language_handle {
                     87:     my @languages = @_;
                     88:     $lh=LCLocalization::localize->get_handle(@languages);
                     89: }
                     90: 
                     91: sub mt (@) {
                     92:     if ($lh) {
                     93:         if ($_[0] eq '') {
                     94:             if (wantarray) {
                     95:                 return @_;
                     96:             } else {
                     97:                 return $_[0];
                     98:             }
                     99:         } else {
                    100:             return $lh->maketext(@_);
                    101:         }
                    102:     } else {
                    103:         if (wantarray) {
                    104:             return @_;
                    105:         } else {
                    106:             return $_[0];
                    107:         }
                    108:     }
                    109: }
                    110: 
                    111: sub texthash {
                    112:     my (%hash) = @_;
                    113:     foreach (keys(%hash)) {
                    114:         $hash{$_}=&mt($hash{$_});
                    115:     }
                    116:     return %hash;
                    117: }
                    118: 
                    119: 
                    120: sub skip_if_nonempty {
                    121:     my ($string,$error)=@_;
                    122:     return if (! defined($error));
                    123:     chomp($string);chomp($error);
                    124:     if ($string ne '') {
                    125:         print_and_log("$error\n".&mt('Stopping execution.')."\n");
                    126:         return 1;
                    127:     }
                    128:     return;
                    129: }
                    130: 
                    131: sub writelog {
                    132:     while ($_ = shift) {
                    133:         chomp();
                    134:         print LOG "$_\n";
                    135:     }
                    136: }
                    137: 
                    138: sub print_and_log {
                    139:     while ($_=shift) {
                    140:         chomp();
                    141:         print "$_\n";
                    142:         print LOG "$_\n";
                    143:     }
                    144: }
                    145: 
                    146: sub get_user_selection {
                    147:     my ($defaultrun) = @_;
                    148:     my $do_action = 0;
                    149:     my $choice = <STDIN>;
                    150:     chomp($choice);
                    151:     $choice =~ s/(^\s+|\s+$)//g;
                    152:     my $yes = &mt('y');
                    153:     if ($defaultrun) {
                    154:         if (($choice eq '') || ($choice =~ /^\Q$yes\E/i)) {
                    155:             $do_action = 1;
                    156:         }
                    157:     } else {
                    158:         if ($choice =~ /^\Q$yes\E/i) {
                    159:             $do_action = 1;
                    160:         }
                    161:     }
                    162:     return $do_action;
                    163: }
                    164: 
                    165: sub get_distro {
1.45.2.1  raeburn   166:     my ($distro,$gotprereqs,$updatecmd,$packagecmd,$installnow,$unknown);
1.1       raeburn   167:     $packagecmd = '/bin/rpm -q LONCAPA-prerequisites ';
1.45.2.3  raeburn   168:     if (-e '/etc/oracle-release') {
                    169:         open(IN,'</etc/oracle-release');
                    170:         my $versionstring=<IN>;
                    171:         chomp($versionstring);
                    172:         close(IN);
                    173:         if ($versionstring =~ /^Oracle Linux Server release (\d+)/) {
                    174:             my $version = $1;
                    175:             $distro = 'oracle'.$1;
                    176:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    177:             $installnow = 'yum -y install LONCAPA-prerequisites';
                    178:         }
                    179:     } elsif (-e '/etc/redhat-release') {
1.1       raeburn   180:         open(IN,'</etc/redhat-release');
                    181:         my $versionstring=<IN>;
                    182:         chomp($versionstring);
                    183:         close(IN);
                    184:         if ($versionstring =~ /^Red Hat Linux release ([\d\.]+) /) {
                    185:             my $version = $1;
                    186:             if ($version=~/^7\./) {
                    187:                 $distro='redhat7';
                    188:             } elsif ($version=~/^8\./) {
                    189:                 $distro='redhat8';
                    190:             } elsif ($version=~/^9/) {
                    191:                 $distro='redhat9';
                    192:             }
                    193:         } elsif ($versionstring =~ /Fedora( Core)? release ([\d\.]+) /) {
                    194:             my $version=$2;
                    195:             if ($version - int($version) > .9) {
                    196:                 $distro = 'fedora'.(int($version)+1);
                    197:             } else {
                    198:                 $distro = 'fedora'.int($version);
                    199:             }
                    200:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    201:             $installnow = 'yum -y install LONCAPA-prerequisites';
                    202:         } elsif ($versionstring =~ /Red Hat Enterprise Linux [AE]S release ([\d\.]+) /) {
                    203:             $distro = 'rhes'.$1;
                    204:             $updatecmd = 'up2date -i LONCAPA-prerequisites';
                    205:         } elsif ($versionstring =~ /Red Hat Enterprise Linux Server release (\d+)/) {
                    206:             $distro = 'rhes'.$1;
                    207:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    208:             $installnow = 'yum -y install LONCAPA-prerequisites';
1.45.2.3  raeburn   209:         } elsif ($versionstring =~ /Red Hat Enterprise Linux release (\d+)/) {
                    210:             $distro = 'rhes'.$1;
                    211:             $updatecmd = 'dnf install LONCAPA-prerequisites';
                    212:             $installnow = 'dnf -y install LONCAPA-prerequisites';
1.45.2.18  raeburn   213:         } elsif ($versionstring =~ /CentOS(| Linux| Stream) release (\d+)/) {
                    214:             $distro = 'centos'.$2;
                    215:             if ($1 eq ' Stream') {
                    216:                 $distro .= '-stream';
                    217:             }
1.1       raeburn   218:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    219:             $installnow = 'yum -y install LONCAPA-prerequisites';
1.22      raeburn   220:         } elsif ($versionstring =~ /Scientific Linux (?:SL )?release ([\d.]+) /) {
1.1       raeburn   221:             my $ver = $1;
                    222:             $ver =~ s/\.\d+$//;
                    223:             $distro = 'scientific'.$ver;
                    224:             $updatecmd = 'yum install LONCAPA-prerequisites';
                    225:             $installnow = 'yum -y install LONCAPA-prerequisites';
1.45.2.18  raeburn   226:         } elsif ($versionstring =~ /Rocky Linux release ([\d.]+)/) {
                    227:             my $ver = $1;
                    228:             $ver =~ s/\.\d+$//;
                    229:             $distro = 'rocky'.$ver;
                    230:             $updatecmd = 'dnf install LONCAPA-prerequisites';
                    231:             $installnow = 'dnf -y install LONCAPA-prerequisites';
                    232:         } elsif ($versionstring =~ /AlmaLinux release ([\d.]+) /) {
                    233:             my $ver = $1;
                    234:             $ver =~ s/\.\d+$//;
                    235:             $distro = 'alma'.$ver;
                    236:             $updatecmd = 'dnf install LONCAPA-prerequisites';
                    237:             $installnow = 'dnf -y install LONCAPA-prerequisites';
1.1       raeburn   238:         } else {
                    239:             print &mt('Unable to interpret [_1] to determine system type.',
                    240:                       '/etc/redhat-release')."\n";
1.45.2.1  raeburn   241:             $unknown = 1;
1.1       raeburn   242:         }
                    243:     } elsif (-e '/etc/SuSE-release') {
                    244:         open(IN,'</etc/SuSE-release');
                    245:         my $versionstring=<IN>;
                    246:         chomp($versionstring);
                    247:         close(IN);
                    248:         if ($versionstring =~ /^SUSE LINUX Enterprise Server ([\d\.]+) /i) {
                    249:             $distro='sles'.$1;
                    250:             if ($1 >= 10) {
                    251:                 $updatecmd = 'zypper install LONCAPA-prerequisites';
                    252:             } else {
                    253:                 $updatecmd = 'yast -i LONCAPA-prerequisites';
                    254:             }
                    255:         } elsif ($versionstring =~ /^SuSE Linux ([\d\.]+) /i) {
                    256:             $distro = 'suse'.$1;
1.12      raeburn   257:             $updatecmd = 'yast -i LONCAPA-prerequisites';
1.1       raeburn   258:         } elsif ($versionstring =~ /^openSUSE ([\d\.]+) /i) {
                    259:             $distro = 'suse'.$1;
                    260:             if ($1 >= 10.3 ) {
                    261:                 $updatecmd = 'zypper install LONCAPA-prerequisites';
                    262:             } else {
                    263:                 $updatecmd = 'yast -i LONCAPA-prerequisites';
                    264:             }
                    265:         } else {
                    266:             print &mt('Unable to interpret [_1] to determine system type.',
                    267:                       '/etc/SuSE-release')."\n";
1.45.2.1  raeburn   268:             $unknown = 1;
1.1       raeburn   269:         }
                    270:     } elsif (-e '/etc/issue') {
                    271:         open(IN,'</etc/issue');
                    272:         my $versionstring=<IN>;
                    273:         chomp($versionstring);
                    274:         close(IN);
                    275:         if ($versionstring =~ /^Ubuntu (\d+)\.\d+/i) {
                    276:             $distro = 'ubuntu'.$1;
                    277:             $updatecmd = 'sudo apt-get install loncapa-prerequisites';
                    278:         } elsif ($versionstring =~ /^Debian\s+GNU\/Linux\s+(\d+)\.\d+/i) {
                    279:             $distro = 'debian'.$1;
1.45.2.1  raeburn   280:             $updatecmd = 'apt-get install loncapa-prerequisites';
1.1       raeburn   281:         } elsif (-e '/etc/debian_version') {
                    282:             open(IN,'</etc/debian_version');
                    283:             my $version=<IN>;
                    284:             chomp($version);
                    285:             close(IN);
                    286:             if ($version =~ /^(\d+)\.\d+\.?\d*/) {
                    287:                 $distro='debian'.$1;
1.45.2.1  raeburn   288:                 $updatecmd = 'apt-get install loncapa-prerequisites';
1.1       raeburn   289:             } else {
                    290:                 print &mt('Unable to interpret [_1] to determine system type.',
                    291:                           '/etc/debian_version')."\n";
1.45.2.1  raeburn   292:                 $unknown = 1;
1.1       raeburn   293:             }
1.45.2.1  raeburn   294:         }
                    295:         if ($distro ne '') {
                    296:             $packagecmd = '/usr/bin/dpkg -l loncapa-prerequisites ';
1.1       raeburn   297:         }
                    298:     } elsif (-e '/etc/debian_version') {
                    299:         open(IN,'</etc/debian_version');
                    300:         my $version=<IN>;
                    301:         chomp($version);
                    302:         close(IN);
                    303:         if ($version =~  /^(\d+)\.\d+\.?\d*/) {
                    304:             $distro='debian'.$1;
                    305:             $packagecmd = '/usr/bin/dpkg -l loncapa-prerequisites ';
                    306:             $updatecmd = 'apt-get install loncapa-prerequisites';
                    307:         } else {
                    308:             print &mt('Unable to interpret [_1] to determine system type.',
                    309:                       '/etc/debian_version')."\n";
1.45.2.1  raeburn   310:             $unknown = 1;
                    311:         }
                    312:     }
                    313:     if (($distro eq '') && (!$unknown)) {
                    314:         if (-e '/etc/os-release') {
                    315:             if (open(IN,'<','/etc/os-release')) {
                    316:                 my ($id,$version);
                    317:                 while(<IN>) {
                    318:                     chomp();
                    319:                     if (/^ID="(\w+)"/) {
                    320:                         $id=$1;
                    321:                     } elsif (/^VERSION_ID="([\d\.]+)"/) {
                    322:                         $version=$1;
                    323:                     }
                    324:                 }
                    325:                 close(IN);
                    326:                 if ($id eq 'sles') {
                    327:                     my ($major,$minor) = split(/\./,$version);
                    328:                     if ($major =~ /^\d+$/) {
                    329:                         $distro = $id.$major;
                    330:                         $updatecmd = 'zypper install LONCAPA-prerequisites';
                    331:                     }
                    332:                 }
                    333:             }
                    334:             if ($distro eq '') {
                    335:                 print &mt('Unable to interpret [_1] to determine system type.',
                    336:                           '/etc/os-release')."\n";
                    337:                 $unknown = 1;
                    338:             }
                    339:         } else {
1.45.2.3  raeburn   340:             print &mt('Unknown installation: expecting a debian, ubuntu, suse, sles, redhat, fedora, scientific linux, or oracle linux system.')."\n";
1.1       raeburn   341:         }
                    342:     }
                    343:     return ($distro,$packagecmd,$updatecmd,$installnow);
                    344: }
                    345: 
                    346: sub check_prerequisites {
                    347:     my ($packagecmd,$distro) = @_;
                    348:     my $gotprereqs;
                    349:     if ($packagecmd ne '') {
                    350:         if (open(PIPE,"$packagecmd|")) {
                    351:             if ($distro =~ /^(debian|ubuntu)/) {
                    352:                 my @lines = <PIPE>;
                    353:                 chomp(@lines);
                    354:                 foreach my $line (@lines) {
                    355:                     if ($line =~ /^ii\s+loncapa-prerequisites\s+([\w\.]+)/) {
                    356:                         $gotprereqs = $1;
                    357:                     }
                    358:                 }
                    359:             } else {
                    360:                 my $line = <PIPE>;
                    361:                 chomp($line);
1.8       raeburn   362:                 if ($line =~ /^LONCAPA\-prerequisites\-([\d\-]+)\.(?:[.\w]+)$/) {
1.1       raeburn   363:                     $gotprereqs = $1;
                    364:                 }
                    365:             }
                    366:             close(PIPE);
                    367:         } else {
                    368:             print &mt('Error: could not determine if LONCAPA-prerequisites package is installed')."\n";
                    369:         }
                    370:     }
                    371:     return $gotprereqs;
                    372: }
                    373: 
1.6       raeburn   374: sub check_locale {
                    375:     my ($distro) = @_;
1.45.2.22  raeburn   376:     my ($fh,$langvar,$command,$langcmd,$earlyout,$default);
1.8       raeburn   377:     $langvar = 'LANG';
1.6       raeburn   378:     if ($distro =~ /^(ubuntu|debian)/) {
                    379:         if (!open($fh,"</etc/default/locale")) {
                    380:             print &mt('Failed to open: [_1], default locale not checked.',
                    381:                       '/etc/default/locale');
1.45.2.7  raeburn   382:             $earlyout = 1;
1.6       raeburn   383:         }
1.45.2.1  raeburn   384:     } elsif ($distro =~ /^(suse|sles)(\d+)/) {
                    385:         if (($1 eq 'sles') && ($2 >= 15)) {
                    386:             if (!open($fh,"</etc/locale.conf")) {
                    387:                 print &mt('Failed to open: [_1], default locale not checked.',
                    388:                           '/etc/locale.conf');
1.45.2.7  raeburn   389:                 $earlyout = 1;
1.45.2.1  raeburn   390:             }
                    391:         } else {
                    392:             if (!open($fh,"</etc/sysconfig/language")) {
                    393:                 print &mt('Failed to open: [_1], default locale not checked.',
                    394:                           '/etc/sysconfig/language');
1.45.2.7  raeburn   395:                 $earlyout = 1;
1.45.2.1  raeburn   396:             }
                    397:             $langvar = 'RC_LANG';
1.8       raeburn   398:         }
1.24      raeburn   399:     } elsif ($distro =~ /^fedora(\d+)/) {
                    400:         if ($1 >= 18) {
                    401:             if (!open($fh,"</etc/locale.conf")) {
                    402:                 print &mt('Failed to open: [_1], default locale not checked.',
                    403:                           '/etc/locale.conf');
1.45.2.7  raeburn   404:                 $earlyout = 1;
1.24      raeburn   405:             }
                    406:         } elsif (!open($fh,"</etc/sysconfig/i18n")) {
                    407:             print &mt('Failed to open: [_1], default locale not checked.',
                    408:                       '/etc/sysconfig/i18n');
1.45.2.7  raeburn   409:             $earlyout = 1;
1.24      raeburn   410:         }
1.45.2.18  raeburn   411:     } elsif ($distro =~ /^(?:rhes|centos|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn   412:         if ($1 >= 7) {
                    413:             if (!open($fh,"</etc/locale.conf")) {
                    414:                 print &mt('Failed to open: [_1], default locale not checked.',
                    415:                           '/etc/locale.conf');
1.45.2.7  raeburn   416:                 $earlyout = 1;
1.29      raeburn   417:             }
                    418:         } elsif (!open($fh,"</etc/sysconfig/i18n")) {
                    419:             print &mt('Failed to open: [_1], default locale not checked.',
                    420:                       '/etc/sysconfig/i18n');
1.45.2.7  raeburn   421:             $earlyout = 1;
1.29      raeburn   422:         }
1.6       raeburn   423:     } else {
                    424:         if (!open($fh,"</etc/sysconfig/i18n")) {
                    425:             print &mt('Failed to open: [_1], default locale not checked.',
                    426:                       '/etc/sysconfig/i18n');
1.45.2.7  raeburn   427:             $earlyout = 1;
1.6       raeburn   428:         }
                    429:     }
1.45.2.22  raeburn   430:     return () if ($earlyout);
1.6       raeburn   431:     my @data = <$fh>;
                    432:     chomp(@data);
1.45.2.22  raeburn   433:     close($fh);
1.6       raeburn   434:     foreach my $item (@data) {
1.25      raeburn   435:         if ($item =~ /^\Q$langvar\E=\"?([^\"]*)\"?/) {
1.45.2.22  raeburn   436:             $default = $1;
1.6       raeburn   437:             if ($default ne 'en_US.UTF-8') {
                    438:                 if ($distro =~ /^debian/) {
1.25      raeburn   439:                     $command = 'locale-gen en_US.UTF-8'."\n".
                    440:                                'update-locale LANG=en_US.UTF-8';
1.6       raeburn   441:                 } elsif ($distro =~ /^ubuntu/) {
1.25      raeburn   442:                     $command = 'sudo locale-gen en_US.UTF-8'."\n".
                    443:                                'sudo update-locale LANG=en_US.UTF-8';
1.7       raeburn   444:                 } elsif ($distro =~ /^(suse|sles)/) {
1.45.2.3  raeburn   445:                     $command = 'yast language';
                    446:                 } elsif (-e '/usr/bin/system-config-language') {
1.6       raeburn   447:                     $command = 'system-config-language';
1.45.2.3  raeburn   448:                 } elsif (-e '/usr/bin/localectl') {
1.45.2.4  raeburn   449:                     $command = '/usr/bin/localectl set-locale LANG=en_US.UTF-8';
1.45.2.3  raeburn   450:                 } else {
                    451:                     $command = 'No standard command found';
1.6       raeburn   452:                 }
                    453:             }
                    454:             last;
                    455:         }
                    456:     }
1.45.2.22  raeburn   457: # Check for locales
                    458:     if ($default ne 'en_US.UTF-8') {
                    459:         my ($has_us_english,$has_other_code,$has_other_lang);
                    460:         if (open(PIPE,"locale -a 2>/dev/null |")) {
                    461:             while (<PIPE>) {
                    462:                 chomp();
                    463:                 next if (/^(C(|\.utf8)|POSIX)$/i);
                    464:                 if (/^en_US\.utf8/i) {
                    465:                     $has_us_english = 1;
                    466:                 } elsif (/^[A-Za-z]{2}_[A-Za-z]{2}/) {
                    467:                     $has_other_code = 1;
                    468:                 } elsif (/^[A-Za-z]{3,}/) {
                    469:                     $has_other_lang = 1;
                    470:                 }
                    471:             }
                    472:             close(PIPE);
                    473:             if (!$has_us_english) {
                    474:                 if ($has_other_code || $has_other_lang) {
                    475:                     if ($distro =~ /^ubuntu/) {
                    476:                         $langcmd = "sudo apt-get install language-pack-en\n";
                    477:                     } elsif ($distro =~ /^debian/) {
                    478:                         $langcmd = "apt-get install language-pack-en\n";
                    479:                     } elsif ($distro =~ /^(suse|sles)/) {
                    480:                         $langcmd = &mt('Use yast: System > Language > Primary Language = English')."\n";
                    481:                     } elsif ($distro =~ /^fedora(\d+)$/) {
                    482:                         if ($1 > 23) {
                    483:                             $langcmd = "dnf install glibc-langpack-en\n";
                    484:                         } else {
                    485:                             $langcmd = "yum install glibc-common\n";
                    486:                         }
                    487:                     } elsif ($distro =~ /^(?:rhes|centos|scientific|oracle|rocky|alma)(\d+)/) {
                    488:                         if ($1 > 7) {
                    489:                             $langcmd = "dnf install glibc-langpack-en\n";
                    490:                         } else {
                    491:                             $langcmd = "yum install glibc-common\n";
                    492:                         }
                    493:                     }
                    494:                 } else {
                    495:                     if ($distro =~ /^ubuntu/) {
                    496:                         $langcmd = "sudo apt-get install language-pack-en\n";
                    497:                     } elsif ($distro =~ /^debian/) {
                    498:                         $langcmd = "apt-get install language-pack-en\n";
                    499:                     } elsif ($distro =~ /^(suse|sles)/) {
                    500:                         $langcmd = &mt('Use yast: System > Language > Primary Language = English')."\n";
                    501:                     } elsif ($distro =~ /^fedora(\d+)$/) {
                    502:                         if ($1 > 23) {
                    503:                             $langcmd = &mt('Either install all languages[_1]or install English only[_2]',
                    504:                                            ":\ndnf install glibc-all-langpacks\n\n",
                    505:                                            ":\ndnf install glibc-langpack-en\n");
                    506:                         } else {
                    507:                             $langcmd = "yum install glibc-common\n";
                    508:                         }
                    509:                     } elsif ($distro =~ /^(?:rhes|centos|scientific|oracle|rocky|alma)(\d+)/) {
                    510:                         if ($1 > 7) {
                    511:                             $langcmd = &mt('Either install all languages[_1]or install English only[_2]',
                    512:                                            ":\ndnf install glibc-all-langpacks\n\n",
                    513:                                            ":\ndnf install glibc-langpack-en\n");
                    514:                         } else {
                    515:                             $langcmd = "yum install glibc-common\n";
                    516:                         }
                    517:                     }
                    518:                 }
                    519:             }
                    520:         }
                    521:     }
                    522:     return ($command,$langcmd);
1.6       raeburn   523: }
                    524: 
1.1       raeburn   525: sub check_required {
                    526:     my ($instdir,$dsn) = @_;
                    527:     my ($distro,$packagecmd,$updatecmd,$installnow) = &get_distro();
                    528:     if ($distro eq '') {
                    529:         return;
                    530:     }
                    531:     my $gotprereqs = &check_prerequisites($packagecmd,$distro); 
                    532:     if ($gotprereqs eq '') {
1.45.2.22  raeburn   533:         return ($distro,$gotprereqs,'','',$packagecmd,$updatecmd);
1.6       raeburn   534:     }
1.45.2.22  raeburn   535:     my ($localecmd,$langcmd) = &check_locale($distro);
1.6       raeburn   536:     unless ($localecmd eq '') {
1.45.2.22  raeburn   537:         return ($distro,$gotprereqs,$localecmd,$langcmd);
1.1       raeburn   538:     }
1.45.2.9  raeburn   539:     my ($mysqlon,$mysqlsetup,$mysqlrestart,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,
                    540:         %recommended,$downloadstatus,$filetouse,$production,$testing,$apachefw,
1.45.2.12  raeburn   541:         $tostop,$uses_systemctl,$mysql_has_wwwuser);
1.1       raeburn   542:     my $wwwuid = &uid_of_www();
                    543:     my $wwwgid = getgrnam('www');
                    544:     if (($wwwuid eq '') || ($wwwgid eq '')) {
                    545:         $recommended{'wwwuser'} = 1;
                    546:     }
                    547:     unless( -e "/usr/local/sbin/pwauth") {
                    548:         $recommended{'pwauth'} = 1;
                    549:     }
                    550:     $mysqlon = &check_mysql_running($distro);
                    551:     if ($mysqlon) {
1.45.2.14  raeburn   552:         ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket) =
1.45.2.12  raeburn   553:             &check_mysql_setup($instdir,$dsn,$distro);
1.34      raeburn   554:         if ($mysqlsetup eq 'needsrestart') {
                    555:             $mysqlrestart = '';
                    556:             if ($distro eq 'ubuntu') {
1.45.2.19  raeburn   557:                 $mysqlrestart = 'sudo ';
1.34      raeburn   558:             }
                    559:             $mysqlrestart .= 'service mysql restart';
1.45.2.22  raeburn   560:             return ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart);
1.1       raeburn   561:         } else {
1.34      raeburn   562:             if ($mysqlsetup eq 'noroot') {
1.1       raeburn   563:                 $recommended{'mysqlperms'} = 1;
1.34      raeburn   564:             } else {
                    565:                 unless ($mysql_has_wwwuser) {
                    566:                     $recommended{'mysqlperms'} = 1;
                    567:                 }
                    568:             }
                    569:             if ($dbh) {
                    570:                 $has_lcdb = &check_loncapa_mysqldb($dbh);
                    571:             }
                    572:             unless ($has_lcdb) {
                    573:                 $recommended{'mysql'} = 1;
1.1       raeburn   574:             }
                    575:         }
                    576:     }
1.5       raeburn   577:     ($recommended{'firewall'},$apachefw) = &chkfirewall($distro);
1.35      raeburn   578:     ($recommended{'runlevels'},$tostop,$uses_systemctl) = &chkconfig($distro,$instdir);
1.45.2.20  raeburn   579:     if ((ref($uses_systemctl) eq 'HASH') && ($uses_systemctl->{'apache'})) {
                    580:         $recommended{'systemd'} = &check_systemd_security($distro);
                    581:     }
1.1       raeburn   582:     $recommended{'apache'} = &chkapache($distro,$instdir);
                    583:     $recommended{'stopsrvcs'} = &chksrvcs($distro,$tostop);
                    584:     ($recommended{'download'},$downloadstatus,$filetouse,$production,$testing) 
1.45.2.16  raeburn   585:         = &need_download($distro,$instdir);
1.45.2.22  raeburn   586:     return ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,
1.45.2.9  raeburn   587:             $mysqlrestart,\%recommended,$dbh,$has_pass,$mysql_unix_socket,
                    588:             $has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw,
                    589:             $uses_systemctl);
1.1       raeburn   590: }
                    591: 
                    592: sub check_mysql_running {
                    593:     my ($distro) = @_;
1.23      raeburn   594:     my $use_systemctl;
1.1       raeburn   595:     my $mysqldaemon ='mysqld';
                    596:     if ($distro =~ /^(suse|sles|debian|ubuntu)/) {
                    597:         $mysqldaemon = 'mysql';
                    598:     }
1.6       raeburn   599:     my $process = 'mysqld_safe';
                    600:     my $proc_owner = 'root';
                    601:     if ($distro =~ /^ubuntu(\w+)/) {
                    602:         if ($1 >= 10) {
                    603:             $process = 'mysqld';
                    604:             $proc_owner = 'mysql';
                    605:         }
1.45.2.20  raeburn   606:         if ($1 >= 16) {
                    607:             $use_systemctl = 1;
                    608:         }
1.45.2.19  raeburn   609:     } elsif ($distro =~ /^debian(\w+)/) {
                    610:         if ($1 >= 10) {
                    611:             $process = 'mysql';
                    612:             $proc_owner = 'mysql';
                    613:         }
                    614:         if ($1 >= 11) {
                    615:             $mysqldaemon = 'mariadb';
                    616:         }
1.45.2.20  raeburn   617:         if ($1 >= 9) {
                    618:             $use_systemctl = 1;
                    619:         }
1.35      raeburn   620:     } elsif ($distro =~ /^fedora(\d+)/) {
1.23      raeburn   621:         if ($1 >= 16) {
                    622:             $process = 'mysqld';
                    623:             $proc_owner = 'mysql';
                    624:             $use_systemctl = 1;
                    625:         }
1.39      raeburn   626:         if ($1 >= 19) {
1.37      raeburn   627:             $mysqldaemon ='mariadb';
                    628:         }
1.45.2.17  raeburn   629:         if ($1 >= 34) {
                    630:             $process = 'mariadb';
                    631:         }
1.45.2.18  raeburn   632:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn   633:         if ($1 >= 7) {
                    634:             $mysqldaemon ='mariadb';
                    635:             $process = 'mysqld';
                    636:             $proc_owner = 'mysql';
                    637:             $use_systemctl = 1;
                    638:         }
1.45.2.19  raeburn   639:         if ($1 >= 9) {
                    640:             $process = 'mariadb';
                    641:         }
1.35      raeburn   642:     } elsif ($distro =~ /^sles(\d+)/) {
                    643:         if ($1 >= 12) {
                    644:             $use_systemctl = 1;
1.42      raeburn   645:             $proc_owner = 'mysql';
                    646:             $process = 'mysqld';
1.35      raeburn   647:         }
1.45.2.23! raeburn   648:         if ($1 >= 12) {
1.45.2.1  raeburn   649:             $mysqldaemon ='mariadb';
                    650:         }
1.35      raeburn   651:     } elsif ($distro =~ /^suse(\d+)/) {
                    652:         if ($1 >= 13) {
                    653:             $use_systemctl = 1;
                    654:         }
1.29      raeburn   655:     }
1.35      raeburn   656:     if (open(PIPE,"ps -ef |grep $process |grep ^$proc_owner |grep -v grep 2>&1 |")) {
1.1       raeburn   657:         my $status = <PIPE>;
                    658:         close(PIPE);
                    659:         chomp($status);
1.6       raeburn   660:         if ($status =~ /^\Q$proc_owner\E\s+\d+\s+/) {
1.1       raeburn   661:             print_and_log(&mt('MySQL is running.')."\n");
                    662:             return 1;
                    663:         } else {
1.23      raeburn   664:             if ($use_systemctl) {
                    665:                 system("/bin/systemctl start $mysqldaemon.service >/dev/null 2>&1 ");
                    666:             } else {
                    667:                 system("/etc/init.d/$mysqldaemon start >/dev/null 2>&1 ");
                    668:             }
1.1       raeburn   669:             print_and_log(&mt('Waiting for MySQL to start.')."\n");
                    670:             sleep 5;
1.12      raeburn   671:             if (open(PIPE,"ps -ef |grep $process |grep -v grep 2>&1 |")) {
                    672:                 $status = <PIPE>;
1.1       raeburn   673:                 close(PIPE);
                    674:                 chomp($status);
1.12      raeburn   675:                 if ($status =~ /^\Q$proc_owner\E\s+\d+\s+/) {
1.1       raeburn   676:                     print_and_log(&mt('MySQL is running.')."\n");
                    677:                     return 1;
                    678:                 } else {
1.12      raeburn   679:                     print_and_log(&mt('Still waiting for MySQL to start.')."\n");
                    680:                     sleep 5;
                    681:                     if (open(PIPE,"ps -ef |grep $process |grep -v grep 2>&1 |")) {
                    682:                         $status = <PIPE>;
                    683:                         close(PIPE);
                    684:                         chomp($status);
                    685:                         if ($status =~ /^\Q$proc_owner\E\s+\d+\s+/) {
                    686:                             print_and_log(&mt('MySQL is running.')."\n");
                    687:                             return 1;
                    688:                         } else {
                    689:                             print_and_log(&mt('Given up waiting for MySQL to start.')."\n"); 
                    690:                         }
                    691:                     }
1.1       raeburn   692:                 }
                    693:             }
                    694:         }
                    695:     } else {
                    696:         print &mt('Could not determine if MySQL is running.')."\n";
                    697:     }
                    698:     return;
                    699: }
                    700: 
                    701: sub chkconfig {
1.8       raeburn   702:     my ($distro,$instdir) = @_;
1.23      raeburn   703:     my (%needfix,%tostop,%uses_systemctl);
1.1       raeburn   704:     my $checker_bin = '/sbin/chkconfig';
1.23      raeburn   705:     my $sysctl_bin = '/bin/systemctl';
1.6       raeburn   706:     my %daemon = (
                    707:                   mysql     => 'mysqld',
                    708:                   apache    => 'httpd',
                    709:                   cups      => 'cups',
                    710:                   ntp       => 'ntpd',
                    711:                   memcached => 'memcached',
                    712:     );
1.1       raeburn   713:     my @runlevels = qw/3 4 5/;
                    714:     my @norunlevels = qw/0 1 6/;
                    715:     if ($distro =~ /^(suse|sles)/) {
                    716:         @runlevels = qw/3 5/;
                    717:         @norunlevels = qw/0 2 1 6/;
1.6       raeburn   718:         $daemon{'mysql'} = 'mysql';
                    719:         $daemon{'apache'} = 'apache2';
1.8       raeburn   720:         $daemon{'ntp'}    = 'ntp';
1.1       raeburn   721:         if ($distro =~ /^(suse|sles)9/) {
1.6       raeburn   722:             $daemon{'apache'} = 'apache';
1.1       raeburn   723:         }
1.35      raeburn   724:         if ($distro =~ /^(suse|sles)([\d\.]+)/) {
                    725:             my $name = $1;
                    726:             my $num = $2;
                    727:             if ($num > 11) {
1.26      raeburn   728:                 $uses_systemctl{'apache'} = 1;
1.35      raeburn   729:                 if (($name eq 'sles') || ($name eq 'suse' && $num >= 13.2)) {
                    730:                     $uses_systemctl{'mysql'} = 1;
                    731:                     $uses_systemctl{'ntp'} = 1;
                    732:                     $uses_systemctl{'cups'} = 1;
                    733:                     $uses_systemctl{'memcached'} = 1;
1.45.2.23! raeburn   734:                     if ($name eq 'sles') {
        !           735:                         if ($num >= 12) {
        !           736:                             $daemon{'mysql'} = 'mariadb';
        !           737:                         }
        !           738:                         if ($num >= 15) {
        !           739:                             $daemon{'ntp'} = 'chronyd';
        !           740:                         } else {
        !           741:                             $daemon{'ntp'} = 'ntpd';
        !           742:                         }
1.45.2.1  raeburn   743:                     } else {
                    744:                         $daemon{'ntp'} = 'ntpd';
                    745:                     }
1.35      raeburn   746:                 }
1.26      raeburn   747:             }
                    748:         }
1.6       raeburn   749:     } elsif ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                    750:         my $version = $1;
1.1       raeburn   751:         @runlevels = qw/2 3 4 5/;
                    752:         @norunlevels = qw/0 1 6/;
1.44      raeburn   753:         if (($distro =~ /^ubuntu/) && ($version <= 16)) {
                    754:             $checker_bin = '/usr/sbin/sysv-rc-conf';
                    755:         } else {
                    756:             $uses_systemctl{'ntp'} = 1;
                    757:             $uses_systemctl{'mysql'} = 1;
                    758:             $uses_systemctl{'apache'} = 1;
                    759:             $uses_systemctl{'memcached'} = 1;
                    760:             $uses_systemctl{'cups'} = 1;
                    761:         }
1.6       raeburn   762:         $daemon{'mysql'}  = 'mysql';
                    763:         $daemon{'apache'} = 'apache2';
                    764:         $daemon{'ntp'}    = 'ntp';
                    765:         if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                    766:             $daemon{'cups'} = 'cupsys';
                    767:         }
1.45.2.19  raeburn   768:         if ((($distro =~ /^ubuntu/) && ($version >= 18)) ||
                    769:             (($distro  =~ /^debian/) && ($version >= 10))) {
1.45.2.6  raeburn   770:             $daemon{'ntp'}    = 'chrony';
                    771:         }
1.45.2.23! raeburn   772:         if (($distro  =~ /^debian/) && ($version >= 10)) {
1.45.2.19  raeburn   773:             $daemon{'mysql'} = 'mariadb';
                    774:         }
1.26      raeburn   775:     } elsif ($distro =~ /^fedora(\d+)/) {
1.23      raeburn   776:         my $version = $1;
                    777:         if ($version >= 15) {
                    778:             $uses_systemctl{'ntp'} = 1;
                    779:         }
                    780:         if ($version >= 16) {
                    781:             $uses_systemctl{'mysql'} = 1;
                    782:             $uses_systemctl{'apache'} = 1;
1.35      raeburn   783:             $uses_systemctl{'memcached'} = 1;
                    784:             $uses_systemctl{'cups'} = 1;
1.23      raeburn   785:         }
1.39      raeburn   786:         if ($version >= 19) {
1.37      raeburn   787:             $daemon{'mysql'} = 'mariadb';
                    788:         }
1.45.2.5  raeburn   789:         if ($version >= 26) {
                    790:             $daemon{'ntp'} = 'chronyd';
                    791:         }
1.45.2.18  raeburn   792:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn   793:         my $version = $1;
                    794:         if ($version >= 7) {
                    795:             $uses_systemctl{'ntp'} = 1;
                    796:             $uses_systemctl{'mysql'} = 1;
                    797:             $uses_systemctl{'apache'} = 1;
1.35      raeburn   798:             $uses_systemctl{'memcached'} = 1;
                    799:             $uses_systemctl{'cups'} = 1;
1.30      raeburn   800:             $daemon{'mysql'} = 'mariadb';
1.29      raeburn   801:         }
1.45.2.3  raeburn   802:         if (($version >= 8) || ($distro eq 'oracle7')) {
                    803:             $daemon{'ntp'} = 'chronyd';
                    804:         }
1.1       raeburn   805:     }
1.23      raeburn   806:     my $nocheck;
1.1       raeburn   807:     if (! -x $checker_bin) {
1.23      raeburn   808:         if ($uses_systemctl{'mysql'} && $uses_systemctl{'apache'}) {
                    809:             if (! -x $sysctl_bin) {
                    810:                 $nocheck = 1;       
                    811:             }
                    812:         } else {
                    813:             $nocheck = 1;
                    814:         }
                    815:     }
                    816:     if ($nocheck) {
1.6       raeburn   817:         print &mt('Could not check runlevel status for MySQL or Apache')."\n";
1.1       raeburn   818:         return;
                    819:     }
                    820:     my $rlstr = join('',@runlevels);
                    821:     my $nrlstr = join('',@norunlevels);
1.23      raeburn   822: 
1.6       raeburn   823:     foreach my $type ('apache','mysql','ntp','cups','memcached') {
                    824:         my $service = $daemon{$type};
1.23      raeburn   825:         if ($uses_systemctl{$type}) {
1.35      raeburn   826:             if (($type eq 'memcached') || ($type eq 'cups')) {
                    827:                 if (-l "/etc/systemd/system/multi-user.target.wants/$service.service") {
                    828:                     $tostop{$type} = 1;
                    829:                 }
                    830:             } else {
                    831:                 if (!-l "/etc/systemd/system/multi-user.target.wants/$service.service") {
                    832:                     $needfix{$type} = "systemctl enable $service.service";
                    833:                 }
1.23      raeburn   834:             }
                    835:         } else {
                    836:             my $command = $checker_bin.' --list '.$service.' 2>/dev/null';
1.35      raeburn   837:             if ($type eq 'cups') {
1.23      raeburn   838:                 if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                    839:                     my $version = $1;
                    840:                     if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                    841:                         $command = $checker_bin.' --list cupsys 2>/dev/null';
1.19      raeburn   842:                     }
                    843:                 }
                    844:             }
1.23      raeburn   845:             my $results = `$command`;
                    846:             my $tofix;
                    847:             if ($results eq '') {
                    848:                 if (($type eq 'apache') || ($type eq 'mysql') || ($type eq 'ntp')) {
                    849:                     if ($distro  =~ /^(debian|ubuntu)/) {
                    850:                         $tofix = "update-rc.d $type defaults";
                    851:                     } else {
                    852:                         $tofix = "$checker_bin --add $service\n";
                    853:                     }
1.6       raeburn   854:                 }
1.23      raeburn   855:             } else {
                    856:                 my %curr_runlevels;
                    857:                 for (my $rl=0; $rl<=6; $rl++) {
                    858:                     if ($results =~ /$rl:on/) { $curr_runlevels{$rl}++; }
                    859:                 }
                    860:                 if (($type eq 'apache') || ($type eq 'mysql') || ($type eq 'ntp')) {
                    861:                     my $warning;
                    862:                     foreach my $rl (@runlevels) {
                    863:                         if (!exists($curr_runlevels{$rl})) {
                    864:                             $warning = 1;
                    865:                         }
                    866:                     }
                    867:                     if ($warning) {
                    868:                         $tofix = "$checker_bin --level $rlstr $service on\n";
                    869:                     }
                    870:                 } elsif (keys(%curr_runlevels) > 0) {
                    871:                     $tostop{$type} = 1;
1.1       raeburn   872:                 }
                    873:             }
1.23      raeburn   874:             if ($tofix) {
                    875:                 $needfix{$type} = $tofix;
1.1       raeburn   876:             }
1.5       raeburn   877:         }
1.1       raeburn   878:     }
                    879:     if ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                    880:         my $name = $1;
                    881:         my $version = $2;
                    882:         my ($major,$minor);
                    883:         if ($name eq 'suse') {
                    884:             ($major,$minor) = split(/\./,$version);
                    885:         } else {
                    886:             $major = $version;
                    887:         }
1.45.2.1  raeburn   888:         if (($major > 10) && ($major <= 13)) {
1.8       raeburn   889:             if (&check_SuSEfirewall2_setup($instdir)) {
                    890:                 $needfix{'insserv'} = 1;
                    891:             }
1.1       raeburn   892:         }
                    893:     }
1.35      raeburn   894:     return (\%needfix,\%tostop,\%uses_systemctl);
1.1       raeburn   895: }
                    896: 
1.45.2.20  raeburn   897: sub check_systemd_security {
                    898:     my ($distro) = @_;
                    899:     my $service = 'httpd.service';
                    900:     if ($distro =~ /^(suse|sles|ubuntu|debian)/) {
                    901:         $service = 'apache2.service';
                    902:     }
                    903:     system("systemctl daemon-reload");
                    904:     if (open(PIPE,"systemctl show $service --property=ProtectHome 2>/dev/null |")) {
                    905:         my $protection = <PIPE>;
                    906:         close(PIPE);
                    907:         chomp($protection);
                    908:         if ($protection =~ /^ProtectHome=(read-only|yes)$/i) {
                    909:             return 1;
                    910:         }
                    911:     } else {
                    912:          print &mt('Could not check systemctl configuration for Apache')."\n";
                    913:     }
                    914:     return 0;
                    915: }
                    916: 
1.45.2.1  raeburn   917: sub uses_firewalld {
                    918:     my ($distro) = @_;
1.45.2.3  raeburn   919:     my ($inuse,$checkfirewalld,$zone);
1.45.2.1  raeburn   920:     if ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                    921:         if (($1 eq 'sles') && ($2 >= 15)) {
                    922:             $checkfirewalld = 1;
                    923:         }
                    924:     } elsif ($distro =~ /^fedora(\d+)$/) {
                    925:         if ($1 >= 18) {
                    926:             $checkfirewalld = 1;
                    927:         }
1.45.2.18  raeburn   928:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.45.2.1  raeburn   929:         if ($1 >= 7) {
                    930:             $checkfirewalld = 1;
                    931:         }
                    932:     }
                    933:     if ($checkfirewalld) {
                    934:         my ($loaded,$active);
1.45.2.15  raeburn   935:         if (open(PIPE,"systemctl status firewalld 2>/dev/null |")) {
1.45.2.1  raeburn   936:             while (<PIPE>) {
                    937:                 chomp();
                    938:                 if (/^\s*Loaded:\s+(\w+)/) {
                    939:                     $loaded = $1;
                    940:                 }
1.45.2.15  raeburn   941:                 if (/^\s*Active:\s+(\w+)/) {
1.45.2.1  raeburn   942:                     $active = $1;
                    943:                 }
                    944:             }
                    945:             close(PIPE);
                    946:         }
                    947:         if (($loaded eq 'loaded') || ($active eq 'active')) {
                    948:             $inuse = 1;
1.45.2.3  raeburn   949:             my $cmd = 'firewall-cmd --get-default-zone';
                    950:             if (open(PIPE,"$cmd |")) {
                    951:                 my $result = <PIPE>;
                    952:                 chomp($result);
                    953:                 close(PIPE);
                    954:                 if ($result =~ /^\w+$/) {
                    955:                     $zone = $result;
                    956:                 }
                    957:             }
1.45.2.1  raeburn   958:         }
                    959:     }
1.45.2.3  raeburn   960:     return ($inuse,$zone);
1.45.2.1  raeburn   961: }
                    962: 
1.1       raeburn   963: sub chkfirewall {
1.5       raeburn   964:     my ($distro) = @_;
1.1       raeburn   965:     my $configfirewall = 1;
                    966:     my %ports = (
                    967:                     http  =>  80,
                    968:                     https => 443,
                    969:                 );
1.5       raeburn   970:     my %activefw;
1.45.2.3  raeburn   971:     my ($firewalld,$zone) = &uses_firewalld($distro);
                    972:     if ($firewalld) {
                    973:         my %current;
                    974:         if (open(PIPE,'firewall-cmd --permanent --zone='.$zone.' --list-services |')) {
                    975:             my $svc = <PIPE>;
                    976:             close(PIPE);
                    977:             chomp($svc);
                    978:             map { $current{$_} = 1; } (split(/\s+/,$svc));
                    979:         }
                    980:         if ($current{'http'} && $current{'https'}) {
                    981:             $configfirewall = 0;
                    982:         }
                    983:     } else {
                    984:         if (&firewall_is_active()) {
1.45.2.1  raeburn   985:             my $iptables = &get_pathto_iptables();
                    986:             if ($iptables eq '') {
                    987:                 print &mt('Firewall not checked as path to iptables not determined.')."\n";
                    988:             } else {
                    989:                 my @fwchains = &get_fw_chains($iptables,$distro);
                    990:                 if (@fwchains) {
                    991:                     foreach my $service ('http','https') {
                    992:                         foreach my $fwchain (@fwchains) {
                    993:                             if (&firewall_is_port_open($iptables,$fwchain,$ports{$service})) {
                    994:                                 $activefw{$service} = 1;
                    995:                                 last;
                    996:                             }
1.1       raeburn   997:                         }
                    998:                     }
1.45.2.1  raeburn   999:                     if ($activefw{'http'}) {
                   1000:                         $configfirewall = 0;
                   1001:                     }
                   1002:                 } else {
                   1003:                     print &mt('Firewall not checked as iptables Chains not identified.')."\n";
1.1       raeburn  1004:                 }
                   1005:             }
1.45.2.3  raeburn  1006:         } else {
                   1007:             print &mt('Firewall not enabled.')."\n";
1.1       raeburn  1008:         }
                   1009:     }
1.5       raeburn  1010:     return ($configfirewall,\%activefw);
1.1       raeburn  1011: }
                   1012: 
                   1013: sub chkapache {
                   1014:     my ($distro,$instdir) = @_;
                   1015:     my $fixapache = 1;
1.28      raeburn  1016:     if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
                   1017:         my $distname = $1;
                   1018:         my $version = $2;
1.33      raeburn  1019:         my ($stdconf,$stdsite);
1.45.2.19  raeburn  1020:         if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   1021:             (($distname eq 'debian') && ($version >= 10))) {
1.33      raeburn  1022:             $stdconf = "$instdir/debian-ubuntu/ubuntu14/loncapa_conf";
                   1023:             $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_sites";
                   1024:         } else {
                   1025:             $stdconf = "$instdir/debian-ubuntu/loncapa"; 
                   1026:         }
                   1027:         if (!-e $stdconf) {
1.1       raeburn  1028:             $fixapache = 0;
                   1029:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n"; 
1.28      raeburn  1030:         } else {
1.33      raeburn  1031:             my ($configfile,$sitefile);
1.45.2.19  raeburn  1032:             if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   1033:                 (($distname eq 'debian') && ($version >= 10))) {
1.45.2.10  raeburn  1034:                 $sitefile = '/etc/apache2/sites-available/loncapa.conf';
                   1035:                 $configfile = '/etc/apache2/conf-available/loncapa.conf';
1.33      raeburn  1036:             } else {
1.45.2.10  raeburn  1037:                 $configfile = '/etc/apache2/sites-available/loncapa';
1.28      raeburn  1038:             }
1.33      raeburn  1039:             if (($configfile ne '') && (-e $configfile) && (-e $stdconf))  {
                   1040:                 if (open(PIPE, "diff --brief $stdconf $configfile |")) {
1.28      raeburn  1041:                     my $diffres = <PIPE>;
                   1042:                     close(PIPE);
                   1043:                     chomp($diffres);
                   1044:                     unless ($diffres) {
                   1045:                         $fixapache = 0;
                   1046:                     }
1.1       raeburn  1047:                 }
                   1048:             }
1.45.2.19  raeburn  1049:             if ((!$fixapache) && ((($distname eq 'ubuntu') && ($version > 12)) ||
                   1050:                                   (($distname eq 'debian') && ($version >= 10))))  {
1.33      raeburn  1051:                 if (($sitefile ne '') && (-e $sitefile) && (-e $stdsite)) {
                   1052:                     if (open(PIPE, "diff --brief $stdsite $sitefile |")) {
                   1053:                         my $diffres = <PIPE>;
                   1054:                         close(PIPE);
                   1055:                         chomp($diffres);
1.45.2.20  raeburn  1056:                         if ($diffres) {
                   1057:                             $fixapache = 1;
                   1058:                         } else {
1.33      raeburn  1059:                             $fixapache = 0;
                   1060:                         }
                   1061:                     }
                   1062:                 }
                   1063:             }
1.1       raeburn  1064:         }
1.6       raeburn  1065:         if (!$fixapache) {
                   1066:             foreach my $module ('headers.load','expires.load') {
                   1067:                 unless (-l "/etc/apache2/mods-enabled/$module") {
                   1068:                     $fixapache = 1;
                   1069:                 }
                   1070:             }
                   1071:         }
1.45.2.19  raeburn  1072:         if ((!$fixapache) && (($distname eq 'ubuntu') || ($distname eq 'debian'))) {
1.45.2.7  raeburn  1073:             my $sitestatus = "/etc/apache2/mods-available/status.conf";
                   1074:             my $stdstatus = "$instdir/debian-ubuntu/status.conf";
                   1075:             if ((-e $stdstatus) && (-e $sitestatus)) {
                   1076:                 if (open(PIPE, "diff --brief $stdstatus $sitestatus |")) {
                   1077:                     my $diffres = <PIPE>;
                   1078:                     close(PIPE);
                   1079:                     chomp($diffres);
                   1080:                     if ($diffres) {
                   1081:                         $fixapache = 1;
                   1082:                     }
                   1083:                 }
                   1084:             }
                   1085:         }
1.45.2.1  raeburn  1086:     } elsif ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                   1087:         my ($name,$version) = ($1,$2);
1.1       raeburn  1088:         my $apache = 'apache';
1.45.2.1  raeburn  1089:         my $conf_file = "$instdir/sles-suse/default-server.conf";
                   1090:         if ($version >= 10) {
1.8       raeburn  1091:             $apache = 'apache2';
1.1       raeburn  1092:         }
1.45.2.1  raeburn  1093:         if (($name eq 'sles') && ($version >= 12)) {
                   1094:             $conf_file = "$instdir/sles-suse/apache2.4/default-server.conf";
                   1095:         }
                   1096:         if (!-e $conf_file) {
1.1       raeburn  1097:             $fixapache = 0;
                   1098:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
1.45.2.1  raeburn  1099:         } elsif (-e "/etc/$apache/default-server.conf") {
                   1100:             if (open(PIPE, "diff --brief $conf_file /etc/$apache/default-server.conf |")) {
1.9       raeburn  1101:                 my $diffres = <PIPE>;
                   1102:                 close(PIPE);
                   1103:                 chomp($diffres);
                   1104:                 unless ($diffres) {
                   1105:                     $fixapache = 0;
                   1106:                 }
                   1107:             }
                   1108:         }
                   1109:     } elsif ($distro eq 'rhes4') {
                   1110:         if (!-e "$instdir/rhes4/httpd.conf") {
                   1111:             $fixapache = 0;
                   1112:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
                   1113:         } elsif ((-e "/etc/httpd/conf/httpd.conf") && (-e "$instdir/rhes4/httpd.conf")) {
                   1114:             if (open(PIPE, "diff --brief $instdir/rhes4/httpd.conf /etc/httpd/conf/httpd.conf |")) {
1.1       raeburn  1115:                 my $diffres = <PIPE>;
                   1116:                 close(PIPE);
                   1117:                 chomp($diffres);
                   1118:                 unless ($diffres) {
                   1119:                     $fixapache = 0;
                   1120:                 }
                   1121:             }
                   1122:         }
                   1123:     } else {
1.14      raeburn  1124:         my $configfile = 'httpd.conf';
1.45.2.5  raeburn  1125:         my $mpmfile = 'mpm.conf';
1.45.2.18  raeburn  1126:         if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn  1127:             if ($1 >= 7) {
                   1128:                 $configfile = 'apache2.4/httpd.conf';
                   1129:             } elsif ($1 > 5) {
1.14      raeburn  1130:                 $configfile = 'new/httpd.conf';
                   1131:             }
                   1132:         } elsif ($distro =~ /^fedora(\d+)$/) {
1.29      raeburn  1133:             if ($1 > 17) {
1.45.2.5  raeburn  1134:                 $configfile = 'apache2.4/httpd.conf';
1.29      raeburn  1135:             } elsif ($1 > 10) {
1.15      raeburn  1136:                 $configfile = 'new/httpd.conf';
1.14      raeburn  1137:             }
                   1138:         }
                   1139:         if (!-e "$instdir/centos-rhes-fedora-sl/$configfile") {
1.1       raeburn  1140:             $fixapache = 0;
                   1141:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
1.14      raeburn  1142:         } elsif ((-e "/etc/httpd/conf/httpd.conf") && (-e "$instdir/centos-rhes-fedora-sl/$configfile")) {
                   1143:             if (open(PIPE, "diff --brief $instdir/centos-rhes-fedora-sl/$configfile /etc/httpd/conf/httpd.conf |")) {
1.1       raeburn  1144:                 my $diffres = <PIPE>;
                   1145:                 close(PIPE);
                   1146:                 chomp($diffres);
                   1147:                 unless ($diffres) {
                   1148:                     $fixapache = 0;
                   1149:                 }
                   1150:             }
                   1151:         }
1.45.2.5  raeburn  1152:         if (-e "/etc/httpd/conf.modules.d/00-mpm.conf") {
                   1153:             if (!-e "$instdir/centos-rhes-fedora-sl/$mpmfile") {
                   1154:                 print &mt('Warning: No LON-CAPA Apache MPM configuration file found for installation check.')."\n";
                   1155:             } elsif ((-e "/etc/httpd/conf.modules.d/00-mpm.conf") && (-e "$instdir/centos-rhes-fedora-sl/$mpmfile")) {
                   1156:                 if (open(PIPE, "diff --brief $instdir/centos-rhes-fedora-sl/$mpmfile /etc/httpd/conf.modules.d/00-mpm.conf |")) {
                   1157:                     my $diffres = <PIPE>;
                   1158:                     close(PIPE);
                   1159:                     chomp($diffres);
                   1160:                     if ($diffres) {
                   1161:                         $fixapache = 1;
                   1162:                     }
                   1163:                 }
                   1164:             }
                   1165:         }
1.1       raeburn  1166:     }
                   1167:     return $fixapache;
                   1168: }
                   1169: 
                   1170: sub chksrvcs {
                   1171:     my ($distro,$tostop) = @_;
                   1172:     my %stopsrvcs;
                   1173:     if (ref($tostop) eq 'HASH') {
                   1174:         %stopsrvcs = %{$tostop};
                   1175:     }
1.6       raeburn  1176:     foreach my $service ('cups','memcached') {
1.1       raeburn  1177:         next if (exists($stopsrvcs{$service}));
                   1178:         my $daemon = $service;
                   1179:         if ($service eq 'cups') {
                   1180:             $daemon = 'cupsd';
                   1181:         }
                   1182:         my $cmd = "ps -ef |grep '$daemon' |grep -v grep";
                   1183:         if (open(PIPE,'-|',$cmd)) {
                   1184:             my $daemonrunning = <PIPE>;
                   1185:             chomp($daemonrunning);
                   1186:             close(PIPE);
                   1187:             if ($daemonrunning) {
1.12      raeburn  1188:                 if ($service eq 'memcached') {
1.16      raeburn  1189:                     my $cmd = '/usr/bin/memcached';
                   1190:                     if ($distro =~ /^(suse|sles)/) {
                   1191:                         $cmd = '/usr/sbin/memcached';
                   1192:                     }
1.12      raeburn  1193:                     unless ($daemonrunning =~ m{^www[^/]+\Q$cmd -m 400 -v\E$}) {
1.10      raeburn  1194:                         $stopsrvcs{$service} = 1;
                   1195:                     }
                   1196:                 } else {
                   1197:                     $stopsrvcs{$service} = 1;
                   1198:                 }
1.1       raeburn  1199:             }
                   1200:         }
1.10      raeburn  1201:     }
1.1       raeburn  1202:     return \%stopsrvcs;
                   1203: }
                   1204: 
                   1205: sub need_download {
1.45.2.16  raeburn  1206:     my ($distro,$instdir) = @_;
1.1       raeburn  1207:     my $needs_download = 1;
                   1208:     my ($production,$testing,$stdsizes) = &download_versionslist();
1.45.2.16  raeburn  1209:     my ($localcurrent,$localtesting,%tarball,%localsize,%bymodtime,
1.1       raeburn  1210:         %bysize,$filetouse,$downloadstatus);
1.45.2.16  raeburn  1211:     if (opendir(my $dir,$instdir)) {
1.1       raeburn  1212:         my (@lcdownloads,$version);
                   1213:         foreach my $file (readdir($dir)) {
                   1214:             if ($file =~ /^loncapa\-([\w\-.]+)\.tar\.gz$/) {
                   1215:                 $version = $1;
                   1216:             } else {
                   1217:                 next;
                   1218:             }
                   1219:             if (ref($stdsizes) eq 'HASH') {
                   1220:                 if ($version eq 'current') {
1.45.2.16  raeburn  1221:                     my @stats = stat("$instdir/$file");
1.1       raeburn  1222:                     $localcurrent = $stats[7];
1.4       raeburn  1223:                     if ($localcurrent == $stdsizes->{$production}) {
1.1       raeburn  1224:                         $needs_download = 0;
                   1225:                         $filetouse = $file;
                   1226:                     }
                   1227:                 } elsif ($version eq 'testing') {
1.45.2.16  raeburn  1228:                     my @stats = stat("$instdir/$file");
1.1       raeburn  1229:                     $localtesting = $stats[7];
1.4       raeburn  1230:                     if ($localtesting == $stdsizes->{$testing}) {
1.1       raeburn  1231:                         $needs_download = 0;
                   1232:                         $filetouse = $file;
                   1233:                     }
                   1234:                 }
                   1235:             }
                   1236:             $tarball{$version} = $file;
                   1237:             push(@lcdownloads,$version);
                   1238:         }
                   1239:         if ($needs_download) {
                   1240:             if (@lcdownloads > 0) {
                   1241:                 foreach my $version (@lcdownloads) {
1.45.2.16  raeburn  1242:                     my @stats = stat("$instdir/$tarball{$version}");
1.1       raeburn  1243:                     my $mtime = $stats[9];
                   1244:                     $localsize{$version} = $stats[7];
                   1245:                     if ($mtime) {
                   1246:                         push(@{$bymodtime{$mtime}},$version);
                   1247:                     }
                   1248:                     if ($localsize{$version}) {
                   1249:                         push(@{$bysize{$localsize{$version}}},$version);
                   1250:                     }
                   1251:                 }
                   1252:                 if ($testing) {
                   1253:                     if (exists($localsize{$testing})) {
                   1254:                         if ($stdsizes->{$testing} == $localsize{$testing}) {
                   1255:                             $needs_download = 0;
                   1256:                             $filetouse = 'loncapa-'.$testing.'.tar.gz';
                   1257:                         }
                   1258:                     }
                   1259:                 }
                   1260:                 if ($needs_download) { 
                   1261:                     if ($production) {
                   1262:                         if (exists($localsize{$production})) {
                   1263:                             if ($stdsizes->{$production} == $localsize{$production}) {
                   1264:                                 $needs_download = 0;
                   1265:                                 $filetouse = 'loncapa-'.$production.'.tar.gz';
                   1266:                             }
                   1267:                         }
                   1268:                     }
                   1269:                 }
                   1270:                 if ($needs_download) {
                   1271:                     my @sorted = sort { $b <=> $a } keys(%bymodtime);
                   1272:                     my $newest = $sorted[0];
                   1273:                     if (ref($bymodtime{$newest}) eq 'ARRAY') {
                   1274:                         $downloadstatus = 
1.45.2.16  raeburn  1275:                               "Latest LON-CAPA source download in $instdir is: ".
1.1       raeburn  1276:                               join(',',@{$bymodtime{$newest}})." (downloaded ".
                   1277:                               localtime($newest).")\n";
                   1278:                     }
                   1279:                 } else {
                   1280:                     $downloadstatus = 
1.45.2.16  raeburn  1281:                         "The $instdir directory already contains the latest LON-CAPA version:".
1.1       raeburn  1282:                         "\n".$filetouse."\n"."which can be used for installation.\n";
                   1283:                 }
                   1284:             } else {
1.45.2.16  raeburn  1285:                 $downloadstatus = "The $instdir directory does not appear to contain any downloaded LON-CAPA source code files which can be used for installation.\n";
1.1       raeburn  1286:             }
                   1287:         }
                   1288:     } else {
1.45.2.16  raeburn  1289:         $downloadstatus = "Could not open $instdir directory to look for existing downloads of LON-CAPA source code.\n";
1.1       raeburn  1290:     }
                   1291:     return ($needs_download,$downloadstatus,$filetouse,$production,$testing);
                   1292: }
                   1293: 
                   1294: sub check_mysql_setup {
1.45.2.12  raeburn  1295:     my ($instdir,$dsn,$distro) = @_;
                   1296:     my ($mysqlsetup,$has_pass,$mysql_unix_socket,$mysql_has_wwwuser);
1.1       raeburn  1297:     my $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
1.45.2.19  raeburn  1298:     my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version();
                   1299:     if (($mysqlname =~ /^MariaDB/i) && (($mysqlversion == 10 && $mysqlminorversion >= 4) || ($mysqlversion >= 11))) {
1.45.2.9  raeburn  1300:         if ($dbh) {
                   1301:             my $sth = $dbh->prepare("SELECT Priv FROM mysql.global_priv WHERE (User = 'root' AND Host ='localhost')");
                   1302:             $sth->execute();
                   1303:             while (my $priv = $sth->fetchrow_array) {
1.45.2.14  raeburn  1304:                 if ($priv =~ /unix_socket/) {
1.45.2.9  raeburn  1305:                     $mysql_unix_socket = 1;
                   1306:                     last;
                   1307:                 }
                   1308:             }
                   1309:             $sth->finish();
                   1310:             if ($mysql_unix_socket) {
                   1311:                 print_and_log(&mt('MariaDB using unix_socket for root access from localhost.')."\n");
                   1312:                 $mysqlsetup = 'rootok';
1.45.2.12  raeburn  1313:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.45.2.9  raeburn  1314:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket);
                   1315:             }
                   1316:         }
                   1317:     }
1.1       raeburn  1318:     if ($dbh) {
1.45.2.12  raeburn  1319:         $mysqlsetup = 'noroot';
1.45.2.19  raeburn  1320:         if (($mysqlname !~ /^MariaDB/i) && (($mysqlversion == 5 && $mysqlminorversion >= 7) || ($mysqlversion >= 6))) {
1.45.2.12  raeburn  1321:             my $sth = $dbh->prepare("SELECT plugin from mysql.user where User='root'");
                   1322:             $sth->execute();
                   1323:             while (my $priv = $sth->fetchrow_array) {
                   1324:                 if ($priv =~ /auth_socket/) {
                   1325:                     $mysql_unix_socket = 1;
                   1326:                     last;
                   1327:                 }
                   1328:             }
                   1329:             $sth->finish();
                   1330:             if ($mysql_unix_socket) {
                   1331:                 print_and_log(&mt('MySQL using unix_socket for root access from localhost.')."\n");
                   1332:                 $mysqlsetup = 'rootok';
                   1333:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
                   1334:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket);
                   1335:             }
1.45.2.14  raeburn  1336:         }
1.1       raeburn  1337:     } elsif ($DBI::err =~ /1045/) {
                   1338:         $has_pass = 1;
1.34      raeburn  1339:     } elsif ($distro =~ /^ubuntu(\d+)$/) {
                   1340:         my $version = $1;
                   1341:         if ($1 > 12) {
                   1342:             print_and_log(&mt('Restarting mysql, please be patient')."\n");
                   1343:             if (open (PIPE, "service mysql restart 2>&1 |")) {
                   1344:                 while (<PIPE>) {
                   1345:                     print $_;
                   1346:                 }
                   1347:                 close(PIPE);
                   1348:             }
                   1349:             $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
                   1350:             if ($dbh) {
                   1351:                 $mysqlsetup = 'noroot';
1.45.2.12  raeburn  1352:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.34      raeburn  1353:             } elsif ($DBI::err =~ /1045/) {
                   1354:                 $has_pass = 1;
                   1355:             } else {
                   1356:                 $mysqlsetup = 'needsrestart';
1.45.2.16  raeburn  1357:                 $mysql_has_wwwuser = &check_mysql_wwwuser();
1.34      raeburn  1358:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
                   1359:             }
                   1360:         }
1.1       raeburn  1361:     }
                   1362:     if ($has_pass) {
                   1363:         print &mt('You have already set a root password for the MySQL database.')."\n";
                   1364:         my $currpass = &get_mysql_password(&mt('Please enter the password now'));
                   1365:         $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
                   1366:         if ($dbh) {
                   1367:             $mysqlsetup = 'rootok';
                   1368:             print_and_log(&mt('Password accepted.')."\n");
1.45.2.12  raeburn  1369:             $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.1       raeburn  1370:         } else {
                   1371:             $mysqlsetup = 'rootfail';
                   1372:             print_and_log(&mt('Problem accessing MySQL.')."\n");
                   1373:             if ($DBI::err =~ /1045/) {
                   1374:                 print_and_log(&mt('Perhaps the password was incorrect?')."\n");
                   1375:                 print &mt('Try again?').' ';
                   1376:                 $currpass = &get_mysql_password(&mt('Re-enter password now')); 
                   1377:                 $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
                   1378:                 if ($dbh) {
                   1379:                     $mysqlsetup = 'rootok';
                   1380:                     print_and_log(&mt('Password accepted.')."\n");
1.45.2.12  raeburn  1381:                     $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.1       raeburn  1382:                 } else {
                   1383:                     if ($DBI::err =~ /1045/) {
                   1384:                         print_and_log(&mt('Incorrect password.')."\n");
                   1385:                     }
1.45.2.16  raeburn  1386:                     $mysql_has_wwwuser = &check_mysql_wwwuser();
1.1       raeburn  1387:                 }
                   1388:             }
                   1389:         }
1.34      raeburn  1390:     } elsif ($mysqlsetup ne 'noroot') {
1.1       raeburn  1391:         print_and_log(&mt('Problem accessing MySQL.')."\n");
                   1392:         $mysqlsetup = 'rootfail';
1.45.2.16  raeburn  1393:         $mysql_has_wwwuser = &check_mysql_wwwuser();
1.1       raeburn  1394:     }
1.34      raeburn  1395:     return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
1.1       raeburn  1396: }
                   1397: 
                   1398: sub check_mysql_wwwuser {
1.45.2.12  raeburn  1399:     my ($dbh) = @_;
1.1       raeburn  1400:     my $mysql_wwwuser;
1.45.2.12  raeburn  1401:     if ($dbh) {
                   1402:         $mysql_wwwuser = $dbh->selectrow_array("SELECT COUNT(User) FROM mysql.user WHERE (User = 'www' AND Host ='localhost')");
                   1403:     } else {
                   1404:         my $dbhn = DBI->connect("DBI:mysql:database=information_schema",'www','localhostkey',
                   1405:                                 {PrintError => +0}) || return;
                   1406:         if ($dbhn) {
                   1407:             $mysql_wwwuser = 1;
                   1408:             $dbhn->disconnect;
                   1409:         }
1.1       raeburn  1410:     }
                   1411:     return $mysql_wwwuser;
                   1412: }
                   1413: 
                   1414: sub check_loncapa_mysqldb {
                   1415:     my ($dbh) = @_;
                   1416:     my $has_lcdb;
                   1417:     if (ref($dbh)) {
                   1418:         my $sth = $dbh->prepare("SHOW DATABASES");
                   1419:         $sth->execute();
                   1420:         while (my $dbname = $sth->fetchrow_array) {
                   1421:             if ($dbname eq 'loncapa') {
                   1422:                 $has_lcdb = 1;
                   1423:                 last;
                   1424:             }
                   1425:         }
                   1426:         $sth->finish();
                   1427:     }
                   1428:     return $has_lcdb;
                   1429: }
                   1430: 
                   1431: sub get_pathto_iptables {
                   1432:     my $iptables;
                   1433:     if (-e '/sbin/iptables') {
                   1434:         $iptables = '/sbin/iptables';
                   1435:     } elsif (-e '/usr/sbin/iptables') {
                   1436:         $iptables = '/usr/sbin/iptables';
                   1437:     } else {
                   1438:         print &mt('Unable to find iptables command.')."\n";
                   1439:     }
                   1440:     return $iptables;
                   1441: }
                   1442: 
                   1443: sub firewall_is_active {
                   1444:     if (-e '/proc/net/ip_tables_names') {
1.45.2.19  raeburn  1445:         my $status;
1.45.2.1  raeburn  1446:         if (open(PIPE,'cat /proc/net/ip_tables_names |grep filter |')) {
1.45.2.19  raeburn  1447:             $status = <PIPE>;
1.45.2.1  raeburn  1448:             close(PIPE);
                   1449:             chomp($status);
                   1450:             if ($status eq 'filter') {
                   1451:                 return 1;
                   1452:             }
                   1453:         }
1.45.2.19  raeburn  1454:         unless ($status) {
                   1455:             if (open(PIPE,'nft list tables |')) {
                   1456:                 while(<PIPE>) {
                   1457:                     chomp();
                   1458:                     if (/filter$/) {
                   1459:                         $status = 1;
                   1460:                         last;
                   1461:                     }
                   1462:                 }
                   1463:                 close(PIPE);
                   1464:                 if ($status) {
                   1465:                     return 1;
                   1466:                 }
                   1467:             }
                   1468:         }
1.1       raeburn  1469:     }
1.45.2.1  raeburn  1470:     return 0;
1.1       raeburn  1471: }
                   1472: 
                   1473: sub get_fw_chains {
1.5       raeburn  1474:     my ($iptables,$distro) = @_;
1.1       raeburn  1475:     my @fw_chains;
                   1476:     my $suse_config = "/etc/sysconfig/SuSEfirewall2";
                   1477:     my $ubuntu_config = "/etc/ufw/ufw.conf";
                   1478:     if (-e $suse_config) {
                   1479:         push(@fw_chains,'input_ext');
                   1480:     } else {
                   1481:         my @posschains;
                   1482:         if (-e $ubuntu_config) {
                   1483:             @posschains = ('ufw-user-input','INPUT');
1.5       raeburn  1484:         } elsif ($distro =~ /^debian5/) {
                   1485:             @posschains = ('INPUT');
1.45.2.1  raeburn  1486:         } elsif ($distro =~ /^(suse|sles)(\d+)/) {
                   1487:             @posschains = ('IN_public');
1.1       raeburn  1488:         } else {
                   1489:             @posschains = ('RH-Firewall-1-INPUT','INPUT');
                   1490:             if (!-e '/etc/sysconfig/iptables') {
                   1491:                 if (!-e '/var/lib/iptables') {
                   1492:                     print &mt('Unable to find iptables file containing static definitions.')."\n";
                   1493:                 }
                   1494:                 push(@fw_chains,'RH-Firewall-1-INPUT');
                   1495:             }
                   1496:         }
                   1497:         if ($iptables eq '') {
                   1498:             $iptables = &get_pathto_iptables();
                   1499:         }
                   1500:         my %counts;
                   1501:         if (open(PIPE,"$iptables -L -n |")) {
                   1502:             while(<PIPE>) {
                   1503:                 foreach my $chain (@posschains) {
                   1504:                     if (/(\Q$chain\E)/) {
                   1505:                         $counts{$1} ++;
                   1506:                     }
                   1507:                 }
                   1508:             }
                   1509:             close(PIPE);
                   1510:         }
                   1511:         foreach my $fw_chain (@posschains) {
                   1512:             if ($counts{$fw_chain}) {
                   1513:                 unless(grep(/^\Q$fw_chain\E$/,@fw_chains)) {
                   1514:                     push(@fw_chains,$fw_chain);
                   1515:                 }
                   1516:             }
                   1517:         }
                   1518:     }
                   1519:     return @fw_chains;
                   1520: }
                   1521: 
                   1522: sub firewall_is_port_open {
                   1523:     my ($iptables,$fw_chain,$port) = @_;
                   1524:     # returns 1 if the firewall port is open, 0 if not.
                   1525:     #
                   1526:     # check if firewall is active or installed
                   1527:     return if (! &firewall_is_active());
                   1528:     my $count = 0;
                   1529:     if (open(PIPE,"$iptables -L $fw_chain -n |")) {
                   1530:         while(<PIPE>) {
                   1531:             if (/tcp dpt\:\Q$port\E/) {
                   1532:                 $count ++;
                   1533:                 last;
                   1534:             }
                   1535:         }
                   1536:         close(PIPE);
                   1537:     } else {
                   1538:         print &mt('Firewall status not checked: unable to run [_1].','iptables -L')."\n";
                   1539:     }
                   1540:     return $count;
                   1541: }
                   1542: 
                   1543: sub get_mysql_password {
                   1544:     my ($prompt) = @_;
                   1545:     local $| = 1;
                   1546:     print $prompt.': ';
                   1547:     my $newpasswd = '';
                   1548:     ReadMode 'raw';
                   1549:     my $key;
                   1550:     while(ord($key = ReadKey(0)) != 10) {
                   1551:         if(ord($key) == 127 || ord($key) == 8) {
                   1552:             chop($newpasswd);
                   1553:             print "\b \b";
                   1554:         } elsif(!ord($key) < 32) {
                   1555:             $newpasswd .= $key;
                   1556:             print '*';
                   1557:         }
                   1558:     }
                   1559:     ReadMode 'normal';
                   1560:     print "\n";
                   1561:     return $newpasswd;
                   1562: }
                   1563: 
                   1564: sub check_SuSEfirewall2_setup {
                   1565:     my ($instdir) = @_;
                   1566:     my $need_override = 1;
1.9       raeburn  1567:     if ((-e "/etc/insserv/overrides/SuSEfirewall2_setup") && (-e "$instdir/sles-suse/SuSEfirewall2_setup")) {
                   1568:         if (open(PIPE, "diff --brief $instdir/sles-suse/SuSEfirewall2_setup /etc/insserv/overrides/SuSEfirewall2_setup  |")) {
1.1       raeburn  1569:             my $diffres = <PIPE>;
                   1570:             close(PIPE);
                   1571:             chomp($diffres);
                   1572:             unless ($diffres) {
                   1573:                 $need_override = 0;
                   1574:             }
                   1575:         }
                   1576:     }
                   1577:     return $need_override;
                   1578: }
                   1579: 
                   1580: sub download_versionslist {
                   1581:     my ($production,$testing,%sizes);
                   1582:     if (-e "latest.txt") {
                   1583:          unlink("latest.txt");
                   1584:     }
                   1585:     my $rtncode = system("wget http://install.loncapa.org/versions/latest.txt ".
                   1586:                          "> /dev/null 2>&1");
                   1587:     if (!$rtncode) {
                   1588:         if (open(my $fh,"<latest.txt")) {
                   1589:             my @info = <$fh>;
                   1590:             close($fh);
                   1591:             foreach my $line (@info) {
                   1592:                 chomp();
                   1593:                 if ($line =~ /^\QLATEST-IS: \E([\w\-.]+):(\d+)$/) {
                   1594:                      $production = $1;
                   1595:                      $sizes{$1} = $2;
                   1596:                 } elsif ($line =~ /^LATEST-TESTING-IS: \E([\w\-.]+):(\d+)$/) {
                   1597:                      $testing = $1;
                   1598:                      $sizes{$1} = $2;
                   1599:                 }
                   1600:             }
                   1601:         }
                   1602:     }
                   1603:     return ($production,$testing,\%sizes);
                   1604: }
                   1605: 
                   1606: #
                   1607: # End helper routines.
                   1608: # Main script starts here
                   1609: #
                   1610: 
                   1611: print "
                   1612: ********************************************************************
                   1613: 
                   1614:                     ".&mt('Welcome to LON-CAPA')."
                   1615: 
                   1616: ".&mt('This script will configure your system for installation of LON-CAPA.')."
                   1617: 
                   1618: ********************************************************************
                   1619: 
                   1620: ".&mt('The following actions are available:')."
                   1621: 
1.4       raeburn  1622: ".&mt('1.')." ".&mt('Create the www user/group.')."
1.1       raeburn  1623:    ".&mt('This is the user/group ownership under which Apache child processes run.')."
                   1624:    ".&mt('It also owns most directories within the /home/httpd directory.')." 
                   1625:    ".&mt('This directory is where most LON-CAPA files and directories are stored.')."
1.4       raeburn  1626: ".&mt('2.')." ".&mt('Install the package LON-CAPA uses to authenticate users.')."
                   1627: ".&mt('3.')." ".&mt('Set-up the MySQL database.')."
                   1628: ".&mt('4.')." ".&mt('Set-up MySQL permissions.')."
                   1629: ".&mt('5.')." ".&mt('Configure Apache web server.')."
1.45.2.20  raeburn  1630: ".&mt('6.')." ".&mt('Configure systemd security settings for Apache web server.')."
                   1631: ".&mt('7.')." ".&mt('Configure start-up of services.')."
                   1632: ".&mt('8.')." ".&mt('Check firewall settings.')."
                   1633: ".&mt('9.')." ".&mt('Stop services not used by LON-CAPA,')."
1.1       raeburn  1634:    ".&mt('i.e., services for a print server: [_1] daemon.',"'cups'")."
1.45.2.20  raeburn  1635: ".&mt('10.')." ".&mt('Download LON-CAPA source code in readiness for installation.')."
1.1       raeburn  1636: 
                   1637: ".&mt('Typically, you will run this script only once, when you first install LON-CAPA.')." 
                   1638: 
                   1639: ".&mt('The script will analyze your system to determine which actions are recommended.')."
                   1640: ".&mt('The script will then prompt you to choose the actions you would like taken.')."
                   1641: 
                   1642: ".&mt('For each the recommended action will be selected if you hit Enter/Return.')."
                   1643: ".&mt('To override the default, type the lower case option from the two options listed.')."
                   1644: ".&mt('So, if the default is "yes", ~[Y/n~] will be shown -- type n to override.')."
                   1645: ".&mt('Whereas if the default is "no", ~[y/N~] will be shown -- type y to override.')." 
                   1646: 
                   1647: ".&mt('To accept the default, simply hit Enter/Return on your keyboard.')."
                   1648: ".&mt('Otherwise type: y or n then hit the Enter/Return key.')."
                   1649: 
                   1650: ".&mt('Once a choice has been entered for all nine actions, required changes will be made.')."
                   1651: ".&mt('Feedback will be displayed on screen, and also stored in: [_1].','loncapa_install.log')."
                   1652: 
                   1653: ".&mt('Continue? ~[Y/n~] ');
                   1654: 
                   1655: my $go_on = &get_user_selection(1);
                   1656: if (!$go_on) {
                   1657:     exit;
                   1658: }
                   1659: 
                   1660: my $instdir = `pwd`;
                   1661: chomp($instdir);
                   1662: 
                   1663: my %callsub;
1.45.2.20  raeburn  1664: my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache','systemd',
1.1       raeburn  1665:                'runlevels','firewall','stopsrvcs','download');
                   1666: my %prompts = &texthash( 
                   1667:     wwwuser    => "Create the 'www' user?",
                   1668:     pwauth     => 'Install the package LON-CAPA uses to authenticate users?',
                   1669:     mysql      => 'Set-up the MySQL database?',
                   1670:     mysqlperms => 'Set-up MySQL permissions?',
                   1671:     apache     => 'Configure Apache web server?',
1.45.2.20  raeburn  1672:     systemd    => 'Configure systemd security settings for Apache web server?',
1.1       raeburn  1673:     runlevels  => 'Set overrides for start-up order of services?',
                   1674:     firewall   => 'Configure firewall settings for Apache',
                   1675:     stopsrvcs  => 'Stop extra services not required on a LON-CAPA server?',
                   1676:     download   => 'Download LON-CAPA source code in readiness for installation?',
                   1677: );
                   1678: 
                   1679: print "\n".&mt('Checking system status ...')."\n";
                   1680: 
                   1681: my $dsn = "DBI:mysql:database=mysql";
1.45.2.22  raeburn  1682: my ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart,
1.45.2.9  raeburn  1683:     $recommended,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$downloadstatus,
                   1684:     $filetouse,$production,$testing,$apachefw,$uses_systemctl) = &check_required($instdir,$dsn);
1.1       raeburn  1685: if ($distro eq '') {
                   1686:     print "\n".&mt('Linux distribution could not be verified as a supported distribution.')."\n".
                   1687:           &mt('The following are supported: [_1].',
                   1688:               'CentOS, RedHat Enterprise, Fedora, Scientific Linux, '.
1.45.2.3  raeburn  1689:               'Oracle Linux, openSuSE, SLES, Ubuntu LTS, Debian')."\n\n".
1.1       raeburn  1690:           &mt('Stopping execution.')."\n";
                   1691:     exit;
                   1692: }
1.34      raeburn  1693: if ($mysqlrestart) {
                   1694:     print "\n".&mt('The mysql daemon needs to be restarted using the following command:')."\n".
                   1695:           $mysqlrestart."\n\n".
                   1696:           &mt('Stopping execution of install.pl script.')."\n".
                   1697:           &mt('Please run the install.pl script again, once you have restarted mysql.')."\n";
                   1698:     exit;
                   1699: }
1.6       raeburn  1700: if ($localecmd ne '') {
1.45.2.22  raeburn  1701:     print "\n".&mt('Although the LON-CAPA application itself is localized for a number of different languages,[_1]the default locale language for the Linux OS on which it runs should be US English.',"\n")."\n\n";
                   1702:     if ($langcmd ne '') {
                   1703:         print &mt('Use the following command(s) or action(s) to install a required language package.')."\n\n".
                   1704:               "$langcmd\n";
                   1705:     }
                   1706:     print &mt('Run the following command from the command line to set the default language for your OS,[_1]and then run this LON-CAPA installation set-up script again.',"\n")."\n\n".
1.6       raeburn  1707:     $localecmd."\n\n".
                   1708:     &mt('Stopping execution.')."\n";
                   1709:     exit;
                   1710: }
1.1       raeburn  1711: if (!$gotprereqs) {
1.12      raeburn  1712:     print "\n".&mt('The LONCAPA-prerequisites package is not installed.')."\n".
1.1       raeburn  1713:           &mt('The following command can be used to install the package (and dependencies):')."\n\n".
                   1714:           $updatecmd."\n\n";
                   1715:     if ($installnow eq '') {
                   1716:         print &mt('Stopping execution.')."\n";
                   1717:         exit;
                   1718:     } else {
                   1719:         print &mt('Run command? ~[Y/n~]');
                   1720:         my $install_prereq = &get_user_selection(1);
                   1721:         if ($install_prereq) {
                   1722:             if (open(PIPE,'|-',$installnow)) {
                   1723:                 close(PIPE);
                   1724:                 $gotprereqs = &check_prerequisites($packagecmd,$distro);
                   1725:                 if (!$gotprereqs) {
1.12      raeburn  1726:                     print &mt('The LONCAPA-prerequisites package is not installed.')."\n".
1.1       raeburn  1727:                           &mt('Stopping execution.')."\n";
                   1728:                     exit;
                   1729:                 } else {
1.45.2.22  raeburn  1730:                     ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,
1.45.2.9  raeburn  1731:                      $mysqlrestart,$recommended,$dbh,$has_pass,$mysql_unix_socket,
                   1732:                      $has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw,
                   1733:                      $uses_systemctl) = &check_required($instdir,$dsn);
1.1       raeburn  1734:                 }
                   1735:             } else {
1.12      raeburn  1736:                 print &mt('Failed to run command to install LONCAPA-prerequisites')."\n";
1.1       raeburn  1737:                 exit;
                   1738:             }
                   1739:         } else {
                   1740:             print &mt('Stopping execution.')."\n";
                   1741:             exit;
                   1742:         }
                   1743:     }
                   1744: }
                   1745: unless (ref($recommended) eq 'HASH') {
                   1746:     print "\n".&mt('An error occurred determining which actions are recommended.')."\n\n".
                   1747:           &mt('Stopping execution.')."\n";
                   1748:     exit;
                   1749: }
                   1750: 
                   1751: print "\n";
                   1752: my $num = 0;
                   1753: foreach my $action (@actions) {
                   1754:     $num ++;
                   1755:     my ($yesno,$defaultrun);
                   1756:     if (ref($recommended) eq 'HASH') {
1.4       raeburn  1757:         if (($action eq 'runlevels') || ($action eq 'stopsrvcs')) {
1.1       raeburn  1758:             $yesno = '[y/N]';
                   1759:             if (ref($recommended->{$action}) eq 'HASH') {
                   1760:                 if (keys(%{$recommended->{$action}}) > 0) {
                   1761:                     $yesno = &mt('~[Y/n~]');
                   1762:                     $defaultrun = 1;
                   1763:                 }
                   1764:             }
                   1765:         } else {
                   1766:             if ($action eq 'download') {
                   1767:                 if ($downloadstatus) {
                   1768:                     print "\n$downloadstatus\n";
                   1769:                 }
                   1770:             }
                   1771:             if ($recommended->{$action}) {
                   1772:                 $yesno = mt('~[Y/n~]');
                   1773:                 $defaultrun = 1;
                   1774:             } else {
                   1775:                 $yesno = &mt('~[y/N~]');
                   1776:             }
                   1777:         }
                   1778:         print $num.'. '.$prompts{$action}." $yesno ";
                   1779:         $callsub{$action} = &get_user_selection($defaultrun);
                   1780:     }
                   1781: }
                   1782: 
                   1783: my $lctarball = 'loncapa-current.tar.gz';
                   1784: my $sourcetarball = $lctarball;
                   1785: if ($callsub{'download'}) {
                   1786:     my ($production,$testing,$sizes) = &download_versionslist();
1.45.2.16  raeburn  1787:     my $homedir = '/root';
                   1788:     if ($distro =~ /^ubuntu/) {
                   1789:         if ($instdir ne $homedir) {
                   1790:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   1791:         }
                   1792:     }
1.1       raeburn  1793:     if ($production && $testing) {
                   1794:         if ($production ne $testing) {
                   1795:             print &mt('Two recent LON-CAPA releases are available: ')."\n".
1.3       raeburn  1796:                   &mt('1.').' '.&mt('A production release - version: [_1].',$production)."\n".
                   1797:                   &mt('2.').' '.&mt('A testing release - version: [_1].',$testing)."\n\n".
1.45.2.16  raeburn  1798:                   &mt("After download, the tar.gz file will be extracted into $homedir")."\n\n".
                   1799:                   &mt("Download the production release into $instdir? ~[Y/n~]");
1.1       raeburn  1800:             if (&get_user_selection(1)) {
1.4       raeburn  1801:                 $sourcetarball = 'loncapa-'.$production.'.tar.gz';
1.45.2.16  raeburn  1802:                 print "$sourcetarball will be downloaded into $instdir\n";
1.1       raeburn  1803:             } else {
                   1804:                 print "\n".&mt('Download the testing release? ~[Y/n~]');
                   1805:                 if (&get_user_selection(1)) {
1.4       raeburn  1806:                     $sourcetarball = 'loncapa-'.$testing.'.tar.gz';
1.45.2.16  raeburn  1807:                     print "$sourcetarball will be downloaded into $instdir\n";
                   1808:                 } else {
                   1809:                     $callsub{'download'} = 0;
1.1       raeburn  1810:                 }
                   1811:             }
                   1812:         }
                   1813:     } elsif ($production) {
                   1814:         print &mt('The most recent LON-CAPA release is version: [_1].',$production)."\n".
1.45.2.16  raeburn  1815:               &mt("After download, the tar.gz file will be extracted into $homedir")."\n\n".
                   1816:               &mt("Download the production release into $instdir? ~[Y/n~]");
1.1       raeburn  1817:         if (&get_user_selection(1)) {
1.20      raeburn  1818:             $sourcetarball = 'loncapa-'.$production.'.tar.gz';
1.45.2.16  raeburn  1819:             print "$sourcetarball will be downloaded into $instdir\n";
                   1820:         } else {
                   1821:             $callsub{'download'} = 0;
1.1       raeburn  1822:         }
                   1823:     }
                   1824: } elsif ($filetouse ne '') {
                   1825:     $sourcetarball = $filetouse;
                   1826: }
                   1827: 
                   1828: print_and_log("\n");
                   1829: 
                   1830: # Each action: report if skipping, or perform action and provide feedback. 
                   1831: if ($callsub{'wwwuser'}) {
                   1832:     &setup_www();
                   1833: } else {
                   1834:     &print_and_log(&mt('Skipping creation of user [_1].',"'www'")."\n");
                   1835: }
                   1836: 
                   1837: if ($callsub{'pwauth'}) {
1.4       raeburn  1838:     &build_and_install_mod_auth_external($instdir);
1.1       raeburn  1839: } else {
                   1840:     &print_and_log(&mt('Skipping [_1] installation.',"'pwauth'")."\n");
                   1841: }
                   1842: 
                   1843: if ($callsub{'mysql'}) {
                   1844:     if ($dbh) {
1.45.2.9  raeburn  1845:         &setup_mysql($callsub{'mysqlperms'},$dbh,$has_pass,
1.45.2.15  raeburn  1846:                      $mysql_unix_socket,$has_lcdb,$distro);
1.1       raeburn  1847:     } else {
                   1848:         print &mt('Unable to configure MySQL because access is denied.')."\n";
                   1849:     }
                   1850: } else {
                   1851:     &print_and_log(&mt('Skipping configuration of MySQL.')."\n");
                   1852:     if ($callsub{'mysqlperms'}) {
                   1853:         if ($dbh) {
1.45.2.9  raeburn  1854:             &setup_mysql_permissions($dbh,$has_pass,$mysql_unix_socket);
1.1       raeburn  1855:         } else {
                   1856:             print &mt('Unable to configure MySQL because access is denied.')."\n";  
                   1857:         }
                   1858:     } else {
                   1859:         &print_and_log(&mt('Skipping MySQL permissions setup.')."\n");
                   1860:     }
                   1861: }
                   1862: 
                   1863: if ($dbh) {
                   1864:     if (!$dbh->disconnect) {
                   1865:         &print_and_log(&mt('Failed to disconnect from MySQL:')."\n".
                   1866:                        $dbh->errstr);
                   1867:     }
                   1868: }
                   1869: 
                   1870: if ($callsub{'apache'}) {
                   1871:     if ($distro =~ /^(suse|sles)/) {
1.45.2.1  raeburn  1872:         &copy_apache2_suseconf($instdir,$distro);
1.1       raeburn  1873:     } elsif ($distro =~ /^(debian|ubuntu)/) {
1.28      raeburn  1874:         &copy_apache2_debconf($instdir,$distro);
1.1       raeburn  1875:     } else {
1.14      raeburn  1876:         &copy_httpd_conf($instdir,$distro);
1.45.2.5  raeburn  1877:         &copy_mpm_conf($instdir,$distro);
1.1       raeburn  1878:     }
                   1879: } else {
                   1880:     print_and_log(&mt('Skipping configuration of Apache web server.')."\n");
                   1881: }
                   1882: 
1.45.2.20  raeburn  1883: if ($callsub{'systemd'}) {
                   1884:     &check_systemd_update($distro);
                   1885: } else {
                   1886:     print_and_log('Skipping systemd configuration update for web server');
                   1887: }
                   1888: 
1.1       raeburn  1889: if ($callsub{'runlevels'}) {
                   1890:     my $count = 0;
                   1891:     if (ref($recommended) eq 'HASH') {
                   1892:         if (ref($recommended->{'runlevels'}) eq 'HASH') {
                   1893:             foreach my $type (keys(%{$recommended->{'runlevels'}})) {
                   1894:                 next if ($type eq 'insserv');
                   1895:                 $count ++;
                   1896:                 my $command = $recommended->{'runlevels'}{$type};
                   1897:                 if ($command ne '') {
                   1898:                     print_and_log(&mt('Runlevel update command run: [_1].',$command)."\n");
                   1899:                     system($command);
                   1900:                 }
                   1901:             }
                   1902:             if (!$count) {
                   1903:                 print_and_log(&mt('No runlevel updates required.')."\n");
                   1904:             }  
                   1905:         }
                   1906:     }
1.45.2.1  raeburn  1907:     if ($distro =~ /^(suse|sles)(\d+)/) {
                   1908:         unless(($1 eq 'sles') && ($2 >= 15)) {
                   1909:             &update_SuSEfirewall2_setup($instdir);
                   1910:         }
1.11      raeburn  1911:     }
1.1       raeburn  1912: } else {
                   1913:     &print_and_log(&mt('Skipping setting override for start-up order of services.')."\n");
                   1914: }
                   1915: 
                   1916: if ($callsub{'firewall'}) {
1.45.2.3  raeburn  1917:     my ($firewalld,$zone) = &uses_firewalld($distro);
                   1918:     if ($firewalld) {
1.45.2.1  raeburn  1919:         my (%current,%added);
1.45.2.3  raeburn  1920:         if (open(PIPE,"firewall-cmd --permanent --zone=$zone --list-services |")) {
1.45.2.1  raeburn  1921:             my $svc = <PIPE>;
                   1922:             close(PIPE);
                   1923:             chomp($svc);
                   1924:             map { $current{$_} = 1; } (split(/\s+/,$svc));
                   1925:         }
                   1926:         foreach my $service ('http','https') {
                   1927:             unless ($current{$service}) {
1.45.2.3  raeburn  1928:                 if (open(PIPE,"firewall-cmd --permanent --zone=$zone --add-service=$service |")) {
1.45.2.1  raeburn  1929:                     my $result = <PIPE>;
                   1930:                     if ($result =~ /^success/) {
                   1931:                         $added{$service} = 1;
                   1932:                     }
                   1933:                 }
                   1934:             }
                   1935:         }
                   1936:         if (keys(%added) > 0) {
                   1937:             print &mt('Firewall configured to allow access for: [_1].',
                   1938:                       join(', ',sort(keys(%added))))."\n";
1.45.2.13  raeburn  1939:             system('firewall-cmd --reload');
1.45.2.1  raeburn  1940:         }
                   1941:         if ($current{'http'} || $current{'https'}) {
                   1942:             print &mt('Firewall already configured to allow access for:[_1].',
                   1943:                       (($current{'http'})? ' http':'').(($current{'https'})? ' https':''))."\n";
                   1944:         }
                   1945:         unless ($current{'ssh'}) {
1.45.2.13  raeburn  1946:             print &mt('If you would like to allow access to ssh from outside, use the commands:')."\n".
                   1947:                   "firewall-cmd --permanent --zone=$zone --add-service=ssh\n".
                   1948:                   "firewall-cmd --reload\n";
1.45.2.1  raeburn  1949:         }
                   1950:     } elsif ($distro =~ /^(suse|sles)/) {
1.5       raeburn  1951:         print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1952:                   'yast -- Security and Users -> Firewall -> Interfaces',
1.45.2.1  raeburn  1953:                   'ssh, http, https')."\n";
1.5       raeburn  1954:     } elsif ($distro =~ /^(debian|ubuntu)(\d+)/) {
                   1955:         if (($1 eq 'ubuntu') || ($2 > 5)) {
                   1956:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1957:                       'ufw','ssh, http, https')."\n";
                   1958:         } else {
                   1959:             my $fwadded = &get_iptables_rules($distro,$instdir,$apachefw);
                   1960:             if ($fwadded) {
                   1961:                 print &mt('Enable firewall? ~[Y/n~]');
                   1962:                 my $enable_iptables = &get_user_selection(1);
                   1963:                 if ($enable_iptables) {
                   1964:                     system('/etc/network/if-pre-up.d/iptables');
                   1965:                     print &mt('Firewall enabled using rules defined in [_1].',
                   1966:                               '/etc/iptables.loncapa.rules'); 
                   1967:                 }
                   1968:             }
                   1969:         }
1.45.2.3  raeburn  1970:     } elsif ($distro =~ /^(scientific|oracle)/) {
1.11      raeburn  1971:         print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1972:                   'system-config-firewall-tui -- Customize',
                   1973:                   'ssh, http')."\n";
1.1       raeburn  1974:     } else {
1.45.2.3  raeburn  1975:         my $version;
1.45.2.18  raeburn  1976:         if ($distro =~ /^(redhat|centos|rocky|alma)(\d+)/) {
1.45.2.3  raeburn  1977:             $version = $1;
                   1978:         }
                   1979:         if ($version > 5) {
                   1980:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1981:                   'system-config-firewall-tui -- Customize',
                   1982:                   'ssh, http')."\n";
                   1983:         } else {
                   1984:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1985:                       'setup -- Firewall configuration -> Customize',
                   1986:                       'ssh, http, https')."\n";
                   1987:         }
1.1       raeburn  1988:     }
                   1989: } else {
1.5       raeburn  1990:     &print_and_log(&mt('Skipping Firewall configuration.')."\n");
1.1       raeburn  1991: }
                   1992: 
                   1993: if ($callsub{'stopsrvcs'}) {
1.45      raeburn  1994:     &kill_extra_services($distro,$recommended->{'stopsrvcs'},$uses_systemctl);
1.1       raeburn  1995: } else {
1.10      raeburn  1996:     &print_and_log(&mt('Skipping stopping unnecessary service ([_1] daemons).',"'cups','memcached'")."\n");
1.1       raeburn  1997: }
                   1998: 
                   1999: my ($have_tarball,$updateshown);
                   2000: if ($callsub{'download'}) {
                   2001:     ($have_tarball,$updateshown) = &download_loncapa($instdir,$sourcetarball);
                   2002: } else {
                   2003:     print_and_log(&mt('Skipping download of LON-CAPA tar file.')."\n\n");
                   2004:     print &mt('LON-CAPA is available for download from: [_1]',
                   2005:               'http://install.loncapa.org/')."\n";
                   2006:     if (!-e '/etc/loncapa-release') {
1.45.2.19  raeburn  2007:         &print_and_log(&mt('LON-CAPA is not yet installed on your system.')."\n\n");
                   2008:         unless ($filetouse) {
                   2009:             &print_and_log(&mt('You may retrieve the source for LON-CAPA by executing:')."\n".
                   2010:                            "wget http://install.loncapa.org/versions/$lctarball\n");
                   2011:         }
1.1       raeburn  2012:     } else {
                   2013:         my $currentversion;
                   2014:         if (open(my $fh,"</etc/loncapa-release")) {
                   2015:             my $version = <$fh>;
                   2016:             chomp($version);
                   2017:             if ($version =~ /^\QLON-CAPA release \E([\w\-.]+)$/) {
                   2018:                 $currentversion = $1;
                   2019:             }
                   2020:         }
                   2021:         if ($currentversion ne '') {
                   2022:             print &mt('Version of LON-CAPA currently installed on this server is: [_1].',
                   2023:                       $currentversion),"\n";
                   2024:             if ($production) {
                   2025:                 print &mt('The latest production release of LON-CAPA is [_1].',$production)."\n";
                   2026:             }
                   2027:             if ($testing) {
                   2028:                 print &mt('The latest testing release of LON-CAPA is [_1].',$testing)."\n";
                   2029:             }
                   2030:         }
                   2031:     }
                   2032:     if ($filetouse ne '') {
                   2033:         $have_tarball = 1;
                   2034:     }
                   2035: }
                   2036: 
                   2037: print "\n".&mt('Requested configuration complete.')."\n\n";
                   2038: if ($have_tarball && !$updateshown) {
                   2039:     my ($lcdir) = ($sourcetarball =~ /^([\w.\-]+)\.tar.gz$/);
1.45.2.16  raeburn  2040:     if ($lcdir eq 'loncapa-current') {
                   2041:         $lcdir = "loncapa-X.Y.Z (X.Y.Z should correspond to a version number like '2.11.3')";
                   2042:     }
1.45.2.14  raeburn  2043:     my ($apachename,$lc_uses_systemctl,$uses_sudo);
1.45.2.12  raeburn  2044:     if ($distro =~ /^(suse|sles|debian|ubuntu)([\d.]+)/) {
                   2045:         if (($1 eq 'suse') && ($2 < 10)) {
                   2046:             $apachename = 'apache';
                   2047:         } else {
                   2048:             $apachename = 'apache2';
                   2049:         }
                   2050:     } else {
                   2051:         $apachename = 'httpd';
                   2052:     }
                   2053:     if ($distro =~ /^oracle(\d+)$/) {
                   2054:         if ($1 > 6) {
                   2055:             $lc_uses_systemctl = 1;
                   2056:         }
1.45.2.18  raeburn  2057:     } elsif ($distro =~ /^(?:rhes|centos|rocky|alma)(\d+)/) {
1.45.2.12  raeburn  2058:         if ($1 > 7) {
                   2059:             $lc_uses_systemctl = 1;
                   2060:         }
                   2061:     } elsif ($distro =~ /^ubuntu(\d+)$/) {
                   2062:         if ($1 > 16) {
                   2063:             $lc_uses_systemctl = 1;
                   2064:         }
                   2065:         $uses_sudo = 1;
1.45.2.19  raeburn  2066:     } elsif ($distro =~ /^debian(\d+)$/) {
                   2067:         if ($1 >= 10) {
                   2068:             $lc_uses_systemctl = 1;
                   2069:         }
1.45.2.12  raeburn  2070:     } elsif ($distro =~ /^sles(\d+)$/) {
                   2071:         if ($1 > 12) {
                   2072:             $lc_uses_systemctl = 1;
                   2073:         }
1.45.2.20  raeburn  2074:     } elsif ($distro =~ /^fedora(\d+)$/) {
                   2075:         if ($1 > 25) {
                   2076:             $lc_uses_systemctl = 1;
                   2077:         }
1.45.2.12  raeburn  2078:     }
1.1       raeburn  2079:     if (!-e '/etc/loncapa-release') {
                   2080:         print &mt('If you are now ready to install LON-CAPA, enter the following commands:')."\n\n";
                   2081:     } else {
1.45.2.12  raeburn  2082:         my $lcstop = '/etc/init.d/loncontrol stop';
                   2083:         if ($lc_uses_systemctl) {
                   2084:             $lcstop = 'systemctl stop loncontrol';
                   2085:         }
                   2086:         my $apachestop = "/etc/init.d/$apachename stop";
                   2087:         if ($uses_systemctl) {
                   2088:             $apachestop = "systemctl stop $apachename";
                   2089:         }
                   2090:         if ($uses_sudo) {
1.45.2.16  raeburn  2091:             $lcstop = 'sudo '.$lcstop;
1.45.2.12  raeburn  2092:             $apachestop = 'sudo '.$apachestop;
1.1       raeburn  2093:         }
1.45.2.12  raeburn  2094:         print &mt('If you are now ready to update LON-CAPA, enter the following commands:').
                   2095:               "\n\n$lcstop\n$apachestop\n";
1.1       raeburn  2096:     }
1.45.2.16  raeburn  2097:     my ($extract,$update);
                   2098:     my $homedir = '/root';
                   2099:     if ($uses_sudo) {
                   2100:         $extract = 'sudo ';
                   2101:         $update = 'sudo ';
                   2102:         if ($instdir ne $homedir) {
                   2103:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   2104:         }
                   2105:     }
                   2106:     $extract .= "tar zxf $sourcetarball --directory $homedir";
                   2107:     $update .= './UPDATE';
                   2108:     print "$extract\n".
                   2109:           "cd $homedir/$lcdir\n".
                   2110:           "$update\n";
1.1       raeburn  2111:     if (-e '/etc/loncapa-release') {
1.45.2.19  raeburn  2112:         my $lcstart = '/etc/init.d/loncontrol start';
1.45.2.12  raeburn  2113:         if ($lc_uses_systemctl) {
                   2114:             $lcstart = '/home/httpd/perl/loncontrol start';
                   2115:         }
                   2116:         my $apachestart = "/etc/init.d/$apachename start";
                   2117:         if ($uses_systemctl) {
                   2118:             $apachestart = "systemctl start $apachename";
                   2119:         }
                   2120:         if ($uses_sudo) {
                   2121:             $lcstart = 'sudo '.$lcstart;
                   2122:             $apachestart = 'sudo '.$apachestart;
                   2123:         }
                   2124:         print "$lcstart\n";
                   2125:         print "$apachestart\n";
1.1       raeburn  2126:     }
                   2127: }
                   2128: exit;
                   2129: 
                   2130: #
                   2131: # End main script
                   2132: #
                   2133: 
                   2134: #
                   2135: # Routines for the actions
                   2136: #
                   2137:  
                   2138: sub setup_www {
                   2139:     ##
                   2140:     ## Set up www
                   2141:     ##
                   2142:     print_and_log(&mt('Creating user [_1]',"'www'")."\n");
                   2143:     # -- Add group
                   2144: 
                   2145:     my $status = `/usr/sbin/groupadd www`;
                   2146:     if ($status =~ /\QGroup `www' already exists.\E/) {
                   2147:         print &mt('Group [_1] already exists.',"'www'")."\n";
                   2148:     } elsif ($status ne '') {
                   2149:         print &mt('Unable to add group [_1].',"'www'")."\n";
                   2150:     }
                   2151:    
                   2152:     my $gid = getgrnam('www');
                   2153: 
                   2154:     if (open (PIPE, "/usr/sbin/useradd -c LONCAPA -g $gid www 2>&1 |")) {
                   2155:         $status = <PIPE>;
                   2156:         close(PIPE);
                   2157:         chomp($status);
                   2158:         if ($status =~ /\QAccount `www' already exists.\E/) {
                   2159:             print &mt('Account [_1] already exists.',"'www'")."\n";
                   2160:         } elsif ($status ne '') {
                   2161:             print &mt('Unable to add user [_1].',"'www'")."\n";
                   2162:         }
                   2163:     }  else {
                   2164:         print &mt('Unable to run command to add user [_1].',"'www'")."\n";
                   2165:     }
                   2166: 
                   2167:     my $uid = &uid_of_www();
                   2168:     if (($gid ne '') && ($uid ne '')) {
                   2169:         if (!-e '/home/www') {
                   2170:             mkdir('/home/www',0755);
                   2171:             system('chown www:www /home/www');
                   2172:         }
                   2173:     }
                   2174:     writelog ($status);
                   2175: }
                   2176: 
                   2177: sub uid_of_www {
                   2178:     my ($num) = (getpwnam('www'))[2];
                   2179:     return $num;
                   2180: }
                   2181: 
                   2182: sub build_and_install_mod_auth_external {
                   2183:     my ($instdir) = @_;
                   2184:     my $num = &uid_of_www();
                   2185:     # Patch pwauth
                   2186:     print_and_log(&mt('Building authentication system for LON-CAPA users.')."\n");
                   2187:     my $patch = <<"ENDPATCH";
                   2188: 148c148
                   2189: < #define SERVER_UIDS 99		/* user "nobody" */
                   2190: ---
                   2191: > #define SERVER_UIDS $num		/* user "www" */
                   2192: ENDPATCH
                   2193: 
1.45.2.19  raeburn  2194:     my $patch_code = <<"ENDPATCH";
                   2195: 127a128
                   2196: > #include <string.h>
                   2197: 214a216
                   2198: > #include <time.h>
                   2199: 566c568
                   2200: < check_fails()
                   2201: ---
                   2202: > int check_fails()
                   2203: 589c591
                   2204: < log_failure()
                   2205: ---
                   2206: > void log_failure()
                   2207: 629c631
                   2208: < snooze(int seconds)
                   2209: ---
                   2210: > void snooze(int seconds)
                   2211: 653c655
                   2212: < main(int argc, char **argv)
                   2213: ---
                   2214: > int main(int argc, char **argv)
                   2215: ENDPATCH
                   2216: 
1.1       raeburn  2217:     if (! -e "/usr/bin/patch") {
                   2218: 	print_and_log(&mt('You must install the software development tools package: [_1], when installing Linux.',"'patch'")."\n");
                   2219:         print_and_log(&mt('Authentication installation not completed.')."\n");
                   2220:         return;
                   2221:     }
                   2222:     if (&skip_if_nonempty(`cd /tmp; tar zxf $instdir/pwauth-2.2.8.tar.gz`,
                   2223: 		     &mt('Unable to extract pwauth')."\n")) {
                   2224:         return;
                   2225:     }
                   2226:     my $dir = "/tmp/pwauth-2.2.8";
1.45.2.19  raeburn  2227:     my $patchedok;
1.1       raeburn  2228:     if (open(PATCH,"| patch $dir/config.h")) {
                   2229:         print PATCH $patch;
                   2230:         close(PATCH);
1.45.2.19  raeburn  2231:         if (open(PATCH,"| patch $dir/pwauth.c")) {
                   2232:             print PATCH $patch_code;
                   2233:             close(PATCH);
                   2234:             $patchedok = 1;
                   2235:         }
                   2236:     }
                   2237:     if ($patchedok) {
1.1       raeburn  2238:         print_and_log("\n");
                   2239:         ##
                   2240:         ## Compile patched pwauth
                   2241:         ##
                   2242:         print_and_log(&mt('Compiling pwauth')."\n");
1.12      raeburn  2243:         my $result = `cd $dir/; make 2>/dev/null `;
1.1       raeburn  2244:         my $expected = <<"END";
                   2245: gcc -g    -c -o pwauth.o pwauth.c
                   2246: gcc -o pwauth -g  pwauth.o -lcrypt
                   2247: END
                   2248:         if ($result eq $expected) {
                   2249:             print_and_log(&mt('Apparent success compiling pwauth:').
                   2250:                           "\n".$result );
                   2251:             # Install patched pwauth
                   2252:             print_and_log(&mt('Copying pwauth to [_1]',' /usr/local/sbin')."\n");
                   2253:             if (copy "$dir/pwauth","/usr/local/sbin/pwauth") {
1.5       raeburn  2254:                 if (chmod(06755, "/usr/local/sbin/pwauth")) {
1.1       raeburn  2255:                     print_and_log(&mt('[_1] copied successfully',"'pwauth'").
                   2256:                                   "\n");
                   2257:                 } else {
                   2258:                     print &mt('Unable to set permissions on [_1].'.
                   2259:                               "/usr/local/sbin/pwauth")."\n";
                   2260:                 }
                   2261:             } else {
                   2262:                 print &mt('Unable to copy [_1] to [_2]',
                   2263:                           "'$dir/pwauth'","/usr/local/sbin/pwauth")."\n$!\n";
                   2264:             }
                   2265:         } else {
                   2266:             print &mt('Unable to compile patched [_1].'."'pwauth'")."\n";
                   2267:         }
                   2268:     } else {
                   2269:         print &mt('Unable to start patch for [_1]',"'pwauth'")."\n";
                   2270:     }
                   2271:     print_and_log("\n");
                   2272: }
                   2273: 
                   2274: sub kill_extra_services {
1.45      raeburn  2275:     my ($distro,$stopsrvcs,$uses_systemctl) = @_;
1.1       raeburn  2276:     if (ref($stopsrvcs) eq 'HASH') {
                   2277:         my @stopping = sort(keys(%{$stopsrvcs}));
                   2278:         if (@stopping) {
1.6       raeburn  2279:             my $kill_list = join("', '",@stopping);
1.1       raeburn  2280:             if ($kill_list) {
                   2281:                 $kill_list = "'".$kill_list."'";
1.6       raeburn  2282:                 &print_and_log("\n".&mt('Killing unnecessary services ([_1] daemon(s)).',$kill_list)."\n");
                   2283:                 foreach my $service (@stopping) {
                   2284:                     my $daemon = $service;
                   2285:                     if ($service eq 'cups') {
                   2286:                         $daemon = 'cupsd';
                   2287:                         if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                   2288:                             my $version = $1;
                   2289:                             if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                   2290:                                 $daemon = 'cupsys';
                   2291:                             }
1.12      raeburn  2292:                         } else {
1.8       raeburn  2293:                             $daemon = 'cups';
1.6       raeburn  2294:                         }
                   2295:                     }
1.12      raeburn  2296:                     my $cmd = "ps -ef |grep '$daemon' |grep -v grep";
                   2297:                     if (open(PIPE,'-|',$cmd)) {
                   2298:                         my $daemonrunning = <PIPE>;
                   2299:                         chomp($daemonrunning);
                   2300:                         close(PIPE);
                   2301:                         if ($daemonrunning) {
                   2302:                             &print_and_log(`/etc/init.d/$daemon stop`);
                   2303:                         }
                   2304:                     }
1.1       raeburn  2305: 	            &print_and_log(&mt('Removing [_1] from startup.',$service)."\n");
1.45      raeburn  2306:                     if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                   2307:                         my $version = $1;
1.45.2.19  raeburn  2308:                         if ((($distro =~ /^ubuntu/) && ($version > 16)) ||
                   2309:                             (($distro =~ /^debian/) && ($version >= 10))) {
1.45      raeburn  2310:                             if (ref($uses_systemctl) eq 'HASH') {
                   2311:                                 if ($uses_systemctl->{$service}) {
                   2312:                                     if (`systemctl is-enabled $service`) {
                   2313:                                         &print_and_log(`systemctl disable $service`);
                   2314:                                     }
                   2315:                                 }
                   2316:                             }
                   2317:                         } else {
                   2318:                             &print_and_log(`update-rc.d -f $daemon remove`);
                   2319:                         }
1.1       raeburn  2320:                     } else {
1.35      raeburn  2321:                         if (ref($uses_systemctl) eq 'HASH') {
                   2322:                             if ($uses_systemctl->{$service}) {
                   2323:                                 if (`systemctl is-enabled $service`) {                          
                   2324:                                     &print_and_log(`systemctl disable $service`);
                   2325:                                 }
                   2326:                             } else {
                   2327:                                 &print_and_log(`/sbin/chkconfig --del $service`);
                   2328:                             }
                   2329:                         } else {
                   2330: 	                    &print_and_log(`/sbin/chkconfig --del $service`);
                   2331:                         } 
1.1       raeburn  2332:                     }
                   2333:                 }
                   2334:             }
                   2335:         }
                   2336:     }
                   2337:     return;
                   2338: }
                   2339: 
                   2340: sub setup_mysql {
1.45.2.15  raeburn  2341:     my ($setup_mysql_permissions,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$distro) = @_;
1.4       raeburn  2342:     my @mysql_lc_commands;
1.1       raeburn  2343:     unless ($has_lcdb) {
1.45.2.15  raeburn  2344:         my $createcmd = 'CREATE DATABASE loncapa';
                   2345:         if ($distro =~ /^sles(\d+)/) {
                   2346:             if ($1 > 11) {
                   2347:                 $createcmd .= ' CHARACTER SET utf8 COLLATE utf8_general_ci';
                   2348:             }
                   2349:         } elsif ($distro =~ /^ubuntu(\d+)/) {
                   2350:             if ($1 > 16) {
                   2351:                 $createcmd .= ' CHARACTER SET latin1 COLLATE latin1_swedish_ci';
                   2352:             }
                   2353:         }
                   2354:         push(@mysql_lc_commands,$createcmd);
1.1       raeburn  2355:     }
1.4       raeburn  2356:     push(@mysql_lc_commands,"USE loncapa");
                   2357:     push(@mysql_lc_commands,qq{
1.18      raeburn  2358: CREATE TABLE IF NOT EXISTS metadata (title TEXT, author TEXT, subject TEXT, url TEXT, keywords TEXT, version TEXT, notes TEXT, abstract TEXT, mime TEXT, language TEXT, creationdate DATETIME, lastrevisiondate DATETIME, owner TEXT, copyright TEXT, domain TEXT, dependencies TEXT, modifyinguser TEXT, authorspace TEXT, lowestgradelevel TEXT, highestgradelevel TEXT, standards TEXT, count INT, course INT, course_list TEXT, goto INT, goto_list TEXT, comefrom INT, comefrom_list TEXT, sequsage INT, sequsage_list TEXT, stdno INT, stdno_list TEXT, avetries FLOAT, avetries_list TEXT, difficulty FLOAT, difficulty_list TEXT, disc FLOAT, disc_list TEXT, clear FLOAT, technical FLOAT, correct FLOAT, helpful FLOAT, depth FLOAT, hostname TEXT, FULLTEXT idx_title (title), FULLTEXT idx_author (author), FULLTEXT idx_subject (subject), FULLTEXT idx_url (url), FULLTEXT idx_keywords (keywords), FULLTEXT idx_version (version), FULLTEXT idx_notes (notes), FULLTEXT idx_abstract (abstract), FULLTEXT idx_mime (mime), FULLTEXT idx_language (language), FULLTEXT idx_owner (owner), FULLTEXT idx_copyright (copyright)) ENGINE=MYISAM
1.4       raeburn  2359: });
1.1       raeburn  2360:     if ($setup_mysql_permissions) {
1.45.2.9  raeburn  2361:         &setup_mysql_permissions($dbh,$has_pass,$mysql_unix_socket,@mysql_lc_commands);
1.1       raeburn  2362:     } else {
                   2363:         print_and_log(&mt('Skipping MySQL permissions setup.')."\n");
                   2364:         if ($dbh) {
1.4       raeburn  2365:             if (@mysql_lc_commands) {
                   2366:                 foreach my $lccmd (@mysql_lc_commands) { 
                   2367:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2368:                 }
                   2369:             }
1.1       raeburn  2370:             print_and_log(&mt('MySQL database set up complete.')."\n");
                   2371:         } else {
                   2372:             print_and_log(&mt('Problem accessing MySQL.')."\n");
                   2373:         }
                   2374:     }
                   2375: }
                   2376: 
                   2377: sub setup_mysql_permissions {
1.45.2.9  raeburn  2378:     my ($dbh,$has_pass,$mysql_unix_socket,@mysql_lc_commands) = @_;
1.45.2.19  raeburn  2379:     my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version();
1.45.2.9  raeburn  2380:     my ($usescreate,$usesauth,$is_mariadb,$hasauthcol,@mysql_commands);
1.38      raeburn  2381:     if ($mysqlname =~ /^MariaDB/i) {
1.45.2.2  raeburn  2382:         $is_mariadb = 1;
1.45.2.19  raeburn  2383:         if ((($mysqlversion == 10) && ($mysqlminorversion >= 4)) || ($mysqlversion >= 11)) {
1.45.2.9  raeburn  2384:             $usescreate = 1;
1.45.2.19  raeburn  2385:         } elsif (($mysqlversion == 10) && ($mysqlminorversion >= 2)) {
1.38      raeburn  2386:             $usesauth = 1;
1.45.2.19  raeburn  2387:         } elsif (($mysqlversion == 5) && ($mysqlminorversion >= 5)) {
1.42      raeburn  2388:             $hasauthcol = 1;
1.38      raeburn  2389:         }
                   2390:     } else {
1.45.2.19  raeburn  2391:         if (($mysqlversion > 5) || (($mysqlminorversion == 5) && ($mysqlminorversion > 7)) ||
                   2392:             (($mysqlversion == 5) && ($mysqlminorversion == 7) && ($mysqlsubver > 5))) {
1.38      raeburn  2393:             $usesauth = 1;
1.45.2.19  raeburn  2394:         } elsif (($mysqlversion == 5) &&
                   2395:                  (($mysqlminorversion >= 6) || (($mysqlminorversion == 5) && ($mysqlsubver >= 7)))) {
1.42      raeburn  2396:             $hasauthcol = 1;
1.38      raeburn  2397:         }
                   2398:     }
1.45.2.9  raeburn  2399:     if ($usescreate) {
                   2400:         @mysql_commands = ("CREATE USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'");
                   2401:     } elsif ($usesauth) {
1.45.2.15  raeburn  2402:         @mysql_commands = ("INSERT user (Host, User, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www','','','','')",
                   2403:                            "FLUSH PRIVILEGES");
1.45.2.2  raeburn  2404:         if ($is_mariadb) {
                   2405:             push(@mysql_commands,"ALTER USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'");
                   2406:         } else {
                   2407:             push(@mysql_commands,"ALTER USER 'www'\@'localhost' IDENTIFIED WITH mysql_native_password BY 'localhostkey'");
                   2408:         }
1.42      raeburn  2409:     } elsif ($hasauthcol) {
                   2410:         @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www',password('localhostkey'),'','','','');");
1.36      raeburn  2411:     } else {
1.42      raeburn  2412:         @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject) VALUES('localhost','www',password('localhostkey'),'','','');");
1.36      raeburn  2413:     }
1.1       raeburn  2414:     if ($mysqlversion < 4) {
1.4       raeburn  2415:         push (@mysql_commands,"
                   2416: INSERT db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Grant_priv,References_priv,Index_priv,Alter_priv) VALUES('localhost','loncapa','www','Y','Y','Y','Y','Y','Y','N','Y','Y','Y')");
                   2417:     } else {
                   2418:         push (@mysql_commands,"
                   2419: INSERT db (Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Grant_priv,References_priv,Index_priv,Alter_priv,Create_tmp_table_priv,Lock_tables_priv) VALUES('localhost','loncapa','www','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y')");
1.1       raeburn  2420:     }
1.4       raeburn  2421:     push(@mysql_commands,"DELETE FROM user WHERE host<>'localhost'");
1.45.2.9  raeburn  2422:     if (($has_pass) || ($mysql_unix_socket)) {
1.1       raeburn  2423:         if ($dbh) {
1.4       raeburn  2424:             push(@mysql_commands,"FLUSH PRIVILEGES");
                   2425:             if (@mysql_commands) {
                   2426:                 foreach my $cmd (@mysql_commands) {
                   2427:                     $dbh->do($cmd) || print $dbh->errstr."\n";
                   2428:                 }
                   2429:             }
                   2430:             if (@mysql_lc_commands) {
                   2431:                 foreach my $lccmd (@mysql_lc_commands) {
                   2432:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2433:                 }
                   2434:             }
1.1       raeburn  2435:             print_and_log(&mt('Permissions set for LON-CAPA MySQL user: [_1]',"'www'")."\n");
                   2436:         } else {
                   2437:             print_and_log(&mt('Problem accessing MySQL.')."\n".
                   2438:                           &mt('Permissions not set.')."\n");
                   2439:         }
                   2440:     } else {
                   2441:         my ($firstpass,$secondpass,$got_passwd,$newmysqlpass);
                   2442:         print &mt('Please enter a root password for the mysql database.')."\n".
                   2443:               &mt('It does not have to match your root account password, but you will need to remember it.')."\n";
                   2444:         my $maxtries = 10;
                   2445:         my $trial = 0;
                   2446:         while ((!$got_passwd) && ($trial < $maxtries)) {
                   2447:             $firstpass = &get_mysql_password(&mt('Enter password'));
                   2448:             if (length($firstpass) > 5) { 
                   2449:                 $secondpass = &get_mysql_password(&mt('Enter password a second time'));
                   2450:                 if ($firstpass eq $secondpass) {
                   2451:                     $got_passwd = 1;
                   2452:                     $newmysqlpass = $firstpass;
                   2453:                 } else {
                   2454:                     print(&mt('Passwords did not match. Please try again.')."\n");
                   2455:                 }
                   2456:                 $trial ++;
                   2457:             } else {
                   2458:                 print(&mt('Password too short.')."\n".
                   2459:                       &mt('Please choose a password with at least six characters.')."\n");
                   2460:             }
                   2461:         }
                   2462:         if ($got_passwd) {
1.45.2.2  raeburn  2463:             my (@newpass_cmds) = &new_mysql_rootpasswd($newmysqlpass,$usesauth,$is_mariadb);
1.4       raeburn  2464:             push(@mysql_commands,@newpass_cmds);
1.1       raeburn  2465:         } else {
                   2466:             print_and_log(&mt('Failed to get MySQL root password from user input.')."\n");
                   2467:         }
                   2468:         if ($dbh) {
1.4       raeburn  2469:             if (@mysql_commands) {
                   2470:                 foreach my $cmd (@mysql_commands) {
                   2471:                     $dbh->do($cmd) || print $dbh->errstr."\n";
                   2472:                 }
                   2473:             }
                   2474:             if (@mysql_lc_commands) {
                   2475:                 foreach my $lccmd (@mysql_lc_commands) {
                   2476:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2477:                 }
                   2478:             }
1.1       raeburn  2479:             if ($got_passwd) {
                   2480:                 print_and_log(&mt('MySQL root password stored.')."\n".
                   2481:                               &mt('Permissions set for LON-CAPA MySQL user: [_1].',"'www'")."\n");
                   2482:             } else {
                   2483:                 print_and_log(&mt('Permissions set for LON-CAPA MySQL user: [_1].',"'www'")."\n");
                   2484:             }
                   2485:         } else {
                   2486:             print_and_log(&mt('Problem accessing MySQL.')."\n".
                   2487:                           &mt('Permissions not set.')."\n");
                   2488:         }
                   2489:     }
                   2490: }
                   2491: 
                   2492: sub new_mysql_rootpasswd {
1.45.2.2  raeburn  2493:     my ($currmysqlpass,$usesauth,$is_mariadb) = @_;
1.36      raeburn  2494:     if ($usesauth) {
1.45.2.2  raeburn  2495:         if ($is_mariadb) {
                   2496:             return ("ALTER USER 'root'\@'localhost' IDENTIFIED BY '$currmysqlpass'",
                   2497:                     "FLUSH PRIVILEGES;");
                   2498:         } else {
                   2499:             return ("ALTER USER 'root'\@'localhost' IDENTIFIED WITH mysql_native_password BY '$currmysqlpass'",
                   2500:                     "FLUSH PRIVILEGES;");
                   2501:         }
1.36      raeburn  2502:     } else {
                   2503:         return ("SET PASSWORD FOR 'root'\@'localhost'=PASSWORD('$currmysqlpass')",
                   2504:                 "FLUSH PRIVILEGES;");
                   2505:     }
1.1       raeburn  2506: }
                   2507: 
                   2508: sub get_mysql_version {
1.45.2.19  raeburn  2509:     my ($version,$minorversion,$subversion,$name);
1.1       raeburn  2510:     if (open(PIPE," mysql -V |")) {
                   2511:         my $info = <PIPE>;
                   2512:         chomp($info);
                   2513:         close(PIPE);
1.45.2.19  raeburn  2514:         ($version,$minorversion,$subversion,$name) = ($info =~ /(\d+)\.(\d+)\.(\d+)(?:\-?(\w*),|)/);
1.1       raeburn  2515:     } else {
                   2516:         print &mt('Could not determine which version of MySQL is installed.').
                   2517:               "\n";
                   2518:     }
1.45.2.19  raeburn  2519:     return ($version,$minorversion,$subversion,$name);
1.1       raeburn  2520: }
                   2521: 
1.45.2.20  raeburn  2522: sub check_systemd_update {
                   2523:     my ($distro) = @_;
                   2524:     my ($use_systemctl,$service);
                   2525:     $service = 'apache2.service';
                   2526:     if ($distro =~ /^ubuntu(\w+)/) {
                   2527:         if ($1 >= 16) {
                   2528:             $use_systemctl = 1;
                   2529:         }
                   2530:     } elsif ($distro =~ /^debian(\w+)/) {
                   2531:         if ($1 >= 9) {
                   2532:             $use_systemctl = 1;
                   2533:         }
                   2534:     } elsif ($distro =~ /^fedora(\d+)/) {
                   2535:         $service = 'httpd.service';
                   2536:         if ($1 >= 16) {
                   2537:             $use_systemctl = 1;
                   2538:         }
                   2539:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
                   2540:         $service = 'httpd.service';
                   2541:         if ($1 >= 7) {
                   2542:             $use_systemctl = 1;
                   2543:         }
                   2544:     } elsif ($distro =~ /^sles(\d+)/) {
                   2545:         if ($1 >= 12) {
                   2546:             $use_systemctl = 1;
                   2547:         }
                   2548:     } elsif ($distro =~ /^suse(\d+)/) {
                   2549:         if ($1 >= 13) {
                   2550:             $use_systemctl = 1;
                   2551:         }
                   2552:     }
                   2553:     if ($use_systemctl) {
                   2554:         my $needsupdate = &check_systemd_security($distro);
                   2555:         if ($needsupdate) {
                   2556:             if (!-d '/etc/systemd/system/'.$service.'.d') {
                   2557:                 mkdir '/etc/systemd/system/'.$service.'.d', 0755;
                   2558:             }
                   2559:             if (-d '/etc/systemd/system/'.$service.'.d') {
                   2560:                 if (-e '/etc/systemd/system/'.$service.'.d/override.conf') {
                   2561:                     if (open(my $fh,'<','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2562:                         my ($inservice,$addservice,$protectoff,$linenum,$change,@lines);
                   2563:                         while (my $entry = <$fh>) {
                   2564:                             $linenum ++;
                   2565:                             chomp($entry);
                   2566:                             if ($entry eq '[Service]') {
                   2567:                                 if (!$protectoff) {
                   2568:                                     $inservice = $linenum;
                   2569:                                     push(@lines,$entry);
                   2570:                                 } else {
                   2571:                                     $addservice = 1;
                   2572:                                     next;
                   2573:                                 }
                   2574:                             }
                   2575:                             if ($entry =~ /^ProtectHome\s*=\s*([\w-]+)\s*$/) {
                   2576:                                 my $value = $1;
                   2577:                                 if ($protectoff) {
                   2578:                                     next;
                   2579:                                     if (lc($value) eq 'no') {
                   2580:                                         $protectoff = $linenum;
                   2581:                                         push(@lines,$entry);
                   2582:                                     } else {
                   2583:                                         if ($protectoff) {
                   2584:                                             next;
                   2585:                                         } else {
                   2586:                                             push(@lines,'ProtectHome=no');
                   2587:                                             $protectoff = $linenum;
                   2588:                                             $change = $linenum;
                   2589:                                         }
                   2590:                                     }
                   2591:                                 }
                   2592:                             }
                   2593:                         }
                   2594:                         close($fh);
                   2595:                         if ($addservice || $change || !$protectoff) {
                   2596:                             if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2597:                                 if ($addservice) {
                   2598:                                     print $fh "[Service]\n";
                   2599:                                 }
                   2600:                                 foreach my $entry (@lines) {
                   2601:                                     print $fh "$entry\n";
                   2602:                                 }
                   2603:                                 close($fh);
                   2604:                                 print_and_log('Updated /etc/systemd/system/'.$service.'.d/override.conf');
1.45.2.21  raeburn  2605:                                 system('systemctl daemon-reload');
1.45.2.20  raeburn  2606:                             } else {
                   2607:                                 print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for writing.');
                   2608:                             }
                   2609:                         } else {
                   2610:                             print_and_log('No change needed in /etc/systemd/system/'.$service.'.d/override.conf');
                   2611:                         }
                   2612:                     } else {
                   2613:                         print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for reading.');
                   2614:                     }
                   2615:                 } else {
                   2616:                     if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2617:                         print $fh '[Service]'."\n".'ProtectHome=no'."\n";
                   2618:                         close($fh);
                   2619:                         print_and_log('Created /etc/systemd/system/'.$service.'.d/override.conf');
1.45.2.21  raeburn  2620:                         system('systemctl daemon-reload');
1.45.2.20  raeburn  2621:                     }
                   2622:                 }
                   2623:             } else {
                   2624:                 print_and_log('No /etc/systemd/system/'.$service.'.d directory exists and creating one failed,');
                   2625:             }
                   2626:         } else {
                   2627:             print_and_log('No update needed to systemd security settings for Apache web server.');
                   2628:         }
                   2629:     } else {
                   2630:         print_and_log('No update needed to systemd, as this Linux distro does not use systemctl');
                   2631:     }
                   2632: }
                   2633: 
1.1       raeburn  2634: ###########################################################
                   2635: ##
                   2636: ## RHEL/CentOS/Fedora/Scientific Linux
                   2637: ## Copy LON-CAPA httpd.conf to /etc/httpd/conf
                   2638: ##
                   2639: ###########################################################
                   2640: 
                   2641: sub copy_httpd_conf {
1.14      raeburn  2642:     my ($instdir,$distro) = @_;
                   2643:     my $configfile = 'httpd.conf';
1.45.2.18  raeburn  2644:     if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn  2645:         if ($1 >= 7) {
                   2646:             $configfile = 'apache2.4/httpd.conf';
                   2647:         } elsif ($1 > 5) {
1.14      raeburn  2648:             $configfile = 'new/httpd.conf';
                   2649:         }
                   2650:     } elsif ($distro =~ /^fedora(\d+)$/) {
1.29      raeburn  2651:         if ($1 > 17) {
                   2652:             $configfile = 'apache2.4/httpd.conf';
                   2653:         } elsif ($1 > 10) {
1.14      raeburn  2654:             $configfile = 'new/httpd.conf';
                   2655:         }
                   2656:     }
1.1       raeburn  2657:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'httpd.conf'",
                   2658:                   "'/etc/httpd/conf/httpd.conf'")."\n");
                   2659:     copy "/etc/httpd/conf/httpd.conf","/etc/httpd/conf/httpd.conf.original";
1.14      raeburn  2660:     copy "$instdir/centos-rhes-fedora-sl/$configfile","/etc/httpd/conf/httpd.conf";
1.5       raeburn  2661:     chmod(0444,"/etc/httpd/conf/httpd.conf");
1.1       raeburn  2662:     print_and_log("\n");
                   2663: }
                   2664: 
1.45.2.5  raeburn  2665: ###########################################################
                   2666: ##
                   2667: ## RHEL/CentOS/Fedora/Scientific Linux
                   2668: ## Copy LON-CAPA mpm.conf to /etc/httpd/conf.modules.d/00-mpm.conf
                   2669: ##
                   2670: ## The LON-CAPA mpm.conf enables the prefork MPM module in
                   2671: ## Apache. This is also the default for RHEL/CentOS/Oracle
                   2672: ## Linux 7 and earlier, and Fedora 26 and earlier. For more
                   2673: ## recent versions of those distros, the event MPM is enabled
                   2674: ## by default. After &copy_mpm_conf() is run, the prefork MPM
                   2675: ## module will be enabled instead of the event MPM module.
                   2676: ##
                   2677: ###########################################################
                   2678: 
                   2679: sub copy_mpm_conf {
                   2680:     my ($instdir,$distro) = @_;
                   2681:     my $mpmfile = 'mpm.conf';
                   2682:     if ((-e "/etc/httpd/conf.modules.d/00-mpm.conf") &&
                   2683:         (-e "$instdir/centos-rhes-fedora-sl/$mpmfile")) {
                   2684:         print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'mpm.conf'",
                   2685:                       "'/etc/httpd/conf.modules.d/00-mpm.conf'")."\n");
                   2686:         copy "$instdir/centos-rhes-fedora-sl/$mpmfile","/etc/httpd/conf.modules.d/00-mpm.conf";
                   2687:         chmod(0644,"/etc/httpd/conf.modules.d/00-mpm.conf");
                   2688:         print_and_log("\n");
                   2689:     } else {
                   2690:         my $logfail;
1.45.2.18  raeburn  2691:         if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.45.2.5  raeburn  2692:             if ($1 > 7) {
                   2693:                 $logfail = 1;
                   2694:             }
                   2695:         } elsif ($distro =~ /^fedora(\d+)$/) {
                   2696:             if ($1 > 26) {
                   2697:                 $logfail = 1;
                   2698:             }
                   2699:         }
                   2700:         if ($logfail) {
                   2701:             print_and_log(&mt('Warning: copying the LON-CAPA [_1] failed because [_2] and/or [_3] are missing.',
                   2702:                               $mpmfile,"'$instdir/centos-rhes-fedora-sl/$mpmfile'",
                   2703:                               "'/etc/httpd/conf.modules.d/00-mpm.conf'"));
                   2704:             print_and_log("\n");
                   2705:         }
                   2706:     }
                   2707: }
                   2708: 
1.1       raeburn  2709: #########################################################
                   2710: ##
1.17      raeburn  2711: ## Ubuntu/Debian -- copy our loncapa configuration file to
1.1       raeburn  2712: ## sites-available and set the symlink from sites-enabled.
                   2713: ##
                   2714: #########################################################
                   2715: 
                   2716: sub copy_apache2_debconf {
1.28      raeburn  2717:     my ($instdir,$distro) = @_;
1.6       raeburn  2718:     my $apache2_mods_enabled_dir = '/etc/apache2/mods-enabled';
                   2719:     my $apache2_mods_available_dir = '/etc/apache2/mods-available';
                   2720:     foreach my $module ('headers.load','expires.load') {
                   2721:         unless (-l "$apache2_mods_enabled_dir/$module") {
                   2722:             symlink("$apache2_mods_available_dir/$module","$apache2_mods_enabled_dir/$module");
                   2723:             print_and_log(&mt('Enabling "[_1]" Apache module.',$module)."\n");
                   2724:         }
                   2725:     }
1.28      raeburn  2726:     my $apache2_sites_enabled_dir = '/etc/apache2/sites-enabled';
                   2727:     my $apache2_sites_available_dir = '/etc/apache2/sites-available';
                   2728:     my $defaultconfig = "$apache2_sites_enabled_dir/000-default";
1.45.2.10  raeburn  2729:     my $defaultsite = "$apache2_sites_enabled_dir/loncapa.conf";
1.28      raeburn  2730:     my ($distname,$version);
                   2731:     if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
                   2732:         $distname = $1;
                   2733:         $version = $2;
                   2734:     }
1.45.2.19  raeburn  2735:     if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   2736:         (($distname eq 'debian') && ($version >= 10))) {
1.28      raeburn  2737:         $defaultconfig = "$apache2_sites_enabled_dir/000-default.conf";
                   2738:     }
1.45.2.7  raeburn  2739:     my ($skipconf,$skipsite,$skipstatus);
1.45.2.19  raeburn  2740:     if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   2741:         (($distname eq 'debian') && ($version >= 10))) {
1.28      raeburn  2742:         my $apache2_conf_enabled_dir = '/etc/apache2/conf-enabled';
                   2743:         my $apache2_conf_available_dir = '/etc/apache2/conf-available';
1.33      raeburn  2744:         my $defaultconf = $apache2_conf_enabled_dir.'/loncapa.conf';
1.45.2.7  raeburn  2745:         if ((-e "$apache2_conf_available_dir/loncapa") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
1.45.2.8  raeburn  2746:             if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
1.45.2.7  raeburn  2747:                 my $diffres = <PIPE>;
                   2748:                 close(PIPE);
                   2749:                 chomp($diffres);
                   2750:                 if ($diffres) {
1.45.2.10  raeburn  2751:                     copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf.original");
                   2752:                 } else {
                   2753:                     copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf");
1.45.2.11  raeburn  2754:                     chdir($apache2_conf_enabled_dir);
                   2755:                     symlink('../conf-available/loncapa.conf','loncapa.conf');
                   2756:                     chdir($instdir);
1.45.2.7  raeburn  2757:                 }
                   2758:                 if (-l $defaultconf) {
                   2759:                     my $linkfname = readlink($defaultconf);
1.45.2.11  raeburn  2760:                     if ($linkfname ne '') {
                   2761:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
                   2762:                     }
1.45.2.7  raeburn  2763:                     if ($linkfname eq "$apache2_conf_available_dir/loncapa") {
1.45.2.10  raeburn  2764:                         unlink($defaultconf);
                   2765:                     }
                   2766:                 }
                   2767:                 unlink("$apache2_conf_available_dir/loncapa");
                   2768:             }
                   2769:         }
                   2770:         if ((-e "$apache2_conf_available_dir/loncapa.conf") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
                   2771:             if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa.conf $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
                   2772:                 my $diffres = <PIPE>;
                   2773:                 close(PIPE);
                   2774:                 chomp($diffres);
                   2775:                 if ($diffres) {
                   2776:                     copy("$apache2_conf_available_dir/loncapa.conf","$apache2_conf_available_dir/loncapa.conf.original");
                   2777:                 }
                   2778:                 if (-l $defaultconf) {
                   2779:                     my $linkfname = readlink($defaultconf);
1.45.2.11  raeburn  2780:                     if ($linkfname ne '') {
                   2781:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
                   2782:                     }
1.45.2.10  raeburn  2783:                     if ($linkfname eq "$apache2_conf_available_dir/loncapa.conf") {
1.45.2.7  raeburn  2784:                         unless ($diffres) {
                   2785:                             $skipconf = 1;
                   2786:                         }
                   2787:                     }
                   2788:                 }
                   2789:             }
                   2790:         }
                   2791:         unless ($skipconf) {
                   2792:             print_and_log(&mt('Copying loncapa [_1] config file to [_2] and pointing [_3] to it from conf-enabled.',"'apache2'","'/etc/apache2/conf-available'","'loncapa.conf symlink'")."\n");
1.45.2.10  raeburn  2793:             copy("$instdir/debian-ubuntu/ubuntu14/loncapa_conf","$apache2_conf_available_dir/loncapa.conf");
                   2794:             chmod(0444,"$apache2_conf_available_dir/loncapa.conf");
1.45.2.7  raeburn  2795:             if (-l $defaultconf) {
                   2796:                 unlink($defaultconf);
                   2797:             }
1.45.2.11  raeburn  2798:             chdir($apache2_conf_enabled_dir);
                   2799:             symlink('../conf-available/loncapa.conf','loncapa.conf');
                   2800:             chdir($instdir);
1.45.2.7  raeburn  2801:         }
                   2802:         my $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_site";
                   2803:         if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa")) {
                   2804:             if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa |")) {
                   2805:                 my $diffres = <PIPE>;
                   2806:                 close(PIPE);
                   2807:                 chomp($diffres);
                   2808:                 if ($diffres) {
1.45.2.10  raeburn  2809:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf.original");
                   2810:                 } else {
                   2811:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf");
1.45.2.7  raeburn  2812:                 }
                   2813:                 if (-l $defaultconfig) {
                   2814:                     my $linkfname = readlink($defaultconfig);
1.45.2.11  raeburn  2815:                     if ($linkfname ne '') {
                   2816:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2817:                     }
1.45.2.7  raeburn  2818:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
1.45.2.10  raeburn  2819:                         unlink($defaultconfig);
                   2820:                     }
                   2821:                 }
                   2822:                 unlink("$apache2_sites_available_dir/loncapa");
                   2823:             }
                   2824:         }
                   2825:         if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa.conf")) {
                   2826:             if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa.conf |")) {
                   2827:                 my $diffres = <PIPE>;
                   2828:                 close(PIPE);
                   2829:                 chomp($diffres);
                   2830:                 if ($diffres) {
                   2831:                     copy("$apache2_sites_available_dir/loncapa.conf","$apache2_sites_available_dir/loncapa.conf.original");
                   2832:                 }
                   2833:                 if (-l $defaultsite) {
                   2834:                     my $linkfname = readlink($defaultsite);
1.45.2.11  raeburn  2835:                     if ($linkfname ne '') {
                   2836:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2837:                     }
                   2838:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa.conf") {
1.45.2.7  raeburn  2839:                         unless ($diffres) {
                   2840:                             $skipsite = 1;
                   2841:                         }
                   2842:                     }
                   2843:                 }
                   2844:             }
                   2845:         }
                   2846:         unless ($skipsite) {
1.45.2.10  raeburn  2847:             print_and_log(&mt('Copying loncapa [_1] site file to [_2] and pointing [_3] to it from sites-enabled.',"'apache2'","'/etc/apache2/sites-available'","'loncapa.conf symlink'")."\n");
                   2848:             copy("$instdir/debian-ubuntu/ubuntu14/loncapa_site","$apache2_sites_available_dir/loncapa.conf");
                   2849:             chmod(0444,"$apache2_sites_available_dir/loncapa.conf");
1.45.2.11  raeburn  2850:             chdir($apache2_sites_enabled_dir);
                   2851:             symlink('../sites-available/loncapa.conf','loncapa.conf');
                   2852:             chdir($instdir);
1.45.2.10  raeburn  2853:         }
1.45.2.11  raeburn  2854:         if (-l $defaultconfig) {
1.45.2.10  raeburn  2855:             my $linkfname = readlink($defaultconfig);
1.45.2.11  raeburn  2856:             if ($linkfname ne '') {
                   2857:                 $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2858:             }
                   2859:             if ($linkfname eq "$apache2_sites_available_dir/000-default.conf") {
1.45.2.10  raeburn  2860:                 unlink($defaultconfig);
                   2861:             }
1.45.2.7  raeburn  2862:         }
                   2863:     } else {
                   2864:         if ((-e "$instdir/debian-ubuntu/loncapa") && (-e "$apache2_sites_available_dir/loncapa")) {
                   2865:             if (open(PIPE, "diff --brief $instdir/debian-ubuntu/loncapa $apache2_sites_available_dir/loncapa |")) {
                   2866:                 my $diffres = <PIPE>;
                   2867:                 close(PIPE);
                   2868:                 chomp($diffres);
                   2869:                 if ($diffres) {
                   2870:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.original");
                   2871:                 }
                   2872:                 if (-l $defaultconfig) {
                   2873:                     my $linkfname = readlink($defaultconfig);
                   2874:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
                   2875:                         unless ($diffres) {
                   2876:                             $skipsite = 1;
                   2877:                         }
                   2878:                     }
                   2879:                 }
                   2880:             }
                   2881:         }
                   2882:         unless ($skipsite) {
                   2883:             if (-l $defaultconfig) {
                   2884:                 unlink($defaultconfig);
                   2885:             }
                   2886:             print_and_log(&mt('Copying loncapa [_1] config file to [_2] and pointing [_3] to it from sites-enabled.',"'apache2'","'/etc/apache2/sites-available'","'000-default symlink'")."\n");
                   2887:             if (-e "$instdir/debian-ubuntu/loncapa") {
                   2888:                 copy("$instdir/debian-ubuntu/loncapa","$apache2_sites_available_dir/loncapa");
                   2889:                 chmod(0444,"$apache2_sites_available_dir/loncapa");
                   2890:                 symlink("$apache2_sites_available_dir/loncapa","$apache2_sites_enabled_dir/000-default");
                   2891:             }
                   2892:         }
                   2893:     }
1.45.2.19  raeburn  2894:     if (($distname eq 'ubuntu') || ($distname eq 'debian')) {
1.45.2.7  raeburn  2895:         my $sitestatus = "$apache2_mods_available_dir/status.conf";
                   2896:         my $stdstatus = "$instdir/debian-ubuntu/status.conf";
                   2897:         if ((-e $sitestatus) && (-e $stdstatus)) {
                   2898:             if (open(PIPE, "diff --brief $stdstatus $sitestatus |")) {
                   2899:                 my $diffres = <PIPE>;
                   2900:                 close(PIPE);
                   2901:                 chomp($diffres);
                   2902:                 if ($diffres) {
                   2903:                     copy("$apache2_mods_available_dir/status.conf","$apache2_mods_available_dir/status.conf.original");
                   2904:                 } else {
                   2905:                     $skipstatus = 1;
                   2906:                 }
                   2907:             }
                   2908:         }
                   2909:         unless ($skipstatus) {
                   2910:             if (-e $stdstatus) {
                   2911:                 print_and_log(&mt('Copying loncapa [_1] file to [_2],',"'status.conf'","'/etc/apache2/mods-available/status.conf'")."\n");
                   2912:                 copy($stdstatus,$sitestatus);
                   2913:                 chmod(0644,$sitestatus);
                   2914:             }
                   2915:         }
1.28      raeburn  2916:     }
1.1       raeburn  2917:     print_and_log("\n");
                   2918: }
                   2919: 
                   2920: ###########################################################
                   2921: ##
                   2922: ## openSuSE/SLES Copy apache2 config files:
                   2923: ##   default-server.conf, uid.conf, /etc/sysconfig/apache2 
                   2924: ##   and create symlink from /srv/www/conf to /etc/apache2 
                   2925: ##
                   2926: ###########################################################
                   2927: 
                   2928: sub copy_apache2_suseconf {
1.45.2.1  raeburn  2929:     my ($instdir,$distro) = @_;
                   2930:     my ($name,$version) = ($distro =~ /^(suse|sles)([\d\.]+)$/);
                   2931:     my $conf_file = "$instdir/sles-suse/default-server.conf";
                   2932:     if (($name eq 'sles') && ($version >= 12)) {
                   2933:         $conf_file = "$instdir/sles-suse/apache2.4/default-server.conf";
                   2934:     }
1.1       raeburn  2935:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
                   2936:                   "'default-server.conf'",
                   2937:                   "'/etc/apache2/default-server.conf'")."\n");
                   2938:     if (!-e "/etc/apache2/default-server.conf.original") {
                   2939:         copy "/etc/apache2/default-server.conf","/etc/apache2/default-server.conf.original";
                   2940:     }
1.45.2.1  raeburn  2941:     copy $conf_file,"/etc/apache2/default-server.conf";
1.5       raeburn  2942:     chmod(0444,"/etc/apache2/default-server.conf");
1.1       raeburn  2943:     # Make symlink for conf directory (included in loncapa_apache.conf)
                   2944:     my $can_symlink = (eval { symlink('/etc/apache2','/srv/www/conf'); }, $@ eq '');
                   2945:     if ($can_symlink) {
                   2946:         &print_and_log(&mt('Symlink created for [_1] to [_2].',
                   2947:                        "'/srv/www/conf'","'/etc/apache2'")."\n");
                   2948:     } else {
                   2949:         &print_and_log(&mt('Symlink creation failed for [_1] to [_2]. You will need to perform this action from the command line.',"'/srv/www/conf'","'/etc/apache2'")."\n");
                   2950:     }
                   2951:     &copy_apache2_conf_files($instdir);
1.45.2.1  raeburn  2952:     &copy_sysconfig_apache2_file($instdir,$name,$version); 
1.1       raeburn  2953:     print_and_log("\n");
                   2954: }
                   2955: 
                   2956: ###############################################
                   2957: ##
                   2958: ## Modify uid.conf
                   2959: ##
                   2960: ###############################################
                   2961: sub copy_apache2_conf_files {
                   2962:     my ($instdir) = @_;
                   2963:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
                   2964:                   "'uid.conf'","'/etc/apache2/uid.conf'")."\n");
                   2965:     if (!-e "/etc/apache2/uid.conf.original") {
                   2966:         copy "/etc/apache2/uid.conf","/etc/apache2/uid.conf.original";
                   2967:     }
1.9       raeburn  2968:     copy "$instdir/sles-suse/uid.conf","/etc/apache2/uid.conf";
1.5       raeburn  2969:     chmod(0444,"/etc/apache2/uid.conf");
1.1       raeburn  2970: }
                   2971: 
                   2972: ###############################################
                   2973: ##
                   2974: ## Modify /etc/sysconfig/apache2  
                   2975: ##
                   2976: ###############################################
                   2977: sub copy_sysconfig_apache2_file {
1.45.2.1  raeburn  2978:     my ($instdir,$name,$version) = @_;
1.1       raeburn  2979:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'sysconfig/apache2'","'/etc/sysconfig/apache2'")."\n");
                   2980:     if (!-e "/etc/sysconfig/apache2.original") {
                   2981:         copy "/etc/sysconfig/apache2","/etc/sysconfig/apache2.original";
                   2982:     }
1.45.2.1  raeburn  2983:     my $sysconf_file = "$instdir/sles-suse/sysconfig_apache2";
                   2984:     if (($name eq 'sles') && ($version >= 12)) {
                   2985:        $sysconf_file = "$instdir/sles-suse/apache2.4/sysconfig_apache2";
                   2986:     }
                   2987:     copy $sysconf_file,"/etc/sysconfig/apache2";
1.5       raeburn  2988:     chmod(0444,"/etc/sysconfig/apache2");
1.1       raeburn  2989: }
                   2990: 
                   2991: ###############################################
                   2992: ##
                   2993: ## Add/Modify /etc/insserv/overrides
                   2994: ##
                   2995: ###############################################
                   2996: 
                   2997: sub update_SuSEfirewall2_setup {
                   2998:     my ($instdir) = @_;
                   2999:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'SuSEfirewall2_setup'","'/etc/insserv/overrides/SuSEfirewall2_setup'")."\n");
                   3000:     if (!-e "/etc/insserv/overrides/SuSEfirewall2_setup") {
                   3001:         if (!-d "/etc/insserv") {
                   3002:             mkdir("/etc/insserv",0755); 
                   3003:         }
                   3004:         if (!-d "/etc/insserv/overrides") {
                   3005:             mkdir("/etc/insserv/overrides",0755);
                   3006:         }
                   3007:     } elsif (!-e  "/etc/insserv/overrides/SuSEfirewall2_setup.original") {
                   3008:         copy "/etc/insserv/overrides/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup.original"
                   3009:     }
1.9       raeburn  3010:     copy "$instdir/sles-suse/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup";
1.5       raeburn  3011:     chmod(0444,"/etc/insserv/overrides/SuSEfirewall2_setup");
                   3012: }
                   3013: 
                   3014: sub get_iptables_rules {
                   3015:     my ($distro,$instdir,$apachefw) = @_;
                   3016:     my (@fwchains,@ports);
                   3017:     if (&firewall_is_active()) {
                   3018:         my $iptables = &get_pathto_iptables();
                   3019:         if ($iptables ne '') {
                   3020:             @fwchains = &get_fw_chains($iptables,$distro);
                   3021:         }
                   3022:     }
                   3023:     if (ref($apachefw) eq 'HASH') {
                   3024:         foreach my $service ('http','https') {
                   3025:             unless ($apachefw->{$service}) {
                   3026:                 push (@ports,$service); 
                   3027:             }
                   3028:         }
                   3029:     } else {
                   3030:         @ports = ('http','https');
                   3031:     }
                   3032:     if (@ports == 0) {
                   3033:         return;
                   3034:     }
                   3035:     my $ask_to_enable;
                   3036:     if (-e "/etc/iptables.loncapa.rules") {
1.9       raeburn  3037:         if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables.loncapa.rules /etc/iptables.loncapa.rules |")) {
1.5       raeburn  3038:             my $diffres = <PIPE>;
                   3039:             close(PIPE);
                   3040:             chomp($diffres);
                   3041:             if ($diffres) {
                   3042:                 print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
                   3043:             }
                   3044:         } else {
                   3045:             print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
                   3046:         }
                   3047:     } else {
1.9       raeburn  3048:         if (-e "$instdir/debian-ubuntu/iptables.loncapa.rules") {
                   3049:             copy "$instdir/debian-ubuntu/iptables.loncapa.rules","/etc/iptables.loncapa.rules";
1.5       raeburn  3050:             chmod(0600,"/etc/iptables.loncapa.rules");
                   3051:         }
                   3052:     }
                   3053:     if (-e "/etc/iptables.loncapa.rules") {
                   3054:         if (-e "/etc/network/if-pre-up.d/iptables") {
1.9       raeburn  3055:             if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables /etc/network/if-pre-up/iptables |")) {
1.5       raeburn  3056:                 my $diffres = <PIPE>;
                   3057:                 close(PIPE);
                   3058:                 chomp($diffres);
                   3059:                 if ($diffres) {
                   3060:                     print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
                   3061:                 }
                   3062:             } else {
                   3063:                 print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
                   3064:             }
                   3065:         } else {
1.9       raeburn  3066:             copy "$instdir/debian-ubuntu/iptables","/etc/network/if-pre-up.d/iptables";
1.5       raeburn  3067:             chmod(0755,"/etc/network/if-pre-up.d/iptables");
                   3068:             print_and_log(&mt('Installed script "[_1]" to add iptables rules to block all ports except 22, 80, and 443 when network is enabled during boot.','/etc/network/if-pre-up.d/iptables'));
                   3069:             $ask_to_enable = 1;
                   3070:         }
                   3071:     }
                   3072:     return $ask_to_enable;
1.1       raeburn  3073: }
                   3074: 
                   3075: sub download_loncapa {
                   3076:     my ($instdir,$lctarball) = @_;
                   3077:     my ($have_tarball,$updateshown);
                   3078:     if (! -e "$instdir/$lctarball") {
                   3079: 	print_and_log(&mt('Retrieving LON-CAPA source files from: [_1]',
                   3080: 		      'http://install.loncapa.org')."\n");
                   3081: 	system("wget http://install.loncapa.org/versions/$lctarball ".
                   3082: 	       "2>/dev/null 1>/dev/null");
                   3083: 	if (! -e "./$lctarball") {
                   3084: 	    print &mt('Unable to retrieve LON-CAPA source files from: [_1].', 
                   3085: 		     "http://install.loncapa.org/versions/$lctarball")."\n";
                   3086: 	} else {
                   3087:             $have_tarball = 1;
                   3088:         }
                   3089: 	print_and_log("\n");
                   3090:     } else {
                   3091:         $have_tarball = 1;
                   3092: 	print_and_log("
                   3093: ------------------------------------------------------------------------
                   3094: 
1.45.2.16  raeburn  3095: ".&mt('You seem to have a version of [_1] in [_2]',$lctarball,$instdir)."\n".
1.1       raeburn  3096: &mt('This copy will be used and a new version will NOT be downloaded.')."\n".
                   3097: &mt('If you wish, you may download a new version by executing:')."
                   3098: 
1.45.2.16  raeburn  3099: wget http://install.loncapa.org/versions/$lctarball
1.1       raeburn  3100: 
                   3101: ------------------------------------------------------------------------
                   3102: ");
                   3103:     }
                   3104: 
                   3105:     ##
1.45.2.16  raeburn  3106:     ## untar loncapa-X.Y.Z.tar.gz
1.1       raeburn  3107:     ##
                   3108:     if ($have_tarball) {
1.45.2.16  raeburn  3109:         my $homedir = '/root';
                   3110:         my ($targetdir,$chdircmd,$updatecmd);
                   3111:         if (($distro =~ /^ubuntu/) && ($instdir ne $homedir)) {
                   3112:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   3113:             $updatecmd = 'sudo ./UPDATE';
                   3114:         } else {
                   3115:             $updatecmd = './UPDATE';
                   3116:         }
1.1       raeburn  3117:         print_and_log(&mt('Extracting LON-CAPA source files')."\n");
1.45.2.16  raeburn  3118:         if (-e $homedir) {
                   3119:             writelog(`tar zxf $instdir/$lctarball --directory $homedir`);
                   3120:             $targetdir = $homedir;
                   3121:         } else {
                   3122:             writelog(`tar zxf $instdir/$lctarball`);
                   3123:             $targetdir = $instdir;
                   3124:         }
                   3125:         if ($lctarball =~ /^loncapa\-(\d+\.\d+\.\d+(?:|[^.]+))\.tar\.gz$/) {
                   3126:             $chdircmd = "cd $targetdir/loncapa-".$1;
                   3127:         } else {
                   3128:             $chdircmd = "cd $targetdir/loncapa-X.Y.Z  (X.Y.Z should correspond to a version number like '2.11.3')";
                   3129:         }
1.1       raeburn  3130:         print_and_log("\n");
                   3131:         print &mt('LON-CAPA source files extracted.')."\n".
1.45.2.16  raeburn  3132:               &mt('It remains for you to execute the following commands:').
                   3133:               "\n$chdircmd\n$updatecmd\n".
                   3134:               &mt('If you have any trouble, please see [_1] and [_2]',
                   3135:                   'http://install.loncapa.org/','http://help.loncapa.org/')."\n";
1.1       raeburn  3136:         $updateshown = 1;
                   3137:     }
                   3138:     return ($have_tarball,$updateshown);
                   3139: }
                   3140: 
                   3141: close LOG;

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