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

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.22! raeburn    79:     print LOG '$Id: install.pl,v 1.45.2.21 2024/07/28 14:05:29 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.1  raeburn   648:         if ($1 >= 15) {
                    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.1  raeburn   734:                     if (($name eq 'sles') && ($num >= 15)) {
                    735:                         $daemon{'ntp'} = 'chronyd';
                    736:                         $daemon{'mysql'} = 'mariadb';
                    737:                     } else {
                    738:                         $daemon{'ntp'} = 'ntpd';
                    739:                     }
1.35      raeburn   740:                 }
1.26      raeburn   741:             }
                    742:         }
1.6       raeburn   743:     } elsif ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                    744:         my $version = $1;
1.1       raeburn   745:         @runlevels = qw/2 3 4 5/;
                    746:         @norunlevels = qw/0 1 6/;
1.44      raeburn   747:         if (($distro =~ /^ubuntu/) && ($version <= 16)) {
                    748:             $checker_bin = '/usr/sbin/sysv-rc-conf';
                    749:         } else {
                    750:             $uses_systemctl{'ntp'} = 1;
                    751:             $uses_systemctl{'mysql'} = 1;
                    752:             $uses_systemctl{'apache'} = 1;
                    753:             $uses_systemctl{'memcached'} = 1;
                    754:             $uses_systemctl{'cups'} = 1;
                    755:         }
1.6       raeburn   756:         $daemon{'mysql'}  = 'mysql';
                    757:         $daemon{'apache'} = 'apache2';
                    758:         $daemon{'ntp'}    = 'ntp';
                    759:         if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                    760:             $daemon{'cups'} = 'cupsys';
                    761:         }
1.45.2.19  raeburn   762:         if ((($distro =~ /^ubuntu/) && ($version >= 18)) ||
                    763:             (($distro  =~ /^debian/) && ($version >= 10))) {
1.45.2.6  raeburn   764:             $daemon{'ntp'}    = 'chrony';
                    765:         }
1.45.2.19  raeburn   766:         if (($distro  =~ /^debian/) && ($version >= 11)) {
                    767:             $daemon{'mysql'} = 'mariadb';
                    768:         }
1.26      raeburn   769:     } elsif ($distro =~ /^fedora(\d+)/) {
1.23      raeburn   770:         my $version = $1;
                    771:         if ($version >= 15) {
                    772:             $uses_systemctl{'ntp'} = 1;
                    773:         }
                    774:         if ($version >= 16) {
                    775:             $uses_systemctl{'mysql'} = 1;
                    776:             $uses_systemctl{'apache'} = 1;
1.35      raeburn   777:             $uses_systemctl{'memcached'} = 1;
                    778:             $uses_systemctl{'cups'} = 1;
1.23      raeburn   779:         }
1.39      raeburn   780:         if ($version >= 19) {
1.37      raeburn   781:             $daemon{'mysql'} = 'mariadb';
                    782:         }
1.45.2.5  raeburn   783:         if ($version >= 26) {
                    784:             $daemon{'ntp'} = 'chronyd';
                    785:         }
1.45.2.18  raeburn   786:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn   787:         my $version = $1;
                    788:         if ($version >= 7) {
                    789:             $uses_systemctl{'ntp'} = 1;
                    790:             $uses_systemctl{'mysql'} = 1;
                    791:             $uses_systemctl{'apache'} = 1;
1.35      raeburn   792:             $uses_systemctl{'memcached'} = 1;
                    793:             $uses_systemctl{'cups'} = 1;
1.30      raeburn   794:             $daemon{'mysql'} = 'mariadb';
1.29      raeburn   795:         }
1.45.2.3  raeburn   796:         if (($version >= 8) || ($distro eq 'oracle7')) {
                    797:             $daemon{'ntp'} = 'chronyd';
                    798:         }
1.1       raeburn   799:     }
1.23      raeburn   800:     my $nocheck;
1.1       raeburn   801:     if (! -x $checker_bin) {
1.23      raeburn   802:         if ($uses_systemctl{'mysql'} && $uses_systemctl{'apache'}) {
                    803:             if (! -x $sysctl_bin) {
                    804:                 $nocheck = 1;       
                    805:             }
                    806:         } else {
                    807:             $nocheck = 1;
                    808:         }
                    809:     }
                    810:     if ($nocheck) {
1.6       raeburn   811:         print &mt('Could not check runlevel status for MySQL or Apache')."\n";
1.1       raeburn   812:         return;
                    813:     }
                    814:     my $rlstr = join('',@runlevels);
                    815:     my $nrlstr = join('',@norunlevels);
1.23      raeburn   816: 
1.6       raeburn   817:     foreach my $type ('apache','mysql','ntp','cups','memcached') {
                    818:         my $service = $daemon{$type};
1.23      raeburn   819:         if ($uses_systemctl{$type}) {
1.35      raeburn   820:             if (($type eq 'memcached') || ($type eq 'cups')) {
                    821:                 if (-l "/etc/systemd/system/multi-user.target.wants/$service.service") {
                    822:                     $tostop{$type} = 1;
                    823:                 }
                    824:             } else {
                    825:                 if (!-l "/etc/systemd/system/multi-user.target.wants/$service.service") {
                    826:                     $needfix{$type} = "systemctl enable $service.service";
                    827:                 }
1.23      raeburn   828:             }
                    829:         } else {
                    830:             my $command = $checker_bin.' --list '.$service.' 2>/dev/null';
1.35      raeburn   831:             if ($type eq 'cups') {
1.23      raeburn   832:                 if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                    833:                     my $version = $1;
                    834:                     if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                    835:                         $command = $checker_bin.' --list cupsys 2>/dev/null';
1.19      raeburn   836:                     }
                    837:                 }
                    838:             }
1.23      raeburn   839:             my $results = `$command`;
                    840:             my $tofix;
                    841:             if ($results eq '') {
                    842:                 if (($type eq 'apache') || ($type eq 'mysql') || ($type eq 'ntp')) {
                    843:                     if ($distro  =~ /^(debian|ubuntu)/) {
                    844:                         $tofix = "update-rc.d $type defaults";
                    845:                     } else {
                    846:                         $tofix = "$checker_bin --add $service\n";
                    847:                     }
1.6       raeburn   848:                 }
1.23      raeburn   849:             } else {
                    850:                 my %curr_runlevels;
                    851:                 for (my $rl=0; $rl<=6; $rl++) {
                    852:                     if ($results =~ /$rl:on/) { $curr_runlevels{$rl}++; }
                    853:                 }
                    854:                 if (($type eq 'apache') || ($type eq 'mysql') || ($type eq 'ntp')) {
                    855:                     my $warning;
                    856:                     foreach my $rl (@runlevels) {
                    857:                         if (!exists($curr_runlevels{$rl})) {
                    858:                             $warning = 1;
                    859:                         }
                    860:                     }
                    861:                     if ($warning) {
                    862:                         $tofix = "$checker_bin --level $rlstr $service on\n";
                    863:                     }
                    864:                 } elsif (keys(%curr_runlevels) > 0) {
                    865:                     $tostop{$type} = 1;
1.1       raeburn   866:                 }
                    867:             }
1.23      raeburn   868:             if ($tofix) {
                    869:                 $needfix{$type} = $tofix;
1.1       raeburn   870:             }
1.5       raeburn   871:         }
1.1       raeburn   872:     }
                    873:     if ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                    874:         my $name = $1;
                    875:         my $version = $2;
                    876:         my ($major,$minor);
                    877:         if ($name eq 'suse') {
                    878:             ($major,$minor) = split(/\./,$version);
                    879:         } else {
                    880:             $major = $version;
                    881:         }
1.45.2.1  raeburn   882:         if (($major > 10) && ($major <= 13)) {
1.8       raeburn   883:             if (&check_SuSEfirewall2_setup($instdir)) {
                    884:                 $needfix{'insserv'} = 1;
                    885:             }
1.1       raeburn   886:         }
                    887:     }
1.35      raeburn   888:     return (\%needfix,\%tostop,\%uses_systemctl);
1.1       raeburn   889: }
                    890: 
1.45.2.20  raeburn   891: sub check_systemd_security {
                    892:     my ($distro) = @_;
                    893:     my $service = 'httpd.service';
                    894:     if ($distro =~ /^(suse|sles|ubuntu|debian)/) {
                    895:         $service = 'apache2.service';
                    896:     }
                    897:     system("systemctl daemon-reload");
                    898:     if (open(PIPE,"systemctl show $service --property=ProtectHome 2>/dev/null |")) {
                    899:         my $protection = <PIPE>;
                    900:         close(PIPE);
                    901:         chomp($protection);
                    902:         if ($protection =~ /^ProtectHome=(read-only|yes)$/i) {
                    903:             return 1;
                    904:         }
                    905:     } else {
                    906:          print &mt('Could not check systemctl configuration for Apache')."\n";
                    907:     }
                    908:     return 0;
                    909: }
                    910: 
1.45.2.1  raeburn   911: sub uses_firewalld {
                    912:     my ($distro) = @_;
1.45.2.3  raeburn   913:     my ($inuse,$checkfirewalld,$zone);
1.45.2.1  raeburn   914:     if ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                    915:         if (($1 eq 'sles') && ($2 >= 15)) {
                    916:             $checkfirewalld = 1;
                    917:         }
                    918:     } elsif ($distro =~ /^fedora(\d+)$/) {
                    919:         if ($1 >= 18) {
                    920:             $checkfirewalld = 1;
                    921:         }
1.45.2.18  raeburn   922:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.45.2.1  raeburn   923:         if ($1 >= 7) {
                    924:             $checkfirewalld = 1;
                    925:         }
                    926:     }
                    927:     if ($checkfirewalld) {
                    928:         my ($loaded,$active);
1.45.2.15  raeburn   929:         if (open(PIPE,"systemctl status firewalld 2>/dev/null |")) {
1.45.2.1  raeburn   930:             while (<PIPE>) {
                    931:                 chomp();
                    932:                 if (/^\s*Loaded:\s+(\w+)/) {
                    933:                     $loaded = $1;
                    934:                 }
1.45.2.15  raeburn   935:                 if (/^\s*Active:\s+(\w+)/) {
1.45.2.1  raeburn   936:                     $active = $1;
                    937:                 }
                    938:             }
                    939:             close(PIPE);
                    940:         }
                    941:         if (($loaded eq 'loaded') || ($active eq 'active')) {
                    942:             $inuse = 1;
1.45.2.3  raeburn   943:             my $cmd = 'firewall-cmd --get-default-zone';
                    944:             if (open(PIPE,"$cmd |")) {
                    945:                 my $result = <PIPE>;
                    946:                 chomp($result);
                    947:                 close(PIPE);
                    948:                 if ($result =~ /^\w+$/) {
                    949:                     $zone = $result;
                    950:                 }
                    951:             }
1.45.2.1  raeburn   952:         }
                    953:     }
1.45.2.3  raeburn   954:     return ($inuse,$zone);
1.45.2.1  raeburn   955: }
                    956: 
1.1       raeburn   957: sub chkfirewall {
1.5       raeburn   958:     my ($distro) = @_;
1.1       raeburn   959:     my $configfirewall = 1;
                    960:     my %ports = (
                    961:                     http  =>  80,
                    962:                     https => 443,
                    963:                 );
1.5       raeburn   964:     my %activefw;
1.45.2.3  raeburn   965:     my ($firewalld,$zone) = &uses_firewalld($distro);
                    966:     if ($firewalld) {
                    967:         my %current;
                    968:         if (open(PIPE,'firewall-cmd --permanent --zone='.$zone.' --list-services |')) {
                    969:             my $svc = <PIPE>;
                    970:             close(PIPE);
                    971:             chomp($svc);
                    972:             map { $current{$_} = 1; } (split(/\s+/,$svc));
                    973:         }
                    974:         if ($current{'http'} && $current{'https'}) {
                    975:             $configfirewall = 0;
                    976:         }
                    977:     } else {
                    978:         if (&firewall_is_active()) {
1.45.2.1  raeburn   979:             my $iptables = &get_pathto_iptables();
                    980:             if ($iptables eq '') {
                    981:                 print &mt('Firewall not checked as path to iptables not determined.')."\n";
                    982:             } else {
                    983:                 my @fwchains = &get_fw_chains($iptables,$distro);
                    984:                 if (@fwchains) {
                    985:                     foreach my $service ('http','https') {
                    986:                         foreach my $fwchain (@fwchains) {
                    987:                             if (&firewall_is_port_open($iptables,$fwchain,$ports{$service})) {
                    988:                                 $activefw{$service} = 1;
                    989:                                 last;
                    990:                             }
1.1       raeburn   991:                         }
                    992:                     }
1.45.2.1  raeburn   993:                     if ($activefw{'http'}) {
                    994:                         $configfirewall = 0;
                    995:                     }
                    996:                 } else {
                    997:                     print &mt('Firewall not checked as iptables Chains not identified.')."\n";
1.1       raeburn   998:                 }
                    999:             }
1.45.2.3  raeburn  1000:         } else {
                   1001:             print &mt('Firewall not enabled.')."\n";
1.1       raeburn  1002:         }
                   1003:     }
1.5       raeburn  1004:     return ($configfirewall,\%activefw);
1.1       raeburn  1005: }
                   1006: 
                   1007: sub chkapache {
                   1008:     my ($distro,$instdir) = @_;
                   1009:     my $fixapache = 1;
1.28      raeburn  1010:     if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
                   1011:         my $distname = $1;
                   1012:         my $version = $2;
1.33      raeburn  1013:         my ($stdconf,$stdsite);
1.45.2.19  raeburn  1014:         if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   1015:             (($distname eq 'debian') && ($version >= 10))) {
1.33      raeburn  1016:             $stdconf = "$instdir/debian-ubuntu/ubuntu14/loncapa_conf";
                   1017:             $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_sites";
                   1018:         } else {
                   1019:             $stdconf = "$instdir/debian-ubuntu/loncapa"; 
                   1020:         }
                   1021:         if (!-e $stdconf) {
1.1       raeburn  1022:             $fixapache = 0;
                   1023:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n"; 
1.28      raeburn  1024:         } else {
1.33      raeburn  1025:             my ($configfile,$sitefile);
1.45.2.19  raeburn  1026:             if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   1027:                 (($distname eq 'debian') && ($version >= 10))) {
1.45.2.10  raeburn  1028:                 $sitefile = '/etc/apache2/sites-available/loncapa.conf';
                   1029:                 $configfile = '/etc/apache2/conf-available/loncapa.conf';
1.33      raeburn  1030:             } else {
1.45.2.10  raeburn  1031:                 $configfile = '/etc/apache2/sites-available/loncapa';
1.28      raeburn  1032:             }
1.33      raeburn  1033:             if (($configfile ne '') && (-e $configfile) && (-e $stdconf))  {
                   1034:                 if (open(PIPE, "diff --brief $stdconf $configfile |")) {
1.28      raeburn  1035:                     my $diffres = <PIPE>;
                   1036:                     close(PIPE);
                   1037:                     chomp($diffres);
                   1038:                     unless ($diffres) {
                   1039:                         $fixapache = 0;
                   1040:                     }
1.1       raeburn  1041:                 }
                   1042:             }
1.45.2.19  raeburn  1043:             if ((!$fixapache) && ((($distname eq 'ubuntu') && ($version > 12)) ||
                   1044:                                   (($distname eq 'debian') && ($version >= 10))))  {
1.33      raeburn  1045:                 if (($sitefile ne '') && (-e $sitefile) && (-e $stdsite)) {
                   1046:                     if (open(PIPE, "diff --brief $stdsite $sitefile |")) {
                   1047:                         my $diffres = <PIPE>;
                   1048:                         close(PIPE);
                   1049:                         chomp($diffres);
1.45.2.20  raeburn  1050:                         if ($diffres) {
                   1051:                             $fixapache = 1;
                   1052:                         } else {
1.33      raeburn  1053:                             $fixapache = 0;
                   1054:                         }
                   1055:                     }
                   1056:                 }
                   1057:             }
1.1       raeburn  1058:         }
1.6       raeburn  1059:         if (!$fixapache) {
                   1060:             foreach my $module ('headers.load','expires.load') {
                   1061:                 unless (-l "/etc/apache2/mods-enabled/$module") {
                   1062:                     $fixapache = 1;
                   1063:                 }
                   1064:             }
                   1065:         }
1.45.2.19  raeburn  1066:         if ((!$fixapache) && (($distname eq 'ubuntu') || ($distname eq 'debian'))) {
1.45.2.7  raeburn  1067:             my $sitestatus = "/etc/apache2/mods-available/status.conf";
                   1068:             my $stdstatus = "$instdir/debian-ubuntu/status.conf";
                   1069:             if ((-e $stdstatus) && (-e $sitestatus)) {
                   1070:                 if (open(PIPE, "diff --brief $stdstatus $sitestatus |")) {
                   1071:                     my $diffres = <PIPE>;
                   1072:                     close(PIPE);
                   1073:                     chomp($diffres);
                   1074:                     if ($diffres) {
                   1075:                         $fixapache = 1;
                   1076:                     }
                   1077:                 }
                   1078:             }
                   1079:         }
1.45.2.1  raeburn  1080:     } elsif ($distro =~ /^(suse|sles)([\d\.]+)$/) {
                   1081:         my ($name,$version) = ($1,$2);
1.1       raeburn  1082:         my $apache = 'apache';
1.45.2.1  raeburn  1083:         my $conf_file = "$instdir/sles-suse/default-server.conf";
                   1084:         if ($version >= 10) {
1.8       raeburn  1085:             $apache = 'apache2';
1.1       raeburn  1086:         }
1.45.2.1  raeburn  1087:         if (($name eq 'sles') && ($version >= 12)) {
                   1088:             $conf_file = "$instdir/sles-suse/apache2.4/default-server.conf";
                   1089:         }
                   1090:         if (!-e $conf_file) {
1.1       raeburn  1091:             $fixapache = 0;
                   1092:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
1.45.2.1  raeburn  1093:         } elsif (-e "/etc/$apache/default-server.conf") {
                   1094:             if (open(PIPE, "diff --brief $conf_file /etc/$apache/default-server.conf |")) {
1.9       raeburn  1095:                 my $diffres = <PIPE>;
                   1096:                 close(PIPE);
                   1097:                 chomp($diffres);
                   1098:                 unless ($diffres) {
                   1099:                     $fixapache = 0;
                   1100:                 }
                   1101:             }
                   1102:         }
                   1103:     } elsif ($distro eq 'rhes4') {
                   1104:         if (!-e "$instdir/rhes4/httpd.conf") {
                   1105:             $fixapache = 0;
                   1106:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
                   1107:         } elsif ((-e "/etc/httpd/conf/httpd.conf") && (-e "$instdir/rhes4/httpd.conf")) {
                   1108:             if (open(PIPE, "diff --brief $instdir/rhes4/httpd.conf /etc/httpd/conf/httpd.conf |")) {
1.1       raeburn  1109:                 my $diffres = <PIPE>;
                   1110:                 close(PIPE);
                   1111:                 chomp($diffres);
                   1112:                 unless ($diffres) {
                   1113:                     $fixapache = 0;
                   1114:                 }
                   1115:             }
                   1116:         }
                   1117:     } else {
1.14      raeburn  1118:         my $configfile = 'httpd.conf';
1.45.2.5  raeburn  1119:         my $mpmfile = 'mpm.conf';
1.45.2.18  raeburn  1120:         if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn  1121:             if ($1 >= 7) {
                   1122:                 $configfile = 'apache2.4/httpd.conf';
                   1123:             } elsif ($1 > 5) {
1.14      raeburn  1124:                 $configfile = 'new/httpd.conf';
                   1125:             }
                   1126:         } elsif ($distro =~ /^fedora(\d+)$/) {
1.29      raeburn  1127:             if ($1 > 17) {
1.45.2.5  raeburn  1128:                 $configfile = 'apache2.4/httpd.conf';
1.29      raeburn  1129:             } elsif ($1 > 10) {
1.15      raeburn  1130:                 $configfile = 'new/httpd.conf';
1.14      raeburn  1131:             }
                   1132:         }
                   1133:         if (!-e "$instdir/centos-rhes-fedora-sl/$configfile") {
1.1       raeburn  1134:             $fixapache = 0;
                   1135:             print &mt('Warning: No LON-CAPA Apache configuration file found for installation check.')."\n";
1.14      raeburn  1136:         } elsif ((-e "/etc/httpd/conf/httpd.conf") && (-e "$instdir/centos-rhes-fedora-sl/$configfile")) {
                   1137:             if (open(PIPE, "diff --brief $instdir/centos-rhes-fedora-sl/$configfile /etc/httpd/conf/httpd.conf |")) {
1.1       raeburn  1138:                 my $diffres = <PIPE>;
                   1139:                 close(PIPE);
                   1140:                 chomp($diffres);
                   1141:                 unless ($diffres) {
                   1142:                     $fixapache = 0;
                   1143:                 }
                   1144:             }
                   1145:         }
1.45.2.5  raeburn  1146:         if (-e "/etc/httpd/conf.modules.d/00-mpm.conf") {
                   1147:             if (!-e "$instdir/centos-rhes-fedora-sl/$mpmfile") {
                   1148:                 print &mt('Warning: No LON-CAPA Apache MPM configuration file found for installation check.')."\n";
                   1149:             } elsif ((-e "/etc/httpd/conf.modules.d/00-mpm.conf") && (-e "$instdir/centos-rhes-fedora-sl/$mpmfile")) {
                   1150:                 if (open(PIPE, "diff --brief $instdir/centos-rhes-fedora-sl/$mpmfile /etc/httpd/conf.modules.d/00-mpm.conf |")) {
                   1151:                     my $diffres = <PIPE>;
                   1152:                     close(PIPE);
                   1153:                     chomp($diffres);
                   1154:                     if ($diffres) {
                   1155:                         $fixapache = 1;
                   1156:                     }
                   1157:                 }
                   1158:             }
                   1159:         }
1.1       raeburn  1160:     }
                   1161:     return $fixapache;
                   1162: }
                   1163: 
                   1164: sub chksrvcs {
                   1165:     my ($distro,$tostop) = @_;
                   1166:     my %stopsrvcs;
                   1167:     if (ref($tostop) eq 'HASH') {
                   1168:         %stopsrvcs = %{$tostop};
                   1169:     }
1.6       raeburn  1170:     foreach my $service ('cups','memcached') {
1.1       raeburn  1171:         next if (exists($stopsrvcs{$service}));
                   1172:         my $daemon = $service;
                   1173:         if ($service eq 'cups') {
                   1174:             $daemon = 'cupsd';
                   1175:         }
                   1176:         my $cmd = "ps -ef |grep '$daemon' |grep -v grep";
                   1177:         if (open(PIPE,'-|',$cmd)) {
                   1178:             my $daemonrunning = <PIPE>;
                   1179:             chomp($daemonrunning);
                   1180:             close(PIPE);
                   1181:             if ($daemonrunning) {
1.12      raeburn  1182:                 if ($service eq 'memcached') {
1.16      raeburn  1183:                     my $cmd = '/usr/bin/memcached';
                   1184:                     if ($distro =~ /^(suse|sles)/) {
                   1185:                         $cmd = '/usr/sbin/memcached';
                   1186:                     }
1.12      raeburn  1187:                     unless ($daemonrunning =~ m{^www[^/]+\Q$cmd -m 400 -v\E$}) {
1.10      raeburn  1188:                         $stopsrvcs{$service} = 1;
                   1189:                     }
                   1190:                 } else {
                   1191:                     $stopsrvcs{$service} = 1;
                   1192:                 }
1.1       raeburn  1193:             }
                   1194:         }
1.10      raeburn  1195:     }
1.1       raeburn  1196:     return \%stopsrvcs;
                   1197: }
                   1198: 
                   1199: sub need_download {
1.45.2.16  raeburn  1200:     my ($distro,$instdir) = @_;
1.1       raeburn  1201:     my $needs_download = 1;
                   1202:     my ($production,$testing,$stdsizes) = &download_versionslist();
1.45.2.16  raeburn  1203:     my ($localcurrent,$localtesting,%tarball,%localsize,%bymodtime,
1.1       raeburn  1204:         %bysize,$filetouse,$downloadstatus);
1.45.2.16  raeburn  1205:     if (opendir(my $dir,$instdir)) {
1.1       raeburn  1206:         my (@lcdownloads,$version);
                   1207:         foreach my $file (readdir($dir)) {
                   1208:             if ($file =~ /^loncapa\-([\w\-.]+)\.tar\.gz$/) {
                   1209:                 $version = $1;
                   1210:             } else {
                   1211:                 next;
                   1212:             }
                   1213:             if (ref($stdsizes) eq 'HASH') {
                   1214:                 if ($version eq 'current') {
1.45.2.16  raeburn  1215:                     my @stats = stat("$instdir/$file");
1.1       raeburn  1216:                     $localcurrent = $stats[7];
1.4       raeburn  1217:                     if ($localcurrent == $stdsizes->{$production}) {
1.1       raeburn  1218:                         $needs_download = 0;
                   1219:                         $filetouse = $file;
                   1220:                     }
                   1221:                 } elsif ($version eq 'testing') {
1.45.2.16  raeburn  1222:                     my @stats = stat("$instdir/$file");
1.1       raeburn  1223:                     $localtesting = $stats[7];
1.4       raeburn  1224:                     if ($localtesting == $stdsizes->{$testing}) {
1.1       raeburn  1225:                         $needs_download = 0;
                   1226:                         $filetouse = $file;
                   1227:                     }
                   1228:                 }
                   1229:             }
                   1230:             $tarball{$version} = $file;
                   1231:             push(@lcdownloads,$version);
                   1232:         }
                   1233:         if ($needs_download) {
                   1234:             if (@lcdownloads > 0) {
                   1235:                 foreach my $version (@lcdownloads) {
1.45.2.16  raeburn  1236:                     my @stats = stat("$instdir/$tarball{$version}");
1.1       raeburn  1237:                     my $mtime = $stats[9];
                   1238:                     $localsize{$version} = $stats[7];
                   1239:                     if ($mtime) {
                   1240:                         push(@{$bymodtime{$mtime}},$version);
                   1241:                     }
                   1242:                     if ($localsize{$version}) {
                   1243:                         push(@{$bysize{$localsize{$version}}},$version);
                   1244:                     }
                   1245:                 }
                   1246:                 if ($testing) {
                   1247:                     if (exists($localsize{$testing})) {
                   1248:                         if ($stdsizes->{$testing} == $localsize{$testing}) {
                   1249:                             $needs_download = 0;
                   1250:                             $filetouse = 'loncapa-'.$testing.'.tar.gz';
                   1251:                         }
                   1252:                     }
                   1253:                 }
                   1254:                 if ($needs_download) { 
                   1255:                     if ($production) {
                   1256:                         if (exists($localsize{$production})) {
                   1257:                             if ($stdsizes->{$production} == $localsize{$production}) {
                   1258:                                 $needs_download = 0;
                   1259:                                 $filetouse = 'loncapa-'.$production.'.tar.gz';
                   1260:                             }
                   1261:                         }
                   1262:                     }
                   1263:                 }
                   1264:                 if ($needs_download) {
                   1265:                     my @sorted = sort { $b <=> $a } keys(%bymodtime);
                   1266:                     my $newest = $sorted[0];
                   1267:                     if (ref($bymodtime{$newest}) eq 'ARRAY') {
                   1268:                         $downloadstatus = 
1.45.2.16  raeburn  1269:                               "Latest LON-CAPA source download in $instdir is: ".
1.1       raeburn  1270:                               join(',',@{$bymodtime{$newest}})." (downloaded ".
                   1271:                               localtime($newest).")\n";
                   1272:                     }
                   1273:                 } else {
                   1274:                     $downloadstatus = 
1.45.2.16  raeburn  1275:                         "The $instdir directory already contains the latest LON-CAPA version:".
1.1       raeburn  1276:                         "\n".$filetouse."\n"."which can be used for installation.\n";
                   1277:                 }
                   1278:             } else {
1.45.2.16  raeburn  1279:                 $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  1280:             }
                   1281:         }
                   1282:     } else {
1.45.2.16  raeburn  1283:         $downloadstatus = "Could not open $instdir directory to look for existing downloads of LON-CAPA source code.\n";
1.1       raeburn  1284:     }
                   1285:     return ($needs_download,$downloadstatus,$filetouse,$production,$testing);
                   1286: }
                   1287: 
                   1288: sub check_mysql_setup {
1.45.2.12  raeburn  1289:     my ($instdir,$dsn,$distro) = @_;
                   1290:     my ($mysqlsetup,$has_pass,$mysql_unix_socket,$mysql_has_wwwuser);
1.1       raeburn  1291:     my $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
1.45.2.19  raeburn  1292:     my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version();
                   1293:     if (($mysqlname =~ /^MariaDB/i) && (($mysqlversion == 10 && $mysqlminorversion >= 4) || ($mysqlversion >= 11))) {
1.45.2.9  raeburn  1294:         if ($dbh) {
                   1295:             my $sth = $dbh->prepare("SELECT Priv FROM mysql.global_priv WHERE (User = 'root' AND Host ='localhost')");
                   1296:             $sth->execute();
                   1297:             while (my $priv = $sth->fetchrow_array) {
1.45.2.14  raeburn  1298:                 if ($priv =~ /unix_socket/) {
1.45.2.9  raeburn  1299:                     $mysql_unix_socket = 1;
                   1300:                     last;
                   1301:                 }
                   1302:             }
                   1303:             $sth->finish();
                   1304:             if ($mysql_unix_socket) {
                   1305:                 print_and_log(&mt('MariaDB using unix_socket for root access from localhost.')."\n");
                   1306:                 $mysqlsetup = 'rootok';
1.45.2.12  raeburn  1307:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.45.2.9  raeburn  1308:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket);
                   1309:             }
                   1310:         }
                   1311:     }
1.1       raeburn  1312:     if ($dbh) {
1.45.2.12  raeburn  1313:         $mysqlsetup = 'noroot';
1.45.2.19  raeburn  1314:         if (($mysqlname !~ /^MariaDB/i) && (($mysqlversion == 5 && $mysqlminorversion >= 7) || ($mysqlversion >= 6))) {
1.45.2.12  raeburn  1315:             my $sth = $dbh->prepare("SELECT plugin from mysql.user where User='root'");
                   1316:             $sth->execute();
                   1317:             while (my $priv = $sth->fetchrow_array) {
                   1318:                 if ($priv =~ /auth_socket/) {
                   1319:                     $mysql_unix_socket = 1;
                   1320:                     last;
                   1321:                 }
                   1322:             }
                   1323:             $sth->finish();
                   1324:             if ($mysql_unix_socket) {
                   1325:                 print_and_log(&mt('MySQL using unix_socket for root access from localhost.')."\n");
                   1326:                 $mysqlsetup = 'rootok';
                   1327:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
                   1328:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket);
                   1329:             }
1.45.2.14  raeburn  1330:         }
1.1       raeburn  1331:     } elsif ($DBI::err =~ /1045/) {
                   1332:         $has_pass = 1;
1.34      raeburn  1333:     } elsif ($distro =~ /^ubuntu(\d+)$/) {
                   1334:         my $version = $1;
                   1335:         if ($1 > 12) {
                   1336:             print_and_log(&mt('Restarting mysql, please be patient')."\n");
                   1337:             if (open (PIPE, "service mysql restart 2>&1 |")) {
                   1338:                 while (<PIPE>) {
                   1339:                     print $_;
                   1340:                 }
                   1341:                 close(PIPE);
                   1342:             }
                   1343:             $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
                   1344:             if ($dbh) {
                   1345:                 $mysqlsetup = 'noroot';
1.45.2.12  raeburn  1346:                 $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.34      raeburn  1347:             } elsif ($DBI::err =~ /1045/) {
                   1348:                 $has_pass = 1;
                   1349:             } else {
                   1350:                 $mysqlsetup = 'needsrestart';
1.45.2.16  raeburn  1351:                 $mysql_has_wwwuser = &check_mysql_wwwuser();
1.34      raeburn  1352:                 return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
                   1353:             }
                   1354:         }
1.1       raeburn  1355:     }
                   1356:     if ($has_pass) {
                   1357:         print &mt('You have already set a root password for the MySQL database.')."\n";
                   1358:         my $currpass = &get_mysql_password(&mt('Please enter the password now'));
                   1359:         $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
                   1360:         if ($dbh) {
                   1361:             $mysqlsetup = 'rootok';
                   1362:             print_and_log(&mt('Password accepted.')."\n");
1.45.2.12  raeburn  1363:             $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.1       raeburn  1364:         } else {
                   1365:             $mysqlsetup = 'rootfail';
                   1366:             print_and_log(&mt('Problem accessing MySQL.')."\n");
                   1367:             if ($DBI::err =~ /1045/) {
                   1368:                 print_and_log(&mt('Perhaps the password was incorrect?')."\n");
                   1369:                 print &mt('Try again?').' ';
                   1370:                 $currpass = &get_mysql_password(&mt('Re-enter password now')); 
                   1371:                 $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
                   1372:                 if ($dbh) {
                   1373:                     $mysqlsetup = 'rootok';
                   1374:                     print_and_log(&mt('Password accepted.')."\n");
1.45.2.12  raeburn  1375:                     $mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
1.1       raeburn  1376:                 } else {
                   1377:                     if ($DBI::err =~ /1045/) {
                   1378:                         print_and_log(&mt('Incorrect password.')."\n");
                   1379:                     }
1.45.2.16  raeburn  1380:                     $mysql_has_wwwuser = &check_mysql_wwwuser();
1.1       raeburn  1381:                 }
                   1382:             }
                   1383:         }
1.34      raeburn  1384:     } elsif ($mysqlsetup ne 'noroot') {
1.1       raeburn  1385:         print_and_log(&mt('Problem accessing MySQL.')."\n");
                   1386:         $mysqlsetup = 'rootfail';
1.45.2.16  raeburn  1387:         $mysql_has_wwwuser = &check_mysql_wwwuser();
1.1       raeburn  1388:     }
1.34      raeburn  1389:     return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
1.1       raeburn  1390: }
                   1391: 
                   1392: sub check_mysql_wwwuser {
1.45.2.12  raeburn  1393:     my ($dbh) = @_;
1.1       raeburn  1394:     my $mysql_wwwuser;
1.45.2.12  raeburn  1395:     if ($dbh) {
                   1396:         $mysql_wwwuser = $dbh->selectrow_array("SELECT COUNT(User) FROM mysql.user WHERE (User = 'www' AND Host ='localhost')");
                   1397:     } else {
                   1398:         my $dbhn = DBI->connect("DBI:mysql:database=information_schema",'www','localhostkey',
                   1399:                                 {PrintError => +0}) || return;
                   1400:         if ($dbhn) {
                   1401:             $mysql_wwwuser = 1;
                   1402:             $dbhn->disconnect;
                   1403:         }
1.1       raeburn  1404:     }
                   1405:     return $mysql_wwwuser;
                   1406: }
                   1407: 
                   1408: sub check_loncapa_mysqldb {
                   1409:     my ($dbh) = @_;
                   1410:     my $has_lcdb;
                   1411:     if (ref($dbh)) {
                   1412:         my $sth = $dbh->prepare("SHOW DATABASES");
                   1413:         $sth->execute();
                   1414:         while (my $dbname = $sth->fetchrow_array) {
                   1415:             if ($dbname eq 'loncapa') {
                   1416:                 $has_lcdb = 1;
                   1417:                 last;
                   1418:             }
                   1419:         }
                   1420:         $sth->finish();
                   1421:     }
                   1422:     return $has_lcdb;
                   1423: }
                   1424: 
                   1425: sub get_pathto_iptables {
                   1426:     my $iptables;
                   1427:     if (-e '/sbin/iptables') {
                   1428:         $iptables = '/sbin/iptables';
                   1429:     } elsif (-e '/usr/sbin/iptables') {
                   1430:         $iptables = '/usr/sbin/iptables';
                   1431:     } else {
                   1432:         print &mt('Unable to find iptables command.')."\n";
                   1433:     }
                   1434:     return $iptables;
                   1435: }
                   1436: 
                   1437: sub firewall_is_active {
                   1438:     if (-e '/proc/net/ip_tables_names') {
1.45.2.19  raeburn  1439:         my $status;
1.45.2.1  raeburn  1440:         if (open(PIPE,'cat /proc/net/ip_tables_names |grep filter |')) {
1.45.2.19  raeburn  1441:             $status = <PIPE>;
1.45.2.1  raeburn  1442:             close(PIPE);
                   1443:             chomp($status);
                   1444:             if ($status eq 'filter') {
                   1445:                 return 1;
                   1446:             }
                   1447:         }
1.45.2.19  raeburn  1448:         unless ($status) {
                   1449:             if (open(PIPE,'nft list tables |')) {
                   1450:                 while(<PIPE>) {
                   1451:                     chomp();
                   1452:                     if (/filter$/) {
                   1453:                         $status = 1;
                   1454:                         last;
                   1455:                     }
                   1456:                 }
                   1457:                 close(PIPE);
                   1458:                 if ($status) {
                   1459:                     return 1;
                   1460:                 }
                   1461:             }
                   1462:         }
1.1       raeburn  1463:     }
1.45.2.1  raeburn  1464:     return 0;
1.1       raeburn  1465: }
                   1466: 
                   1467: sub get_fw_chains {
1.5       raeburn  1468:     my ($iptables,$distro) = @_;
1.1       raeburn  1469:     my @fw_chains;
                   1470:     my $suse_config = "/etc/sysconfig/SuSEfirewall2";
                   1471:     my $ubuntu_config = "/etc/ufw/ufw.conf";
                   1472:     if (-e $suse_config) {
                   1473:         push(@fw_chains,'input_ext');
                   1474:     } else {
                   1475:         my @posschains;
                   1476:         if (-e $ubuntu_config) {
                   1477:             @posschains = ('ufw-user-input','INPUT');
1.5       raeburn  1478:         } elsif ($distro =~ /^debian5/) {
                   1479:             @posschains = ('INPUT');
1.45.2.1  raeburn  1480:         } elsif ($distro =~ /^(suse|sles)(\d+)/) {
                   1481:             @posschains = ('IN_public');
1.1       raeburn  1482:         } else {
                   1483:             @posschains = ('RH-Firewall-1-INPUT','INPUT');
                   1484:             if (!-e '/etc/sysconfig/iptables') {
                   1485:                 if (!-e '/var/lib/iptables') {
                   1486:                     print &mt('Unable to find iptables file containing static definitions.')."\n";
                   1487:                 }
                   1488:                 push(@fw_chains,'RH-Firewall-1-INPUT');
                   1489:             }
                   1490:         }
                   1491:         if ($iptables eq '') {
                   1492:             $iptables = &get_pathto_iptables();
                   1493:         }
                   1494:         my %counts;
                   1495:         if (open(PIPE,"$iptables -L -n |")) {
                   1496:             while(<PIPE>) {
                   1497:                 foreach my $chain (@posschains) {
                   1498:                     if (/(\Q$chain\E)/) {
                   1499:                         $counts{$1} ++;
                   1500:                     }
                   1501:                 }
                   1502:             }
                   1503:             close(PIPE);
                   1504:         }
                   1505:         foreach my $fw_chain (@posschains) {
                   1506:             if ($counts{$fw_chain}) {
                   1507:                 unless(grep(/^\Q$fw_chain\E$/,@fw_chains)) {
                   1508:                     push(@fw_chains,$fw_chain);
                   1509:                 }
                   1510:             }
                   1511:         }
                   1512:     }
                   1513:     return @fw_chains;
                   1514: }
                   1515: 
                   1516: sub firewall_is_port_open {
                   1517:     my ($iptables,$fw_chain,$port) = @_;
                   1518:     # returns 1 if the firewall port is open, 0 if not.
                   1519:     #
                   1520:     # check if firewall is active or installed
                   1521:     return if (! &firewall_is_active());
                   1522:     my $count = 0;
                   1523:     if (open(PIPE,"$iptables -L $fw_chain -n |")) {
                   1524:         while(<PIPE>) {
                   1525:             if (/tcp dpt\:\Q$port\E/) {
                   1526:                 $count ++;
                   1527:                 last;
                   1528:             }
                   1529:         }
                   1530:         close(PIPE);
                   1531:     } else {
                   1532:         print &mt('Firewall status not checked: unable to run [_1].','iptables -L')."\n";
                   1533:     }
                   1534:     return $count;
                   1535: }
                   1536: 
                   1537: sub get_mysql_password {
                   1538:     my ($prompt) = @_;
                   1539:     local $| = 1;
                   1540:     print $prompt.': ';
                   1541:     my $newpasswd = '';
                   1542:     ReadMode 'raw';
                   1543:     my $key;
                   1544:     while(ord($key = ReadKey(0)) != 10) {
                   1545:         if(ord($key) == 127 || ord($key) == 8) {
                   1546:             chop($newpasswd);
                   1547:             print "\b \b";
                   1548:         } elsif(!ord($key) < 32) {
                   1549:             $newpasswd .= $key;
                   1550:             print '*';
                   1551:         }
                   1552:     }
                   1553:     ReadMode 'normal';
                   1554:     print "\n";
                   1555:     return $newpasswd;
                   1556: }
                   1557: 
                   1558: sub check_SuSEfirewall2_setup {
                   1559:     my ($instdir) = @_;
                   1560:     my $need_override = 1;
1.9       raeburn  1561:     if ((-e "/etc/insserv/overrides/SuSEfirewall2_setup") && (-e "$instdir/sles-suse/SuSEfirewall2_setup")) {
                   1562:         if (open(PIPE, "diff --brief $instdir/sles-suse/SuSEfirewall2_setup /etc/insserv/overrides/SuSEfirewall2_setup  |")) {
1.1       raeburn  1563:             my $diffres = <PIPE>;
                   1564:             close(PIPE);
                   1565:             chomp($diffres);
                   1566:             unless ($diffres) {
                   1567:                 $need_override = 0;
                   1568:             }
                   1569:         }
                   1570:     }
                   1571:     return $need_override;
                   1572: }
                   1573: 
                   1574: sub download_versionslist {
                   1575:     my ($production,$testing,%sizes);
                   1576:     if (-e "latest.txt") {
                   1577:          unlink("latest.txt");
                   1578:     }
                   1579:     my $rtncode = system("wget http://install.loncapa.org/versions/latest.txt ".
                   1580:                          "> /dev/null 2>&1");
                   1581:     if (!$rtncode) {
                   1582:         if (open(my $fh,"<latest.txt")) {
                   1583:             my @info = <$fh>;
                   1584:             close($fh);
                   1585:             foreach my $line (@info) {
                   1586:                 chomp();
                   1587:                 if ($line =~ /^\QLATEST-IS: \E([\w\-.]+):(\d+)$/) {
                   1588:                      $production = $1;
                   1589:                      $sizes{$1} = $2;
                   1590:                 } elsif ($line =~ /^LATEST-TESTING-IS: \E([\w\-.]+):(\d+)$/) {
                   1591:                      $testing = $1;
                   1592:                      $sizes{$1} = $2;
                   1593:                 }
                   1594:             }
                   1595:         }
                   1596:     }
                   1597:     return ($production,$testing,\%sizes);
                   1598: }
                   1599: 
                   1600: #
                   1601: # End helper routines.
                   1602: # Main script starts here
                   1603: #
                   1604: 
                   1605: print "
                   1606: ********************************************************************
                   1607: 
                   1608:                     ".&mt('Welcome to LON-CAPA')."
                   1609: 
                   1610: ".&mt('This script will configure your system for installation of LON-CAPA.')."
                   1611: 
                   1612: ********************************************************************
                   1613: 
                   1614: ".&mt('The following actions are available:')."
                   1615: 
1.4       raeburn  1616: ".&mt('1.')." ".&mt('Create the www user/group.')."
1.1       raeburn  1617:    ".&mt('This is the user/group ownership under which Apache child processes run.')."
                   1618:    ".&mt('It also owns most directories within the /home/httpd directory.')." 
                   1619:    ".&mt('This directory is where most LON-CAPA files and directories are stored.')."
1.4       raeburn  1620: ".&mt('2.')." ".&mt('Install the package LON-CAPA uses to authenticate users.')."
                   1621: ".&mt('3.')." ".&mt('Set-up the MySQL database.')."
                   1622: ".&mt('4.')." ".&mt('Set-up MySQL permissions.')."
                   1623: ".&mt('5.')." ".&mt('Configure Apache web server.')."
1.45.2.20  raeburn  1624: ".&mt('6.')." ".&mt('Configure systemd security settings for Apache web server.')."
                   1625: ".&mt('7.')." ".&mt('Configure start-up of services.')."
                   1626: ".&mt('8.')." ".&mt('Check firewall settings.')."
                   1627: ".&mt('9.')." ".&mt('Stop services not used by LON-CAPA,')."
1.1       raeburn  1628:    ".&mt('i.e., services for a print server: [_1] daemon.',"'cups'")."
1.45.2.20  raeburn  1629: ".&mt('10.')." ".&mt('Download LON-CAPA source code in readiness for installation.')."
1.1       raeburn  1630: 
                   1631: ".&mt('Typically, you will run this script only once, when you first install LON-CAPA.')." 
                   1632: 
                   1633: ".&mt('The script will analyze your system to determine which actions are recommended.')."
                   1634: ".&mt('The script will then prompt you to choose the actions you would like taken.')."
                   1635: 
                   1636: ".&mt('For each the recommended action will be selected if you hit Enter/Return.')."
                   1637: ".&mt('To override the default, type the lower case option from the two options listed.')."
                   1638: ".&mt('So, if the default is "yes", ~[Y/n~] will be shown -- type n to override.')."
                   1639: ".&mt('Whereas if the default is "no", ~[y/N~] will be shown -- type y to override.')." 
                   1640: 
                   1641: ".&mt('To accept the default, simply hit Enter/Return on your keyboard.')."
                   1642: ".&mt('Otherwise type: y or n then hit the Enter/Return key.')."
                   1643: 
                   1644: ".&mt('Once a choice has been entered for all nine actions, required changes will be made.')."
                   1645: ".&mt('Feedback will be displayed on screen, and also stored in: [_1].','loncapa_install.log')."
                   1646: 
                   1647: ".&mt('Continue? ~[Y/n~] ');
                   1648: 
                   1649: my $go_on = &get_user_selection(1);
                   1650: if (!$go_on) {
                   1651:     exit;
                   1652: }
                   1653: 
                   1654: my $instdir = `pwd`;
                   1655: chomp($instdir);
                   1656: 
                   1657: my %callsub;
1.45.2.20  raeburn  1658: my @actions = ('wwwuser','pwauth','mysql','mysqlperms','apache','systemd',
1.1       raeburn  1659:                'runlevels','firewall','stopsrvcs','download');
                   1660: my %prompts = &texthash( 
                   1661:     wwwuser    => "Create the 'www' user?",
                   1662:     pwauth     => 'Install the package LON-CAPA uses to authenticate users?',
                   1663:     mysql      => 'Set-up the MySQL database?',
                   1664:     mysqlperms => 'Set-up MySQL permissions?',
                   1665:     apache     => 'Configure Apache web server?',
1.45.2.20  raeburn  1666:     systemd    => 'Configure systemd security settings for Apache web server?',
1.1       raeburn  1667:     runlevels  => 'Set overrides for start-up order of services?',
                   1668:     firewall   => 'Configure firewall settings for Apache',
                   1669:     stopsrvcs  => 'Stop extra services not required on a LON-CAPA server?',
                   1670:     download   => 'Download LON-CAPA source code in readiness for installation?',
                   1671: );
                   1672: 
                   1673: print "\n".&mt('Checking system status ...')."\n";
                   1674: 
                   1675: my $dsn = "DBI:mysql:database=mysql";
1.45.2.22! raeburn  1676: my ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart,
1.45.2.9  raeburn  1677:     $recommended,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$downloadstatus,
                   1678:     $filetouse,$production,$testing,$apachefw,$uses_systemctl) = &check_required($instdir,$dsn);
1.1       raeburn  1679: if ($distro eq '') {
                   1680:     print "\n".&mt('Linux distribution could not be verified as a supported distribution.')."\n".
                   1681:           &mt('The following are supported: [_1].',
                   1682:               'CentOS, RedHat Enterprise, Fedora, Scientific Linux, '.
1.45.2.3  raeburn  1683:               'Oracle Linux, openSuSE, SLES, Ubuntu LTS, Debian')."\n\n".
1.1       raeburn  1684:           &mt('Stopping execution.')."\n";
                   1685:     exit;
                   1686: }
1.34      raeburn  1687: if ($mysqlrestart) {
                   1688:     print "\n".&mt('The mysql daemon needs to be restarted using the following command:')."\n".
                   1689:           $mysqlrestart."\n\n".
                   1690:           &mt('Stopping execution of install.pl script.')."\n".
                   1691:           &mt('Please run the install.pl script again, once you have restarted mysql.')."\n";
                   1692:     exit;
                   1693: }
1.6       raeburn  1694: if ($localecmd ne '') {
1.45.2.22! raeburn  1695:     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";
        !          1696:     if ($langcmd ne '') {
        !          1697:         print &mt('Use the following command(s) or action(s) to install a required language package.')."\n\n".
        !          1698:               "$langcmd\n";
        !          1699:     }
        !          1700:     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  1701:     $localecmd."\n\n".
                   1702:     &mt('Stopping execution.')."\n";
                   1703:     exit;
                   1704: }
1.1       raeburn  1705: if (!$gotprereqs) {
1.12      raeburn  1706:     print "\n".&mt('The LONCAPA-prerequisites package is not installed.')."\n".
1.1       raeburn  1707:           &mt('The following command can be used to install the package (and dependencies):')."\n\n".
                   1708:           $updatecmd."\n\n";
                   1709:     if ($installnow eq '') {
                   1710:         print &mt('Stopping execution.')."\n";
                   1711:         exit;
                   1712:     } else {
                   1713:         print &mt('Run command? ~[Y/n~]');
                   1714:         my $install_prereq = &get_user_selection(1);
                   1715:         if ($install_prereq) {
                   1716:             if (open(PIPE,'|-',$installnow)) {
                   1717:                 close(PIPE);
                   1718:                 $gotprereqs = &check_prerequisites($packagecmd,$distro);
                   1719:                 if (!$gotprereqs) {
1.12      raeburn  1720:                     print &mt('The LONCAPA-prerequisites package is not installed.')."\n".
1.1       raeburn  1721:                           &mt('Stopping execution.')."\n";
                   1722:                     exit;
                   1723:                 } else {
1.45.2.22! raeburn  1724:                     ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,
1.45.2.9  raeburn  1725:                      $mysqlrestart,$recommended,$dbh,$has_pass,$mysql_unix_socket,
                   1726:                      $has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw,
                   1727:                      $uses_systemctl) = &check_required($instdir,$dsn);
1.1       raeburn  1728:                 }
                   1729:             } else {
1.12      raeburn  1730:                 print &mt('Failed to run command to install LONCAPA-prerequisites')."\n";
1.1       raeburn  1731:                 exit;
                   1732:             }
                   1733:         } else {
                   1734:             print &mt('Stopping execution.')."\n";
                   1735:             exit;
                   1736:         }
                   1737:     }
                   1738: }
                   1739: unless (ref($recommended) eq 'HASH') {
                   1740:     print "\n".&mt('An error occurred determining which actions are recommended.')."\n\n".
                   1741:           &mt('Stopping execution.')."\n";
                   1742:     exit;
                   1743: }
                   1744: 
                   1745: print "\n";
                   1746: my $num = 0;
                   1747: foreach my $action (@actions) {
                   1748:     $num ++;
                   1749:     my ($yesno,$defaultrun);
                   1750:     if (ref($recommended) eq 'HASH') {
1.4       raeburn  1751:         if (($action eq 'runlevels') || ($action eq 'stopsrvcs')) {
1.1       raeburn  1752:             $yesno = '[y/N]';
                   1753:             if (ref($recommended->{$action}) eq 'HASH') {
                   1754:                 if (keys(%{$recommended->{$action}}) > 0) {
                   1755:                     $yesno = &mt('~[Y/n~]');
                   1756:                     $defaultrun = 1;
                   1757:                 }
                   1758:             }
                   1759:         } else {
                   1760:             if ($action eq 'download') {
                   1761:                 if ($downloadstatus) {
                   1762:                     print "\n$downloadstatus\n";
                   1763:                 }
                   1764:             }
                   1765:             if ($recommended->{$action}) {
                   1766:                 $yesno = mt('~[Y/n~]');
                   1767:                 $defaultrun = 1;
                   1768:             } else {
                   1769:                 $yesno = &mt('~[y/N~]');
                   1770:             }
                   1771:         }
                   1772:         print $num.'. '.$prompts{$action}." $yesno ";
                   1773:         $callsub{$action} = &get_user_selection($defaultrun);
                   1774:     }
                   1775: }
                   1776: 
                   1777: my $lctarball = 'loncapa-current.tar.gz';
                   1778: my $sourcetarball = $lctarball;
                   1779: if ($callsub{'download'}) {
                   1780:     my ($production,$testing,$sizes) = &download_versionslist();
1.45.2.16  raeburn  1781:     my $homedir = '/root';
                   1782:     if ($distro =~ /^ubuntu/) {
                   1783:         if ($instdir ne $homedir) {
                   1784:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   1785:         }
                   1786:     }
1.1       raeburn  1787:     if ($production && $testing) {
                   1788:         if ($production ne $testing) {
                   1789:             print &mt('Two recent LON-CAPA releases are available: ')."\n".
1.3       raeburn  1790:                   &mt('1.').' '.&mt('A production release - version: [_1].',$production)."\n".
                   1791:                   &mt('2.').' '.&mt('A testing release - version: [_1].',$testing)."\n\n".
1.45.2.16  raeburn  1792:                   &mt("After download, the tar.gz file will be extracted into $homedir")."\n\n".
                   1793:                   &mt("Download the production release into $instdir? ~[Y/n~]");
1.1       raeburn  1794:             if (&get_user_selection(1)) {
1.4       raeburn  1795:                 $sourcetarball = 'loncapa-'.$production.'.tar.gz';
1.45.2.16  raeburn  1796:                 print "$sourcetarball will be downloaded into $instdir\n";
1.1       raeburn  1797:             } else {
                   1798:                 print "\n".&mt('Download the testing release? ~[Y/n~]');
                   1799:                 if (&get_user_selection(1)) {
1.4       raeburn  1800:                     $sourcetarball = 'loncapa-'.$testing.'.tar.gz';
1.45.2.16  raeburn  1801:                     print "$sourcetarball will be downloaded into $instdir\n";
                   1802:                 } else {
                   1803:                     $callsub{'download'} = 0;
1.1       raeburn  1804:                 }
                   1805:             }
                   1806:         }
                   1807:     } elsif ($production) {
                   1808:         print &mt('The most recent LON-CAPA release is version: [_1].',$production)."\n".
1.45.2.16  raeburn  1809:               &mt("After download, the tar.gz file will be extracted into $homedir")."\n\n".
                   1810:               &mt("Download the production release into $instdir? ~[Y/n~]");
1.1       raeburn  1811:         if (&get_user_selection(1)) {
1.20      raeburn  1812:             $sourcetarball = 'loncapa-'.$production.'.tar.gz';
1.45.2.16  raeburn  1813:             print "$sourcetarball will be downloaded into $instdir\n";
                   1814:         } else {
                   1815:             $callsub{'download'} = 0;
1.1       raeburn  1816:         }
                   1817:     }
                   1818: } elsif ($filetouse ne '') {
                   1819:     $sourcetarball = $filetouse;
                   1820: }
                   1821: 
                   1822: print_and_log("\n");
                   1823: 
                   1824: # Each action: report if skipping, or perform action and provide feedback. 
                   1825: if ($callsub{'wwwuser'}) {
                   1826:     &setup_www();
                   1827: } else {
                   1828:     &print_and_log(&mt('Skipping creation of user [_1].',"'www'")."\n");
                   1829: }
                   1830: 
                   1831: if ($callsub{'pwauth'}) {
1.4       raeburn  1832:     &build_and_install_mod_auth_external($instdir);
1.1       raeburn  1833: } else {
                   1834:     &print_and_log(&mt('Skipping [_1] installation.',"'pwauth'")."\n");
                   1835: }
                   1836: 
                   1837: if ($callsub{'mysql'}) {
                   1838:     if ($dbh) {
1.45.2.9  raeburn  1839:         &setup_mysql($callsub{'mysqlperms'},$dbh,$has_pass,
1.45.2.15  raeburn  1840:                      $mysql_unix_socket,$has_lcdb,$distro);
1.1       raeburn  1841:     } else {
                   1842:         print &mt('Unable to configure MySQL because access is denied.')."\n";
                   1843:     }
                   1844: } else {
                   1845:     &print_and_log(&mt('Skipping configuration of MySQL.')."\n");
                   1846:     if ($callsub{'mysqlperms'}) {
                   1847:         if ($dbh) {
1.45.2.9  raeburn  1848:             &setup_mysql_permissions($dbh,$has_pass,$mysql_unix_socket);
1.1       raeburn  1849:         } else {
                   1850:             print &mt('Unable to configure MySQL because access is denied.')."\n";  
                   1851:         }
                   1852:     } else {
                   1853:         &print_and_log(&mt('Skipping MySQL permissions setup.')."\n");
                   1854:     }
                   1855: }
                   1856: 
                   1857: if ($dbh) {
                   1858:     if (!$dbh->disconnect) {
                   1859:         &print_and_log(&mt('Failed to disconnect from MySQL:')."\n".
                   1860:                        $dbh->errstr);
                   1861:     }
                   1862: }
                   1863: 
                   1864: if ($callsub{'apache'}) {
                   1865:     if ($distro =~ /^(suse|sles)/) {
1.45.2.1  raeburn  1866:         &copy_apache2_suseconf($instdir,$distro);
1.1       raeburn  1867:     } elsif ($distro =~ /^(debian|ubuntu)/) {
1.28      raeburn  1868:         &copy_apache2_debconf($instdir,$distro);
1.1       raeburn  1869:     } else {
1.14      raeburn  1870:         &copy_httpd_conf($instdir,$distro);
1.45.2.5  raeburn  1871:         &copy_mpm_conf($instdir,$distro);
1.1       raeburn  1872:     }
                   1873: } else {
                   1874:     print_and_log(&mt('Skipping configuration of Apache web server.')."\n");
                   1875: }
                   1876: 
1.45.2.20  raeburn  1877: if ($callsub{'systemd'}) {
                   1878:     &check_systemd_update($distro);
                   1879: } else {
                   1880:     print_and_log('Skipping systemd configuration update for web server');
                   1881: }
                   1882: 
1.1       raeburn  1883: if ($callsub{'runlevels'}) {
                   1884:     my $count = 0;
                   1885:     if (ref($recommended) eq 'HASH') {
                   1886:         if (ref($recommended->{'runlevels'}) eq 'HASH') {
                   1887:             foreach my $type (keys(%{$recommended->{'runlevels'}})) {
                   1888:                 next if ($type eq 'insserv');
                   1889:                 $count ++;
                   1890:                 my $command = $recommended->{'runlevels'}{$type};
                   1891:                 if ($command ne '') {
                   1892:                     print_and_log(&mt('Runlevel update command run: [_1].',$command)."\n");
                   1893:                     system($command);
                   1894:                 }
                   1895:             }
                   1896:             if (!$count) {
                   1897:                 print_and_log(&mt('No runlevel updates required.')."\n");
                   1898:             }  
                   1899:         }
                   1900:     }
1.45.2.1  raeburn  1901:     if ($distro =~ /^(suse|sles)(\d+)/) {
                   1902:         unless(($1 eq 'sles') && ($2 >= 15)) {
                   1903:             &update_SuSEfirewall2_setup($instdir);
                   1904:         }
1.11      raeburn  1905:     }
1.1       raeburn  1906: } else {
                   1907:     &print_and_log(&mt('Skipping setting override for start-up order of services.')."\n");
                   1908: }
                   1909: 
                   1910: if ($callsub{'firewall'}) {
1.45.2.3  raeburn  1911:     my ($firewalld,$zone) = &uses_firewalld($distro);
                   1912:     if ($firewalld) {
1.45.2.1  raeburn  1913:         my (%current,%added);
1.45.2.3  raeburn  1914:         if (open(PIPE,"firewall-cmd --permanent --zone=$zone --list-services |")) {
1.45.2.1  raeburn  1915:             my $svc = <PIPE>;
                   1916:             close(PIPE);
                   1917:             chomp($svc);
                   1918:             map { $current{$_} = 1; } (split(/\s+/,$svc));
                   1919:         }
                   1920:         foreach my $service ('http','https') {
                   1921:             unless ($current{$service}) {
1.45.2.3  raeburn  1922:                 if (open(PIPE,"firewall-cmd --permanent --zone=$zone --add-service=$service |")) {
1.45.2.1  raeburn  1923:                     my $result = <PIPE>;
                   1924:                     if ($result =~ /^success/) {
                   1925:                         $added{$service} = 1;
                   1926:                     }
                   1927:                 }
                   1928:             }
                   1929:         }
                   1930:         if (keys(%added) > 0) {
                   1931:             print &mt('Firewall configured to allow access for: [_1].',
                   1932:                       join(', ',sort(keys(%added))))."\n";
1.45.2.13  raeburn  1933:             system('firewall-cmd --reload');
1.45.2.1  raeburn  1934:         }
                   1935:         if ($current{'http'} || $current{'https'}) {
                   1936:             print &mt('Firewall already configured to allow access for:[_1].',
                   1937:                       (($current{'http'})? ' http':'').(($current{'https'})? ' https':''))."\n";
                   1938:         }
                   1939:         unless ($current{'ssh'}) {
1.45.2.13  raeburn  1940:             print &mt('If you would like to allow access to ssh from outside, use the commands:')."\n".
                   1941:                   "firewall-cmd --permanent --zone=$zone --add-service=ssh\n".
                   1942:                   "firewall-cmd --reload\n";
1.45.2.1  raeburn  1943:         }
                   1944:     } elsif ($distro =~ /^(suse|sles)/) {
1.5       raeburn  1945:         print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1946:                   'yast -- Security and Users -> Firewall -> Interfaces',
1.45.2.1  raeburn  1947:                   'ssh, http, https')."\n";
1.5       raeburn  1948:     } elsif ($distro =~ /^(debian|ubuntu)(\d+)/) {
                   1949:         if (($1 eq 'ubuntu') || ($2 > 5)) {
                   1950:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1951:                       'ufw','ssh, http, https')."\n";
                   1952:         } else {
                   1953:             my $fwadded = &get_iptables_rules($distro,$instdir,$apachefw);
                   1954:             if ($fwadded) {
                   1955:                 print &mt('Enable firewall? ~[Y/n~]');
                   1956:                 my $enable_iptables = &get_user_selection(1);
                   1957:                 if ($enable_iptables) {
                   1958:                     system('/etc/network/if-pre-up.d/iptables');
                   1959:                     print &mt('Firewall enabled using rules defined in [_1].',
                   1960:                               '/etc/iptables.loncapa.rules'); 
                   1961:                 }
                   1962:             }
                   1963:         }
1.45.2.3  raeburn  1964:     } elsif ($distro =~ /^(scientific|oracle)/) {
1.11      raeburn  1965:         print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1966:                   'system-config-firewall-tui -- Customize',
                   1967:                   'ssh, http')."\n";
1.1       raeburn  1968:     } else {
1.45.2.3  raeburn  1969:         my $version;
1.45.2.18  raeburn  1970:         if ($distro =~ /^(redhat|centos|rocky|alma)(\d+)/) {
1.45.2.3  raeburn  1971:             $version = $1;
                   1972:         }
                   1973:         if ($version > 5) {
                   1974:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1975:                   'system-config-firewall-tui -- Customize',
                   1976:                   'ssh, http')."\n";
                   1977:         } else {
                   1978:             print &mt('Use [_1] to configure the firewall to allow access for [_2].',
                   1979:                       'setup -- Firewall configuration -> Customize',
                   1980:                       'ssh, http, https')."\n";
                   1981:         }
1.1       raeburn  1982:     }
                   1983: } else {
1.5       raeburn  1984:     &print_and_log(&mt('Skipping Firewall configuration.')."\n");
1.1       raeburn  1985: }
                   1986: 
                   1987: if ($callsub{'stopsrvcs'}) {
1.45      raeburn  1988:     &kill_extra_services($distro,$recommended->{'stopsrvcs'},$uses_systemctl);
1.1       raeburn  1989: } else {
1.10      raeburn  1990:     &print_and_log(&mt('Skipping stopping unnecessary service ([_1] daemons).',"'cups','memcached'")."\n");
1.1       raeburn  1991: }
                   1992: 
                   1993: my ($have_tarball,$updateshown);
                   1994: if ($callsub{'download'}) {
                   1995:     ($have_tarball,$updateshown) = &download_loncapa($instdir,$sourcetarball);
                   1996: } else {
                   1997:     print_and_log(&mt('Skipping download of LON-CAPA tar file.')."\n\n");
                   1998:     print &mt('LON-CAPA is available for download from: [_1]',
                   1999:               'http://install.loncapa.org/')."\n";
                   2000:     if (!-e '/etc/loncapa-release') {
1.45.2.19  raeburn  2001:         &print_and_log(&mt('LON-CAPA is not yet installed on your system.')."\n\n");
                   2002:         unless ($filetouse) {
                   2003:             &print_and_log(&mt('You may retrieve the source for LON-CAPA by executing:')."\n".
                   2004:                            "wget http://install.loncapa.org/versions/$lctarball\n");
                   2005:         }
1.1       raeburn  2006:     } else {
                   2007:         my $currentversion;
                   2008:         if (open(my $fh,"</etc/loncapa-release")) {
                   2009:             my $version = <$fh>;
                   2010:             chomp($version);
                   2011:             if ($version =~ /^\QLON-CAPA release \E([\w\-.]+)$/) {
                   2012:                 $currentversion = $1;
                   2013:             }
                   2014:         }
                   2015:         if ($currentversion ne '') {
                   2016:             print &mt('Version of LON-CAPA currently installed on this server is: [_1].',
                   2017:                       $currentversion),"\n";
                   2018:             if ($production) {
                   2019:                 print &mt('The latest production release of LON-CAPA is [_1].',$production)."\n";
                   2020:             }
                   2021:             if ($testing) {
                   2022:                 print &mt('The latest testing release of LON-CAPA is [_1].',$testing)."\n";
                   2023:             }
                   2024:         }
                   2025:     }
                   2026:     if ($filetouse ne '') {
                   2027:         $have_tarball = 1;
                   2028:     }
                   2029: }
                   2030: 
                   2031: print "\n".&mt('Requested configuration complete.')."\n\n";
                   2032: if ($have_tarball && !$updateshown) {
                   2033:     my ($lcdir) = ($sourcetarball =~ /^([\w.\-]+)\.tar.gz$/);
1.45.2.16  raeburn  2034:     if ($lcdir eq 'loncapa-current') {
                   2035:         $lcdir = "loncapa-X.Y.Z (X.Y.Z should correspond to a version number like '2.11.3')";
                   2036:     }
1.45.2.14  raeburn  2037:     my ($apachename,$lc_uses_systemctl,$uses_sudo);
1.45.2.12  raeburn  2038:     if ($distro =~ /^(suse|sles|debian|ubuntu)([\d.]+)/) {
                   2039:         if (($1 eq 'suse') && ($2 < 10)) {
                   2040:             $apachename = 'apache';
                   2041:         } else {
                   2042:             $apachename = 'apache2';
                   2043:         }
                   2044:     } else {
                   2045:         $apachename = 'httpd';
                   2046:     }
                   2047:     if ($distro =~ /^oracle(\d+)$/) {
                   2048:         if ($1 > 6) {
                   2049:             $lc_uses_systemctl = 1;
                   2050:         }
1.45.2.18  raeburn  2051:     } elsif ($distro =~ /^(?:rhes|centos|rocky|alma)(\d+)/) {
1.45.2.12  raeburn  2052:         if ($1 > 7) {
                   2053:             $lc_uses_systemctl = 1;
                   2054:         }
                   2055:     } elsif ($distro =~ /^ubuntu(\d+)$/) {
                   2056:         if ($1 > 16) {
                   2057:             $lc_uses_systemctl = 1;
                   2058:         }
                   2059:         $uses_sudo = 1;
1.45.2.19  raeburn  2060:     } elsif ($distro =~ /^debian(\d+)$/) {
                   2061:         if ($1 >= 10) {
                   2062:             $lc_uses_systemctl = 1;
                   2063:         }
1.45.2.12  raeburn  2064:     } elsif ($distro =~ /^sles(\d+)$/) {
                   2065:         if ($1 > 12) {
                   2066:             $lc_uses_systemctl = 1;
                   2067:         }
1.45.2.20  raeburn  2068:     } elsif ($distro =~ /^fedora(\d+)$/) {
                   2069:         if ($1 > 25) {
                   2070:             $lc_uses_systemctl = 1;
                   2071:         }
1.45.2.12  raeburn  2072:     }
1.1       raeburn  2073:     if (!-e '/etc/loncapa-release') {
                   2074:         print &mt('If you are now ready to install LON-CAPA, enter the following commands:')."\n\n";
                   2075:     } else {
1.45.2.12  raeburn  2076:         my $lcstop = '/etc/init.d/loncontrol stop';
                   2077:         if ($lc_uses_systemctl) {
                   2078:             $lcstop = 'systemctl stop loncontrol';
                   2079:         }
                   2080:         my $apachestop = "/etc/init.d/$apachename stop";
                   2081:         if ($uses_systemctl) {
                   2082:             $apachestop = "systemctl stop $apachename";
                   2083:         }
                   2084:         if ($uses_sudo) {
1.45.2.16  raeburn  2085:             $lcstop = 'sudo '.$lcstop;
1.45.2.12  raeburn  2086:             $apachestop = 'sudo '.$apachestop;
1.1       raeburn  2087:         }
1.45.2.12  raeburn  2088:         print &mt('If you are now ready to update LON-CAPA, enter the following commands:').
                   2089:               "\n\n$lcstop\n$apachestop\n";
1.1       raeburn  2090:     }
1.45.2.16  raeburn  2091:     my ($extract,$update);
                   2092:     my $homedir = '/root';
                   2093:     if ($uses_sudo) {
                   2094:         $extract = 'sudo ';
                   2095:         $update = 'sudo ';
                   2096:         if ($instdir ne $homedir) {
                   2097:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   2098:         }
                   2099:     }
                   2100:     $extract .= "tar zxf $sourcetarball --directory $homedir";
                   2101:     $update .= './UPDATE';
                   2102:     print "$extract\n".
                   2103:           "cd $homedir/$lcdir\n".
                   2104:           "$update\n";
1.1       raeburn  2105:     if (-e '/etc/loncapa-release') {
1.45.2.19  raeburn  2106:         my $lcstart = '/etc/init.d/loncontrol start';
1.45.2.12  raeburn  2107:         if ($lc_uses_systemctl) {
                   2108:             $lcstart = '/home/httpd/perl/loncontrol start';
                   2109:         }
                   2110:         my $apachestart = "/etc/init.d/$apachename start";
                   2111:         if ($uses_systemctl) {
                   2112:             $apachestart = "systemctl start $apachename";
                   2113:         }
                   2114:         if ($uses_sudo) {
                   2115:             $lcstart = 'sudo '.$lcstart;
                   2116:             $apachestart = 'sudo '.$apachestart;
                   2117:         }
                   2118:         print "$lcstart\n";
                   2119:         print "$apachestart\n";
1.1       raeburn  2120:     }
                   2121: }
                   2122: exit;
                   2123: 
                   2124: #
                   2125: # End main script
                   2126: #
                   2127: 
                   2128: #
                   2129: # Routines for the actions
                   2130: #
                   2131:  
                   2132: sub setup_www {
                   2133:     ##
                   2134:     ## Set up www
                   2135:     ##
                   2136:     print_and_log(&mt('Creating user [_1]',"'www'")."\n");
                   2137:     # -- Add group
                   2138: 
                   2139:     my $status = `/usr/sbin/groupadd www`;
                   2140:     if ($status =~ /\QGroup `www' already exists.\E/) {
                   2141:         print &mt('Group [_1] already exists.',"'www'")."\n";
                   2142:     } elsif ($status ne '') {
                   2143:         print &mt('Unable to add group [_1].',"'www'")."\n";
                   2144:     }
                   2145:    
                   2146:     my $gid = getgrnam('www');
                   2147: 
                   2148:     if (open (PIPE, "/usr/sbin/useradd -c LONCAPA -g $gid www 2>&1 |")) {
                   2149:         $status = <PIPE>;
                   2150:         close(PIPE);
                   2151:         chomp($status);
                   2152:         if ($status =~ /\QAccount `www' already exists.\E/) {
                   2153:             print &mt('Account [_1] already exists.',"'www'")."\n";
                   2154:         } elsif ($status ne '') {
                   2155:             print &mt('Unable to add user [_1].',"'www'")."\n";
                   2156:         }
                   2157:     }  else {
                   2158:         print &mt('Unable to run command to add user [_1].',"'www'")."\n";
                   2159:     }
                   2160: 
                   2161:     my $uid = &uid_of_www();
                   2162:     if (($gid ne '') && ($uid ne '')) {
                   2163:         if (!-e '/home/www') {
                   2164:             mkdir('/home/www',0755);
                   2165:             system('chown www:www /home/www');
                   2166:         }
                   2167:     }
                   2168:     writelog ($status);
                   2169: }
                   2170: 
                   2171: sub uid_of_www {
                   2172:     my ($num) = (getpwnam('www'))[2];
                   2173:     return $num;
                   2174: }
                   2175: 
                   2176: sub build_and_install_mod_auth_external {
                   2177:     my ($instdir) = @_;
                   2178:     my $num = &uid_of_www();
                   2179:     # Patch pwauth
                   2180:     print_and_log(&mt('Building authentication system for LON-CAPA users.')."\n");
                   2181:     my $patch = <<"ENDPATCH";
                   2182: 148c148
                   2183: < #define SERVER_UIDS 99		/* user "nobody" */
                   2184: ---
                   2185: > #define SERVER_UIDS $num		/* user "www" */
                   2186: ENDPATCH
                   2187: 
1.45.2.19  raeburn  2188:     my $patch_code = <<"ENDPATCH";
                   2189: 127a128
                   2190: > #include <string.h>
                   2191: 214a216
                   2192: > #include <time.h>
                   2193: 566c568
                   2194: < check_fails()
                   2195: ---
                   2196: > int check_fails()
                   2197: 589c591
                   2198: < log_failure()
                   2199: ---
                   2200: > void log_failure()
                   2201: 629c631
                   2202: < snooze(int seconds)
                   2203: ---
                   2204: > void snooze(int seconds)
                   2205: 653c655
                   2206: < main(int argc, char **argv)
                   2207: ---
                   2208: > int main(int argc, char **argv)
                   2209: ENDPATCH
                   2210: 
1.1       raeburn  2211:     if (! -e "/usr/bin/patch") {
                   2212: 	print_and_log(&mt('You must install the software development tools package: [_1], when installing Linux.',"'patch'")."\n");
                   2213:         print_and_log(&mt('Authentication installation not completed.')."\n");
                   2214:         return;
                   2215:     }
                   2216:     if (&skip_if_nonempty(`cd /tmp; tar zxf $instdir/pwauth-2.2.8.tar.gz`,
                   2217: 		     &mt('Unable to extract pwauth')."\n")) {
                   2218:         return;
                   2219:     }
                   2220:     my $dir = "/tmp/pwauth-2.2.8";
1.45.2.19  raeburn  2221:     my $patchedok;
1.1       raeburn  2222:     if (open(PATCH,"| patch $dir/config.h")) {
                   2223:         print PATCH $patch;
                   2224:         close(PATCH);
1.45.2.19  raeburn  2225:         if (open(PATCH,"| patch $dir/pwauth.c")) {
                   2226:             print PATCH $patch_code;
                   2227:             close(PATCH);
                   2228:             $patchedok = 1;
                   2229:         }
                   2230:     }
                   2231:     if ($patchedok) {
1.1       raeburn  2232:         print_and_log("\n");
                   2233:         ##
                   2234:         ## Compile patched pwauth
                   2235:         ##
                   2236:         print_and_log(&mt('Compiling pwauth')."\n");
1.12      raeburn  2237:         my $result = `cd $dir/; make 2>/dev/null `;
1.1       raeburn  2238:         my $expected = <<"END";
                   2239: gcc -g    -c -o pwauth.o pwauth.c
                   2240: gcc -o pwauth -g  pwauth.o -lcrypt
                   2241: END
                   2242:         if ($result eq $expected) {
                   2243:             print_and_log(&mt('Apparent success compiling pwauth:').
                   2244:                           "\n".$result );
                   2245:             # Install patched pwauth
                   2246:             print_and_log(&mt('Copying pwauth to [_1]',' /usr/local/sbin')."\n");
                   2247:             if (copy "$dir/pwauth","/usr/local/sbin/pwauth") {
1.5       raeburn  2248:                 if (chmod(06755, "/usr/local/sbin/pwauth")) {
1.1       raeburn  2249:                     print_and_log(&mt('[_1] copied successfully',"'pwauth'").
                   2250:                                   "\n");
                   2251:                 } else {
                   2252:                     print &mt('Unable to set permissions on [_1].'.
                   2253:                               "/usr/local/sbin/pwauth")."\n";
                   2254:                 }
                   2255:             } else {
                   2256:                 print &mt('Unable to copy [_1] to [_2]',
                   2257:                           "'$dir/pwauth'","/usr/local/sbin/pwauth")."\n$!\n";
                   2258:             }
                   2259:         } else {
                   2260:             print &mt('Unable to compile patched [_1].'."'pwauth'")."\n";
                   2261:         }
                   2262:     } else {
                   2263:         print &mt('Unable to start patch for [_1]',"'pwauth'")."\n";
                   2264:     }
                   2265:     print_and_log("\n");
                   2266: }
                   2267: 
                   2268: sub kill_extra_services {
1.45      raeburn  2269:     my ($distro,$stopsrvcs,$uses_systemctl) = @_;
1.1       raeburn  2270:     if (ref($stopsrvcs) eq 'HASH') {
                   2271:         my @stopping = sort(keys(%{$stopsrvcs}));
                   2272:         if (@stopping) {
1.6       raeburn  2273:             my $kill_list = join("', '",@stopping);
1.1       raeburn  2274:             if ($kill_list) {
                   2275:                 $kill_list = "'".$kill_list."'";
1.6       raeburn  2276:                 &print_and_log("\n".&mt('Killing unnecessary services ([_1] daemon(s)).',$kill_list)."\n");
                   2277:                 foreach my $service (@stopping) {
                   2278:                     my $daemon = $service;
                   2279:                     if ($service eq 'cups') {
                   2280:                         $daemon = 'cupsd';
                   2281:                         if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                   2282:                             my $version = $1;
                   2283:                             if (($distro =~ /^ubuntu/) && ($version <= 8)) {
                   2284:                                 $daemon = 'cupsys';
                   2285:                             }
1.12      raeburn  2286:                         } else {
1.8       raeburn  2287:                             $daemon = 'cups';
1.6       raeburn  2288:                         }
                   2289:                     }
1.12      raeburn  2290:                     my $cmd = "ps -ef |grep '$daemon' |grep -v grep";
                   2291:                     if (open(PIPE,'-|',$cmd)) {
                   2292:                         my $daemonrunning = <PIPE>;
                   2293:                         chomp($daemonrunning);
                   2294:                         close(PIPE);
                   2295:                         if ($daemonrunning) {
                   2296:                             &print_and_log(`/etc/init.d/$daemon stop`);
                   2297:                         }
                   2298:                     }
1.1       raeburn  2299: 	            &print_and_log(&mt('Removing [_1] from startup.',$service)."\n");
1.45      raeburn  2300:                     if ($distro =~ /^(?:debian|ubuntu)(\d+)/) {
                   2301:                         my $version = $1;
1.45.2.19  raeburn  2302:                         if ((($distro =~ /^ubuntu/) && ($version > 16)) ||
                   2303:                             (($distro =~ /^debian/) && ($version >= 10))) {
1.45      raeburn  2304:                             if (ref($uses_systemctl) eq 'HASH') {
                   2305:                                 if ($uses_systemctl->{$service}) {
                   2306:                                     if (`systemctl is-enabled $service`) {
                   2307:                                         &print_and_log(`systemctl disable $service`);
                   2308:                                     }
                   2309:                                 }
                   2310:                             }
                   2311:                         } else {
                   2312:                             &print_and_log(`update-rc.d -f $daemon remove`);
                   2313:                         }
1.1       raeburn  2314:                     } else {
1.35      raeburn  2315:                         if (ref($uses_systemctl) eq 'HASH') {
                   2316:                             if ($uses_systemctl->{$service}) {
                   2317:                                 if (`systemctl is-enabled $service`) {                          
                   2318:                                     &print_and_log(`systemctl disable $service`);
                   2319:                                 }
                   2320:                             } else {
                   2321:                                 &print_and_log(`/sbin/chkconfig --del $service`);
                   2322:                             }
                   2323:                         } else {
                   2324: 	                    &print_and_log(`/sbin/chkconfig --del $service`);
                   2325:                         } 
1.1       raeburn  2326:                     }
                   2327:                 }
                   2328:             }
                   2329:         }
                   2330:     }
                   2331:     return;
                   2332: }
                   2333: 
                   2334: sub setup_mysql {
1.45.2.15  raeburn  2335:     my ($setup_mysql_permissions,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$distro) = @_;
1.4       raeburn  2336:     my @mysql_lc_commands;
1.1       raeburn  2337:     unless ($has_lcdb) {
1.45.2.15  raeburn  2338:         my $createcmd = 'CREATE DATABASE loncapa';
                   2339:         if ($distro =~ /^sles(\d+)/) {
                   2340:             if ($1 > 11) {
                   2341:                 $createcmd .= ' CHARACTER SET utf8 COLLATE utf8_general_ci';
                   2342:             }
                   2343:         } elsif ($distro =~ /^ubuntu(\d+)/) {
                   2344:             if ($1 > 16) {
                   2345:                 $createcmd .= ' CHARACTER SET latin1 COLLATE latin1_swedish_ci';
                   2346:             }
                   2347:         }
                   2348:         push(@mysql_lc_commands,$createcmd);
1.1       raeburn  2349:     }
1.4       raeburn  2350:     push(@mysql_lc_commands,"USE loncapa");
                   2351:     push(@mysql_lc_commands,qq{
1.18      raeburn  2352: 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  2353: });
1.1       raeburn  2354:     if ($setup_mysql_permissions) {
1.45.2.9  raeburn  2355:         &setup_mysql_permissions($dbh,$has_pass,$mysql_unix_socket,@mysql_lc_commands);
1.1       raeburn  2356:     } else {
                   2357:         print_and_log(&mt('Skipping MySQL permissions setup.')."\n");
                   2358:         if ($dbh) {
1.4       raeburn  2359:             if (@mysql_lc_commands) {
                   2360:                 foreach my $lccmd (@mysql_lc_commands) { 
                   2361:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2362:                 }
                   2363:             }
1.1       raeburn  2364:             print_and_log(&mt('MySQL database set up complete.')."\n");
                   2365:         } else {
                   2366:             print_and_log(&mt('Problem accessing MySQL.')."\n");
                   2367:         }
                   2368:     }
                   2369: }
                   2370: 
                   2371: sub setup_mysql_permissions {
1.45.2.9  raeburn  2372:     my ($dbh,$has_pass,$mysql_unix_socket,@mysql_lc_commands) = @_;
1.45.2.19  raeburn  2373:     my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version();
1.45.2.9  raeburn  2374:     my ($usescreate,$usesauth,$is_mariadb,$hasauthcol,@mysql_commands);
1.38      raeburn  2375:     if ($mysqlname =~ /^MariaDB/i) {
1.45.2.2  raeburn  2376:         $is_mariadb = 1;
1.45.2.19  raeburn  2377:         if ((($mysqlversion == 10) && ($mysqlminorversion >= 4)) || ($mysqlversion >= 11)) {
1.45.2.9  raeburn  2378:             $usescreate = 1;
1.45.2.19  raeburn  2379:         } elsif (($mysqlversion == 10) && ($mysqlminorversion >= 2)) {
1.38      raeburn  2380:             $usesauth = 1;
1.45.2.19  raeburn  2381:         } elsif (($mysqlversion == 5) && ($mysqlminorversion >= 5)) {
1.42      raeburn  2382:             $hasauthcol = 1;
1.38      raeburn  2383:         }
                   2384:     } else {
1.45.2.19  raeburn  2385:         if (($mysqlversion > 5) || (($mysqlminorversion == 5) && ($mysqlminorversion > 7)) ||
                   2386:             (($mysqlversion == 5) && ($mysqlminorversion == 7) && ($mysqlsubver > 5))) {
1.38      raeburn  2387:             $usesauth = 1;
1.45.2.19  raeburn  2388:         } elsif (($mysqlversion == 5) &&
                   2389:                  (($mysqlminorversion >= 6) || (($mysqlminorversion == 5) && ($mysqlsubver >= 7)))) {
1.42      raeburn  2390:             $hasauthcol = 1;
1.38      raeburn  2391:         }
                   2392:     }
1.45.2.9  raeburn  2393:     if ($usescreate) {
                   2394:         @mysql_commands = ("CREATE USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'");
                   2395:     } elsif ($usesauth) {
1.45.2.15  raeburn  2396:         @mysql_commands = ("INSERT user (Host, User, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www','','','','')",
                   2397:                            "FLUSH PRIVILEGES");
1.45.2.2  raeburn  2398:         if ($is_mariadb) {
                   2399:             push(@mysql_commands,"ALTER USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'");
                   2400:         } else {
                   2401:             push(@mysql_commands,"ALTER USER 'www'\@'localhost' IDENTIFIED WITH mysql_native_password BY 'localhostkey'");
                   2402:         }
1.42      raeburn  2403:     } elsif ($hasauthcol) {
                   2404:         @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject, authentication_string) VALUES('localhost','www',password('localhostkey'),'','','','');");
1.36      raeburn  2405:     } else {
1.42      raeburn  2406:         @mysql_commands = ("INSERT user (Host, User, Password, ssl_cipher, x509_issuer, x509_subject) VALUES('localhost','www',password('localhostkey'),'','','');");
1.36      raeburn  2407:     }
1.1       raeburn  2408:     if ($mysqlversion < 4) {
1.4       raeburn  2409:         push (@mysql_commands,"
                   2410: 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')");
                   2411:     } else {
                   2412:         push (@mysql_commands,"
                   2413: 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  2414:     }
1.4       raeburn  2415:     push(@mysql_commands,"DELETE FROM user WHERE host<>'localhost'");
1.45.2.9  raeburn  2416:     if (($has_pass) || ($mysql_unix_socket)) {
1.1       raeburn  2417:         if ($dbh) {
1.4       raeburn  2418:             push(@mysql_commands,"FLUSH PRIVILEGES");
                   2419:             if (@mysql_commands) {
                   2420:                 foreach my $cmd (@mysql_commands) {
                   2421:                     $dbh->do($cmd) || print $dbh->errstr."\n";
                   2422:                 }
                   2423:             }
                   2424:             if (@mysql_lc_commands) {
                   2425:                 foreach my $lccmd (@mysql_lc_commands) {
                   2426:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2427:                 }
                   2428:             }
1.1       raeburn  2429:             print_and_log(&mt('Permissions set for LON-CAPA MySQL user: [_1]',"'www'")."\n");
                   2430:         } else {
                   2431:             print_and_log(&mt('Problem accessing MySQL.')."\n".
                   2432:                           &mt('Permissions not set.')."\n");
                   2433:         }
                   2434:     } else {
                   2435:         my ($firstpass,$secondpass,$got_passwd,$newmysqlpass);
                   2436:         print &mt('Please enter a root password for the mysql database.')."\n".
                   2437:               &mt('It does not have to match your root account password, but you will need to remember it.')."\n";
                   2438:         my $maxtries = 10;
                   2439:         my $trial = 0;
                   2440:         while ((!$got_passwd) && ($trial < $maxtries)) {
                   2441:             $firstpass = &get_mysql_password(&mt('Enter password'));
                   2442:             if (length($firstpass) > 5) { 
                   2443:                 $secondpass = &get_mysql_password(&mt('Enter password a second time'));
                   2444:                 if ($firstpass eq $secondpass) {
                   2445:                     $got_passwd = 1;
                   2446:                     $newmysqlpass = $firstpass;
                   2447:                 } else {
                   2448:                     print(&mt('Passwords did not match. Please try again.')."\n");
                   2449:                 }
                   2450:                 $trial ++;
                   2451:             } else {
                   2452:                 print(&mt('Password too short.')."\n".
                   2453:                       &mt('Please choose a password with at least six characters.')."\n");
                   2454:             }
                   2455:         }
                   2456:         if ($got_passwd) {
1.45.2.2  raeburn  2457:             my (@newpass_cmds) = &new_mysql_rootpasswd($newmysqlpass,$usesauth,$is_mariadb);
1.4       raeburn  2458:             push(@mysql_commands,@newpass_cmds);
1.1       raeburn  2459:         } else {
                   2460:             print_and_log(&mt('Failed to get MySQL root password from user input.')."\n");
                   2461:         }
                   2462:         if ($dbh) {
1.4       raeburn  2463:             if (@mysql_commands) {
                   2464:                 foreach my $cmd (@mysql_commands) {
                   2465:                     $dbh->do($cmd) || print $dbh->errstr."\n";
                   2466:                 }
                   2467:             }
                   2468:             if (@mysql_lc_commands) {
                   2469:                 foreach my $lccmd (@mysql_lc_commands) {
                   2470:                     $dbh->do($lccmd) || print $dbh->errstr."\n";
                   2471:                 }
                   2472:             }
1.1       raeburn  2473:             if ($got_passwd) {
                   2474:                 print_and_log(&mt('MySQL root password stored.')."\n".
                   2475:                               &mt('Permissions set for LON-CAPA MySQL user: [_1].',"'www'")."\n");
                   2476:             } else {
                   2477:                 print_and_log(&mt('Permissions set for LON-CAPA MySQL user: [_1].',"'www'")."\n");
                   2478:             }
                   2479:         } else {
                   2480:             print_and_log(&mt('Problem accessing MySQL.')."\n".
                   2481:                           &mt('Permissions not set.')."\n");
                   2482:         }
                   2483:     }
                   2484: }
                   2485: 
                   2486: sub new_mysql_rootpasswd {
1.45.2.2  raeburn  2487:     my ($currmysqlpass,$usesauth,$is_mariadb) = @_;
1.36      raeburn  2488:     if ($usesauth) {
1.45.2.2  raeburn  2489:         if ($is_mariadb) {
                   2490:             return ("ALTER USER 'root'\@'localhost' IDENTIFIED BY '$currmysqlpass'",
                   2491:                     "FLUSH PRIVILEGES;");
                   2492:         } else {
                   2493:             return ("ALTER USER 'root'\@'localhost' IDENTIFIED WITH mysql_native_password BY '$currmysqlpass'",
                   2494:                     "FLUSH PRIVILEGES;");
                   2495:         }
1.36      raeburn  2496:     } else {
                   2497:         return ("SET PASSWORD FOR 'root'\@'localhost'=PASSWORD('$currmysqlpass')",
                   2498:                 "FLUSH PRIVILEGES;");
                   2499:     }
1.1       raeburn  2500: }
                   2501: 
                   2502: sub get_mysql_version {
1.45.2.19  raeburn  2503:     my ($version,$minorversion,$subversion,$name);
1.1       raeburn  2504:     if (open(PIPE," mysql -V |")) {
                   2505:         my $info = <PIPE>;
                   2506:         chomp($info);
                   2507:         close(PIPE);
1.45.2.19  raeburn  2508:         ($version,$minorversion,$subversion,$name) = ($info =~ /(\d+)\.(\d+)\.(\d+)(?:\-?(\w*),|)/);
1.1       raeburn  2509:     } else {
                   2510:         print &mt('Could not determine which version of MySQL is installed.').
                   2511:               "\n";
                   2512:     }
1.45.2.19  raeburn  2513:     return ($version,$minorversion,$subversion,$name);
1.1       raeburn  2514: }
                   2515: 
1.45.2.20  raeburn  2516: sub check_systemd_update {
                   2517:     my ($distro) = @_;
                   2518:     my ($use_systemctl,$service);
                   2519:     $service = 'apache2.service';
                   2520:     if ($distro =~ /^ubuntu(\w+)/) {
                   2521:         if ($1 >= 16) {
                   2522:             $use_systemctl = 1;
                   2523:         }
                   2524:     } elsif ($distro =~ /^debian(\w+)/) {
                   2525:         if ($1 >= 9) {
                   2526:             $use_systemctl = 1;
                   2527:         }
                   2528:     } elsif ($distro =~ /^fedora(\d+)/) {
                   2529:         $service = 'httpd.service';
                   2530:         if ($1 >= 16) {
                   2531:             $use_systemctl = 1;
                   2532:         }
                   2533:     } elsif ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
                   2534:         $service = 'httpd.service';
                   2535:         if ($1 >= 7) {
                   2536:             $use_systemctl = 1;
                   2537:         }
                   2538:     } elsif ($distro =~ /^sles(\d+)/) {
                   2539:         if ($1 >= 12) {
                   2540:             $use_systemctl = 1;
                   2541:         }
                   2542:     } elsif ($distro =~ /^suse(\d+)/) {
                   2543:         if ($1 >= 13) {
                   2544:             $use_systemctl = 1;
                   2545:         }
                   2546:     }
                   2547:     if ($use_systemctl) {
                   2548:         my $needsupdate = &check_systemd_security($distro);
                   2549:         if ($needsupdate) {
                   2550:             if (!-d '/etc/systemd/system/'.$service.'.d') {
                   2551:                 mkdir '/etc/systemd/system/'.$service.'.d', 0755;
                   2552:             }
                   2553:             if (-d '/etc/systemd/system/'.$service.'.d') {
                   2554:                 if (-e '/etc/systemd/system/'.$service.'.d/override.conf') {
                   2555:                     if (open(my $fh,'<','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2556:                         my ($inservice,$addservice,$protectoff,$linenum,$change,@lines);
                   2557:                         while (my $entry = <$fh>) {
                   2558:                             $linenum ++;
                   2559:                             chomp($entry);
                   2560:                             if ($entry eq '[Service]') {
                   2561:                                 if (!$protectoff) {
                   2562:                                     $inservice = $linenum;
                   2563:                                     push(@lines,$entry);
                   2564:                                 } else {
                   2565:                                     $addservice = 1;
                   2566:                                     next;
                   2567:                                 }
                   2568:                             }
                   2569:                             if ($entry =~ /^ProtectHome\s*=\s*([\w-]+)\s*$/) {
                   2570:                                 my $value = $1;
                   2571:                                 if ($protectoff) {
                   2572:                                     next;
                   2573:                                     if (lc($value) eq 'no') {
                   2574:                                         $protectoff = $linenum;
                   2575:                                         push(@lines,$entry);
                   2576:                                     } else {
                   2577:                                         if ($protectoff) {
                   2578:                                             next;
                   2579:                                         } else {
                   2580:                                             push(@lines,'ProtectHome=no');
                   2581:                                             $protectoff = $linenum;
                   2582:                                             $change = $linenum;
                   2583:                                         }
                   2584:                                     }
                   2585:                                 }
                   2586:                             }
                   2587:                         }
                   2588:                         close($fh);
                   2589:                         if ($addservice || $change || !$protectoff) {
                   2590:                             if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2591:                                 if ($addservice) {
                   2592:                                     print $fh "[Service]\n";
                   2593:                                 }
                   2594:                                 foreach my $entry (@lines) {
                   2595:                                     print $fh "$entry\n";
                   2596:                                 }
                   2597:                                 close($fh);
                   2598:                                 print_and_log('Updated /etc/systemd/system/'.$service.'.d/override.conf');
1.45.2.21  raeburn  2599:                                 system('systemctl daemon-reload');
1.45.2.20  raeburn  2600:                             } else {
                   2601:                                 print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for writing.');
                   2602:                             }
                   2603:                         } else {
                   2604:                             print_and_log('No change needed in /etc/systemd/system/'.$service.'.d/override.conf');
                   2605:                         }
                   2606:                     } else {
                   2607:                         print_and_log('Could not open /etc/systemd/system/'.$service.'.d/override.conf for reading.');
                   2608:                     }
                   2609:                 } else {
                   2610:                     if (open(my $fh,'>','/etc/systemd/system/'.$service.'.d/override.conf')) {
                   2611:                         print $fh '[Service]'."\n".'ProtectHome=no'."\n";
                   2612:                         close($fh);
                   2613:                         print_and_log('Created /etc/systemd/system/'.$service.'.d/override.conf');
1.45.2.21  raeburn  2614:                         system('systemctl daemon-reload');
1.45.2.20  raeburn  2615:                     }
                   2616:                 }
                   2617:             } else {
                   2618:                 print_and_log('No /etc/systemd/system/'.$service.'.d directory exists and creating one failed,');
                   2619:             }
                   2620:         } else {
                   2621:             print_and_log('No update needed to systemd security settings for Apache web server.');
                   2622:         }
                   2623:     } else {
                   2624:         print_and_log('No update needed to systemd, as this Linux distro does not use systemctl');
                   2625:     }
                   2626: }
                   2627: 
1.1       raeburn  2628: ###########################################################
                   2629: ##
                   2630: ## RHEL/CentOS/Fedora/Scientific Linux
                   2631: ## Copy LON-CAPA httpd.conf to /etc/httpd/conf
                   2632: ##
                   2633: ###########################################################
                   2634: 
                   2635: sub copy_httpd_conf {
1.14      raeburn  2636:     my ($instdir,$distro) = @_;
                   2637:     my $configfile = 'httpd.conf';
1.45.2.18  raeburn  2638:     if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.29      raeburn  2639:         if ($1 >= 7) {
                   2640:             $configfile = 'apache2.4/httpd.conf';
                   2641:         } elsif ($1 > 5) {
1.14      raeburn  2642:             $configfile = 'new/httpd.conf';
                   2643:         }
                   2644:     } elsif ($distro =~ /^fedora(\d+)$/) {
1.29      raeburn  2645:         if ($1 > 17) {
                   2646:             $configfile = 'apache2.4/httpd.conf';
                   2647:         } elsif ($1 > 10) {
1.14      raeburn  2648:             $configfile = 'new/httpd.conf';
                   2649:         }
                   2650:     }
1.1       raeburn  2651:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'httpd.conf'",
                   2652:                   "'/etc/httpd/conf/httpd.conf'")."\n");
                   2653:     copy "/etc/httpd/conf/httpd.conf","/etc/httpd/conf/httpd.conf.original";
1.14      raeburn  2654:     copy "$instdir/centos-rhes-fedora-sl/$configfile","/etc/httpd/conf/httpd.conf";
1.5       raeburn  2655:     chmod(0444,"/etc/httpd/conf/httpd.conf");
1.1       raeburn  2656:     print_and_log("\n");
                   2657: }
                   2658: 
1.45.2.5  raeburn  2659: ###########################################################
                   2660: ##
                   2661: ## RHEL/CentOS/Fedora/Scientific Linux
                   2662: ## Copy LON-CAPA mpm.conf to /etc/httpd/conf.modules.d/00-mpm.conf
                   2663: ##
                   2664: ## The LON-CAPA mpm.conf enables the prefork MPM module in
                   2665: ## Apache. This is also the default for RHEL/CentOS/Oracle
                   2666: ## Linux 7 and earlier, and Fedora 26 and earlier. For more
                   2667: ## recent versions of those distros, the event MPM is enabled
                   2668: ## by default. After &copy_mpm_conf() is run, the prefork MPM
                   2669: ## module will be enabled instead of the event MPM module.
                   2670: ##
                   2671: ###########################################################
                   2672: 
                   2673: sub copy_mpm_conf {
                   2674:     my ($instdir,$distro) = @_;
                   2675:     my $mpmfile = 'mpm.conf';
                   2676:     if ((-e "/etc/httpd/conf.modules.d/00-mpm.conf") &&
                   2677:         (-e "$instdir/centos-rhes-fedora-sl/$mpmfile")) {
                   2678:         print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'mpm.conf'",
                   2679:                       "'/etc/httpd/conf.modules.d/00-mpm.conf'")."\n");
                   2680:         copy "$instdir/centos-rhes-fedora-sl/$mpmfile","/etc/httpd/conf.modules.d/00-mpm.conf";
                   2681:         chmod(0644,"/etc/httpd/conf.modules.d/00-mpm.conf");
                   2682:         print_and_log("\n");
                   2683:     } else {
                   2684:         my $logfail;
1.45.2.18  raeburn  2685:         if ($distro =~ /^(?:centos|rhes|scientific|oracle|rocky|alma)(\d+)/) {
1.45.2.5  raeburn  2686:             if ($1 > 7) {
                   2687:                 $logfail = 1;
                   2688:             }
                   2689:         } elsif ($distro =~ /^fedora(\d+)$/) {
                   2690:             if ($1 > 26) {
                   2691:                 $logfail = 1;
                   2692:             }
                   2693:         }
                   2694:         if ($logfail) {
                   2695:             print_and_log(&mt('Warning: copying the LON-CAPA [_1] failed because [_2] and/or [_3] are missing.',
                   2696:                               $mpmfile,"'$instdir/centos-rhes-fedora-sl/$mpmfile'",
                   2697:                               "'/etc/httpd/conf.modules.d/00-mpm.conf'"));
                   2698:             print_and_log("\n");
                   2699:         }
                   2700:     }
                   2701: }
                   2702: 
1.1       raeburn  2703: #########################################################
                   2704: ##
1.17      raeburn  2705: ## Ubuntu/Debian -- copy our loncapa configuration file to
1.1       raeburn  2706: ## sites-available and set the symlink from sites-enabled.
                   2707: ##
                   2708: #########################################################
                   2709: 
                   2710: sub copy_apache2_debconf {
1.28      raeburn  2711:     my ($instdir,$distro) = @_;
1.6       raeburn  2712:     my $apache2_mods_enabled_dir = '/etc/apache2/mods-enabled';
                   2713:     my $apache2_mods_available_dir = '/etc/apache2/mods-available';
                   2714:     foreach my $module ('headers.load','expires.load') {
                   2715:         unless (-l "$apache2_mods_enabled_dir/$module") {
                   2716:             symlink("$apache2_mods_available_dir/$module","$apache2_mods_enabled_dir/$module");
                   2717:             print_and_log(&mt('Enabling "[_1]" Apache module.',$module)."\n");
                   2718:         }
                   2719:     }
1.28      raeburn  2720:     my $apache2_sites_enabled_dir = '/etc/apache2/sites-enabled';
                   2721:     my $apache2_sites_available_dir = '/etc/apache2/sites-available';
                   2722:     my $defaultconfig = "$apache2_sites_enabled_dir/000-default";
1.45.2.10  raeburn  2723:     my $defaultsite = "$apache2_sites_enabled_dir/loncapa.conf";
1.28      raeburn  2724:     my ($distname,$version);
                   2725:     if ($distro =~ /^(debian|ubuntu)(\d+)$/) {
                   2726:         $distname = $1;
                   2727:         $version = $2;
                   2728:     }
1.45.2.19  raeburn  2729:     if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   2730:         (($distname eq 'debian') && ($version >= 10))) {
1.28      raeburn  2731:         $defaultconfig = "$apache2_sites_enabled_dir/000-default.conf";
                   2732:     }
1.45.2.7  raeburn  2733:     my ($skipconf,$skipsite,$skipstatus);
1.45.2.19  raeburn  2734:     if ((($distname eq 'ubuntu') && ($version > 12)) ||
                   2735:         (($distname eq 'debian') && ($version >= 10))) {
1.28      raeburn  2736:         my $apache2_conf_enabled_dir = '/etc/apache2/conf-enabled';
                   2737:         my $apache2_conf_available_dir = '/etc/apache2/conf-available';
1.33      raeburn  2738:         my $defaultconf = $apache2_conf_enabled_dir.'/loncapa.conf';
1.45.2.7  raeburn  2739:         if ((-e "$apache2_conf_available_dir/loncapa") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
1.45.2.8  raeburn  2740:             if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
1.45.2.7  raeburn  2741:                 my $diffres = <PIPE>;
                   2742:                 close(PIPE);
                   2743:                 chomp($diffres);
                   2744:                 if ($diffres) {
1.45.2.10  raeburn  2745:                     copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf.original");
                   2746:                 } else {
                   2747:                     copy("$apache2_conf_available_dir/loncapa","$apache2_conf_available_dir/loncapa.conf");
1.45.2.11  raeburn  2748:                     chdir($apache2_conf_enabled_dir);
                   2749:                     symlink('../conf-available/loncapa.conf','loncapa.conf');
                   2750:                     chdir($instdir);
1.45.2.7  raeburn  2751:                 }
                   2752:                 if (-l $defaultconf) {
                   2753:                     my $linkfname = readlink($defaultconf);
1.45.2.11  raeburn  2754:                     if ($linkfname ne '') {
                   2755:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
                   2756:                     }
1.45.2.7  raeburn  2757:                     if ($linkfname eq "$apache2_conf_available_dir/loncapa") {
1.45.2.10  raeburn  2758:                         unlink($defaultconf);
                   2759:                     }
                   2760:                 }
                   2761:                 unlink("$apache2_conf_available_dir/loncapa");
                   2762:             }
                   2763:         }
                   2764:         if ((-e "$apache2_conf_available_dir/loncapa.conf") && (-e "$instdir/debian-ubuntu/ubuntu14/loncapa_conf")) {
                   2765:             if (open(PIPE, "diff --brief $apache2_conf_available_dir/loncapa.conf $instdir/debian-ubuntu/ubuntu14/loncapa_conf |")) {
                   2766:                 my $diffres = <PIPE>;
                   2767:                 close(PIPE);
                   2768:                 chomp($diffres);
                   2769:                 if ($diffres) {
                   2770:                     copy("$apache2_conf_available_dir/loncapa.conf","$apache2_conf_available_dir/loncapa.conf.original");
                   2771:                 }
                   2772:                 if (-l $defaultconf) {
                   2773:                     my $linkfname = readlink($defaultconf);
1.45.2.11  raeburn  2774:                     if ($linkfname ne '') {
                   2775:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_conf_enabled_dir));
                   2776:                     }
1.45.2.10  raeburn  2777:                     if ($linkfname eq "$apache2_conf_available_dir/loncapa.conf") {
1.45.2.7  raeburn  2778:                         unless ($diffres) {
                   2779:                             $skipconf = 1;
                   2780:                         }
                   2781:                     }
                   2782:                 }
                   2783:             }
                   2784:         }
                   2785:         unless ($skipconf) {
                   2786:             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  2787:             copy("$instdir/debian-ubuntu/ubuntu14/loncapa_conf","$apache2_conf_available_dir/loncapa.conf");
                   2788:             chmod(0444,"$apache2_conf_available_dir/loncapa.conf");
1.45.2.7  raeburn  2789:             if (-l $defaultconf) {
                   2790:                 unlink($defaultconf);
                   2791:             }
1.45.2.11  raeburn  2792:             chdir($apache2_conf_enabled_dir);
                   2793:             symlink('../conf-available/loncapa.conf','loncapa.conf');
                   2794:             chdir($instdir);
1.45.2.7  raeburn  2795:         }
                   2796:         my $stdsite = "$instdir/debian-ubuntu/ubuntu14/loncapa_site";
                   2797:         if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa")) {
                   2798:             if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa |")) {
                   2799:                 my $diffres = <PIPE>;
                   2800:                 close(PIPE);
                   2801:                 chomp($diffres);
                   2802:                 if ($diffres) {
1.45.2.10  raeburn  2803:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf.original");
                   2804:                 } else {
                   2805:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.conf");
1.45.2.7  raeburn  2806:                 }
                   2807:                 if (-l $defaultconfig) {
                   2808:                     my $linkfname = readlink($defaultconfig);
1.45.2.11  raeburn  2809:                     if ($linkfname ne '') {
                   2810:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2811:                     }
1.45.2.7  raeburn  2812:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
1.45.2.10  raeburn  2813:                         unlink($defaultconfig);
                   2814:                     }
                   2815:                 }
                   2816:                 unlink("$apache2_sites_available_dir/loncapa");
                   2817:             }
                   2818:         }
                   2819:         if ((-e $stdsite) && (-e "$apache2_sites_available_dir/loncapa.conf")) {
                   2820:             if (open(PIPE, "diff --brief $stdsite $apache2_sites_available_dir/loncapa.conf |")) {
                   2821:                 my $diffres = <PIPE>;
                   2822:                 close(PIPE);
                   2823:                 chomp($diffres);
                   2824:                 if ($diffres) {
                   2825:                     copy("$apache2_sites_available_dir/loncapa.conf","$apache2_sites_available_dir/loncapa.conf.original");
                   2826:                 }
                   2827:                 if (-l $defaultsite) {
                   2828:                     my $linkfname = readlink($defaultsite);
1.45.2.11  raeburn  2829:                     if ($linkfname ne '') {
                   2830:                         $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2831:                     }
                   2832:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa.conf") {
1.45.2.7  raeburn  2833:                         unless ($diffres) {
                   2834:                             $skipsite = 1;
                   2835:                         }
                   2836:                     }
                   2837:                 }
                   2838:             }
                   2839:         }
                   2840:         unless ($skipsite) {
1.45.2.10  raeburn  2841:             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");
                   2842:             copy("$instdir/debian-ubuntu/ubuntu14/loncapa_site","$apache2_sites_available_dir/loncapa.conf");
                   2843:             chmod(0444,"$apache2_sites_available_dir/loncapa.conf");
1.45.2.11  raeburn  2844:             chdir($apache2_sites_enabled_dir);
                   2845:             symlink('../sites-available/loncapa.conf','loncapa.conf');
                   2846:             chdir($instdir);
1.45.2.10  raeburn  2847:         }
1.45.2.11  raeburn  2848:         if (-l $defaultconfig) {
1.45.2.10  raeburn  2849:             my $linkfname = readlink($defaultconfig);
1.45.2.11  raeburn  2850:             if ($linkfname ne '') {
                   2851:                 $linkfname = Cwd::abs_path(File::Spec->rel2abs($linkfname,$apache2_sites_enabled_dir));
                   2852:             }
                   2853:             if ($linkfname eq "$apache2_sites_available_dir/000-default.conf") {
1.45.2.10  raeburn  2854:                 unlink($defaultconfig);
                   2855:             }
1.45.2.7  raeburn  2856:         }
                   2857:     } else {
                   2858:         if ((-e "$instdir/debian-ubuntu/loncapa") && (-e "$apache2_sites_available_dir/loncapa")) {
                   2859:             if (open(PIPE, "diff --brief $instdir/debian-ubuntu/loncapa $apache2_sites_available_dir/loncapa |")) {
                   2860:                 my $diffres = <PIPE>;
                   2861:                 close(PIPE);
                   2862:                 chomp($diffres);
                   2863:                 if ($diffres) {
                   2864:                     copy("$apache2_sites_available_dir/loncapa","$apache2_sites_available_dir/loncapa.original");
                   2865:                 }
                   2866:                 if (-l $defaultconfig) {
                   2867:                     my $linkfname = readlink($defaultconfig);
                   2868:                     if ($linkfname eq "$apache2_sites_available_dir/loncapa") {
                   2869:                         unless ($diffres) {
                   2870:                             $skipsite = 1;
                   2871:                         }
                   2872:                     }
                   2873:                 }
                   2874:             }
                   2875:         }
                   2876:         unless ($skipsite) {
                   2877:             if (-l $defaultconfig) {
                   2878:                 unlink($defaultconfig);
                   2879:             }
                   2880:             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");
                   2881:             if (-e "$instdir/debian-ubuntu/loncapa") {
                   2882:                 copy("$instdir/debian-ubuntu/loncapa","$apache2_sites_available_dir/loncapa");
                   2883:                 chmod(0444,"$apache2_sites_available_dir/loncapa");
                   2884:                 symlink("$apache2_sites_available_dir/loncapa","$apache2_sites_enabled_dir/000-default");
                   2885:             }
                   2886:         }
                   2887:     }
1.45.2.19  raeburn  2888:     if (($distname eq 'ubuntu') || ($distname eq 'debian')) {
1.45.2.7  raeburn  2889:         my $sitestatus = "$apache2_mods_available_dir/status.conf";
                   2890:         my $stdstatus = "$instdir/debian-ubuntu/status.conf";
                   2891:         if ((-e $sitestatus) && (-e $stdstatus)) {
                   2892:             if (open(PIPE, "diff --brief $stdstatus $sitestatus |")) {
                   2893:                 my $diffres = <PIPE>;
                   2894:                 close(PIPE);
                   2895:                 chomp($diffres);
                   2896:                 if ($diffres) {
                   2897:                     copy("$apache2_mods_available_dir/status.conf","$apache2_mods_available_dir/status.conf.original");
                   2898:                 } else {
                   2899:                     $skipstatus = 1;
                   2900:                 }
                   2901:             }
                   2902:         }
                   2903:         unless ($skipstatus) {
                   2904:             if (-e $stdstatus) {
                   2905:                 print_and_log(&mt('Copying loncapa [_1] file to [_2],',"'status.conf'","'/etc/apache2/mods-available/status.conf'")."\n");
                   2906:                 copy($stdstatus,$sitestatus);
                   2907:                 chmod(0644,$sitestatus);
                   2908:             }
                   2909:         }
1.28      raeburn  2910:     }
1.1       raeburn  2911:     print_and_log("\n");
                   2912: }
                   2913: 
                   2914: ###########################################################
                   2915: ##
                   2916: ## openSuSE/SLES Copy apache2 config files:
                   2917: ##   default-server.conf, uid.conf, /etc/sysconfig/apache2 
                   2918: ##   and create symlink from /srv/www/conf to /etc/apache2 
                   2919: ##
                   2920: ###########################################################
                   2921: 
                   2922: sub copy_apache2_suseconf {
1.45.2.1  raeburn  2923:     my ($instdir,$distro) = @_;
                   2924:     my ($name,$version) = ($distro =~ /^(suse|sles)([\d\.]+)$/);
                   2925:     my $conf_file = "$instdir/sles-suse/default-server.conf";
                   2926:     if (($name eq 'sles') && ($version >= 12)) {
                   2927:         $conf_file = "$instdir/sles-suse/apache2.4/default-server.conf";
                   2928:     }
1.1       raeburn  2929:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
                   2930:                   "'default-server.conf'",
                   2931:                   "'/etc/apache2/default-server.conf'")."\n");
                   2932:     if (!-e "/etc/apache2/default-server.conf.original") {
                   2933:         copy "/etc/apache2/default-server.conf","/etc/apache2/default-server.conf.original";
                   2934:     }
1.45.2.1  raeburn  2935:     copy $conf_file,"/etc/apache2/default-server.conf";
1.5       raeburn  2936:     chmod(0444,"/etc/apache2/default-server.conf");
1.1       raeburn  2937:     # Make symlink for conf directory (included in loncapa_apache.conf)
                   2938:     my $can_symlink = (eval { symlink('/etc/apache2','/srv/www/conf'); }, $@ eq '');
                   2939:     if ($can_symlink) {
                   2940:         &print_and_log(&mt('Symlink created for [_1] to [_2].',
                   2941:                        "'/srv/www/conf'","'/etc/apache2'")."\n");
                   2942:     } else {
                   2943:         &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");
                   2944:     }
                   2945:     &copy_apache2_conf_files($instdir);
1.45.2.1  raeburn  2946:     &copy_sysconfig_apache2_file($instdir,$name,$version); 
1.1       raeburn  2947:     print_and_log("\n");
                   2948: }
                   2949: 
                   2950: ###############################################
                   2951: ##
                   2952: ## Modify uid.conf
                   2953: ##
                   2954: ###############################################
                   2955: sub copy_apache2_conf_files {
                   2956:     my ($instdir) = @_;
                   2957:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',
                   2958:                   "'uid.conf'","'/etc/apache2/uid.conf'")."\n");
                   2959:     if (!-e "/etc/apache2/uid.conf.original") {
                   2960:         copy "/etc/apache2/uid.conf","/etc/apache2/uid.conf.original";
                   2961:     }
1.9       raeburn  2962:     copy "$instdir/sles-suse/uid.conf","/etc/apache2/uid.conf";
1.5       raeburn  2963:     chmod(0444,"/etc/apache2/uid.conf");
1.1       raeburn  2964: }
                   2965: 
                   2966: ###############################################
                   2967: ##
                   2968: ## Modify /etc/sysconfig/apache2  
                   2969: ##
                   2970: ###############################################
                   2971: sub copy_sysconfig_apache2_file {
1.45.2.1  raeburn  2972:     my ($instdir,$name,$version) = @_;
1.1       raeburn  2973:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'sysconfig/apache2'","'/etc/sysconfig/apache2'")."\n");
                   2974:     if (!-e "/etc/sysconfig/apache2.original") {
                   2975:         copy "/etc/sysconfig/apache2","/etc/sysconfig/apache2.original";
                   2976:     }
1.45.2.1  raeburn  2977:     my $sysconf_file = "$instdir/sles-suse/sysconfig_apache2";
                   2978:     if (($name eq 'sles') && ($version >= 12)) {
                   2979:        $sysconf_file = "$instdir/sles-suse/apache2.4/sysconfig_apache2";
                   2980:     }
                   2981:     copy $sysconf_file,"/etc/sysconfig/apache2";
1.5       raeburn  2982:     chmod(0444,"/etc/sysconfig/apache2");
1.1       raeburn  2983: }
                   2984: 
                   2985: ###############################################
                   2986: ##
                   2987: ## Add/Modify /etc/insserv/overrides
                   2988: ##
                   2989: ###############################################
                   2990: 
                   2991: sub update_SuSEfirewall2_setup {
                   2992:     my ($instdir) = @_;
                   2993:     print_and_log(&mt('Copying the LON-CAPA [_1] to [_2].',"'SuSEfirewall2_setup'","'/etc/insserv/overrides/SuSEfirewall2_setup'")."\n");
                   2994:     if (!-e "/etc/insserv/overrides/SuSEfirewall2_setup") {
                   2995:         if (!-d "/etc/insserv") {
                   2996:             mkdir("/etc/insserv",0755); 
                   2997:         }
                   2998:         if (!-d "/etc/insserv/overrides") {
                   2999:             mkdir("/etc/insserv/overrides",0755);
                   3000:         }
                   3001:     } elsif (!-e  "/etc/insserv/overrides/SuSEfirewall2_setup.original") {
                   3002:         copy "/etc/insserv/overrides/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup.original"
                   3003:     }
1.9       raeburn  3004:     copy "$instdir/sles-suse/SuSEfirewall2_setup","/etc/insserv/overrides/SuSEfirewall2_setup";
1.5       raeburn  3005:     chmod(0444,"/etc/insserv/overrides/SuSEfirewall2_setup");
                   3006: }
                   3007: 
                   3008: sub get_iptables_rules {
                   3009:     my ($distro,$instdir,$apachefw) = @_;
                   3010:     my (@fwchains,@ports);
                   3011:     if (&firewall_is_active()) {
                   3012:         my $iptables = &get_pathto_iptables();
                   3013:         if ($iptables ne '') {
                   3014:             @fwchains = &get_fw_chains($iptables,$distro);
                   3015:         }
                   3016:     }
                   3017:     if (ref($apachefw) eq 'HASH') {
                   3018:         foreach my $service ('http','https') {
                   3019:             unless ($apachefw->{$service}) {
                   3020:                 push (@ports,$service); 
                   3021:             }
                   3022:         }
                   3023:     } else {
                   3024:         @ports = ('http','https');
                   3025:     }
                   3026:     if (@ports == 0) {
                   3027:         return;
                   3028:     }
                   3029:     my $ask_to_enable;
                   3030:     if (-e "/etc/iptables.loncapa.rules") {
1.9       raeburn  3031:         if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables.loncapa.rules /etc/iptables.loncapa.rules |")) {
1.5       raeburn  3032:             my $diffres = <PIPE>;
                   3033:             close(PIPE);
                   3034:             chomp($diffres);
                   3035:             if ($diffres) {
                   3036:                 print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
                   3037:             }
                   3038:         } else {
                   3039:             print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/iptables.loncapa.rules')."\n";
                   3040:         }
                   3041:     } else {
1.9       raeburn  3042:         if (-e "$instdir/debian-ubuntu/iptables.loncapa.rules") {
                   3043:             copy "$instdir/debian-ubuntu/iptables.loncapa.rules","/etc/iptables.loncapa.rules";
1.5       raeburn  3044:             chmod(0600,"/etc/iptables.loncapa.rules");
                   3045:         }
                   3046:     }
                   3047:     if (-e "/etc/iptables.loncapa.rules") {
                   3048:         if (-e "/etc/network/if-pre-up.d/iptables") {
1.9       raeburn  3049:             if (open(PIPE, "diff --brief $instdir/debian-ubuntu/iptables /etc/network/if-pre-up/iptables |")) {
1.5       raeburn  3050:                 my $diffres = <PIPE>;
                   3051:                 close(PIPE);
                   3052:                 chomp($diffres);
                   3053:                 if ($diffres) {
                   3054:                     print &mt('Warning: [_1] exists but differs from LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
                   3055:                 }
                   3056:             } else {
                   3057:                 print &mt('Error: unable to open [_1] to compare contents with LON-CAPA supplied file.','/etc/network/if-pre-up.d/iptables')."\n";
                   3058:             }
                   3059:         } else {
1.9       raeburn  3060:             copy "$instdir/debian-ubuntu/iptables","/etc/network/if-pre-up.d/iptables";
1.5       raeburn  3061:             chmod(0755,"/etc/network/if-pre-up.d/iptables");
                   3062:             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'));
                   3063:             $ask_to_enable = 1;
                   3064:         }
                   3065:     }
                   3066:     return $ask_to_enable;
1.1       raeburn  3067: }
                   3068: 
                   3069: sub download_loncapa {
                   3070:     my ($instdir,$lctarball) = @_;
                   3071:     my ($have_tarball,$updateshown);
                   3072:     if (! -e "$instdir/$lctarball") {
                   3073: 	print_and_log(&mt('Retrieving LON-CAPA source files from: [_1]',
                   3074: 		      'http://install.loncapa.org')."\n");
                   3075: 	system("wget http://install.loncapa.org/versions/$lctarball ".
                   3076: 	       "2>/dev/null 1>/dev/null");
                   3077: 	if (! -e "./$lctarball") {
                   3078: 	    print &mt('Unable to retrieve LON-CAPA source files from: [_1].', 
                   3079: 		     "http://install.loncapa.org/versions/$lctarball")."\n";
                   3080: 	} else {
                   3081:             $have_tarball = 1;
                   3082:         }
                   3083: 	print_and_log("\n");
                   3084:     } else {
                   3085:         $have_tarball = 1;
                   3086: 	print_and_log("
                   3087: ------------------------------------------------------------------------
                   3088: 
1.45.2.16  raeburn  3089: ".&mt('You seem to have a version of [_1] in [_2]',$lctarball,$instdir)."\n".
1.1       raeburn  3090: &mt('This copy will be used and a new version will NOT be downloaded.')."\n".
                   3091: &mt('If you wish, you may download a new version by executing:')."
                   3092: 
1.45.2.16  raeburn  3093: wget http://install.loncapa.org/versions/$lctarball
1.1       raeburn  3094: 
                   3095: ------------------------------------------------------------------------
                   3096: ");
                   3097:     }
                   3098: 
                   3099:     ##
1.45.2.16  raeburn  3100:     ## untar loncapa-X.Y.Z.tar.gz
1.1       raeburn  3101:     ##
                   3102:     if ($have_tarball) {
1.45.2.16  raeburn  3103:         my $homedir = '/root';
                   3104:         my ($targetdir,$chdircmd,$updatecmd);
                   3105:         if (($distro =~ /^ubuntu/) && ($instdir ne $homedir)) {
                   3106:             ($homedir) = ($instdir =~ m{^(.*)/[^/]+$});
                   3107:             $updatecmd = 'sudo ./UPDATE';
                   3108:         } else {
                   3109:             $updatecmd = './UPDATE';
                   3110:         }
1.1       raeburn  3111:         print_and_log(&mt('Extracting LON-CAPA source files')."\n");
1.45.2.16  raeburn  3112:         if (-e $homedir) {
                   3113:             writelog(`tar zxf $instdir/$lctarball --directory $homedir`);
                   3114:             $targetdir = $homedir;
                   3115:         } else {
                   3116:             writelog(`tar zxf $instdir/$lctarball`);
                   3117:             $targetdir = $instdir;
                   3118:         }
                   3119:         if ($lctarball =~ /^loncapa\-(\d+\.\d+\.\d+(?:|[^.]+))\.tar\.gz$/) {
                   3120:             $chdircmd = "cd $targetdir/loncapa-".$1;
                   3121:         } else {
                   3122:             $chdircmd = "cd $targetdir/loncapa-X.Y.Z  (X.Y.Z should correspond to a version number like '2.11.3')";
                   3123:         }
1.1       raeburn  3124:         print_and_log("\n");
                   3125:         print &mt('LON-CAPA source files extracted.')."\n".
1.45.2.16  raeburn  3126:               &mt('It remains for you to execute the following commands:').
                   3127:               "\n$chdircmd\n$updatecmd\n".
                   3128:               &mt('If you have any trouble, please see [_1] and [_2]',
                   3129:                   'http://install.loncapa.org/','http://help.loncapa.org/')."\n";
1.1       raeburn  3130:         $updateshown = 1;
                   3131:     }
                   3132:     return ($have_tarball,$updateshown);
                   3133: }
                   3134: 
                   3135: close LOG;

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