[LON-CAPA-cvs] cvs: doc /install/linux install.pl
raeburn
raeburn at source.lon-capa.org
Sat Aug 8 18:44:55 EDT 2026
raeburn Sat Aug 8 22:44:55 2026 EDT
Modified files:
/doc/install/linux install.pl
Log:
- Support Ubuntu 26 for which MySQL 8.4 is the default, and for which use of
the old mysql_native_password authentication method is disabled by default.
-------------- next part --------------
Index: doc/install/linux/install.pl
diff -u doc/install/linux/install.pl:1.102 doc/install/linux/install.pl:1.103
--- doc/install/linux/install.pl:1.102 Sat Aug 8 22:04:56 2026
+++ doc/install/linux/install.pl Sat Aug 8 22:44:55 2026
@@ -78,7 +78,7 @@
&mt('Stopping execution.')."\n";
exit;
} else {
- print LOG '$Id: install.pl,v 1.102 2026/08/08 22:04:56 raeburn Exp $'."\n";
+ print LOG '$Id: install.pl,v 1.103 2026/08/08 22:44:55 raeburn Exp $'."\n";
}
#
@@ -611,7 +611,7 @@
}
my ($mysqlon,$mysqlsetup,$mysqlrestart,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,
%recommended,$downloadstatus,$filetouse,$production,$testing,$apachefw,
- $tostop,$uses_systemctl,$mysql_has_wwwuser,$hostname,$hostip);
+ $tostop,$uses_systemctl,$mysql_has_wwwuser,$hostname,$hostip,$need_mysql_native);
my $wwwuid = &uid_of_www();
my $wwwgid = getgrnam('www');
if (($wwwuid eq '') || ($wwwgid eq '')) {
@@ -641,7 +641,7 @@
print_and_log("\n".&mt('Hostname is [_1] and IP address is [_2]',$hostname,$hostip)."\n");
$mysqlon = &check_mysql_running($distro);
if ($mysqlon) {
- ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket) =
+ ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket,$need_mysql_native) =
&check_mysql_setup($instdir,$dsn,$distro);
if ($mysqlsetup eq 'needsrestart') {
$mysqlrestart = '';
@@ -649,7 +649,8 @@
$mysqlrestart = 'sudo ';
}
$mysqlrestart .= 'service mysql restart';
- return ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart);
+ return ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart,
+ $need_mysql_native);
} else {
if ($mysqlsetup eq 'noroot') {
$recommended{'mysqlperms'} = 1;
@@ -664,6 +665,9 @@
unless ($has_lcdb) {
$recommended{'mysql'} = 1;
}
+ if ($need_mysql_native) {
+ $recommended{'mysqlperms'} = 1;
+ }
}
}
my ($sslhostsfilesref,$has_std,$has_int,$rewritenum,$nochgstd,$nochgint);
@@ -679,7 +683,7 @@
($recommended{'download'},$downloadstatus,$filetouse,$production,$testing)
= &need_download($distro,$instdir);
return ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,
- $mysqlrestart,\%recommended,$dbh,$has_pass,$mysql_unix_socket,
+ $mysqlrestart,$need_mysql_native,\%recommended,$dbh,$has_pass,$mysql_unix_socket,
$has_lcdb,$downloadstatus,$filetouse,$production,$testing,$apachefw,
$uses_systemctl,$hostname,$hostip,$sslhostsfilesref,$has_std,$has_int,
$rewritenum,$nochgstd,$nochgint);
@@ -1691,7 +1695,7 @@
sub check_mysql_setup {
my ($instdir,$dsn,$distro) = @_;
- my ($mysqlsetup,$has_pass,$mysql_unix_socket,$mysql_has_wwwuser);
+ my ($mysqlsetup,$has_pass,$mysql_unix_socket,$mysql_has_wwwuser,$need_mysql_native);
my $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version($distro);
if (($mysqlname =~ /^MariaDB/i) && (($mysqlversion == 10 && $mysqlminorversion >= 4) || ($mysqlversion >= 11))) {
@@ -1725,11 +1729,21 @@
}
}
$sth->finish();
+ if (($mysqlversion == 8 && $mysqlminorversion >= 4)) {
+ $need_mysql_native = &check_mysql_native_pw($dbh);
+ }
if ($mysql_unix_socket) {
print_and_log(&mt('MySQL using unix_socket for root access from localhost.')."\n");
$mysqlsetup = 'rootok';
$mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
- return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket);
+ if ($need_mysql_native) {
+ print_and_log(&mt('[_1] needs mysql_native_password to be activated',
+ "$mysqlname $mysqlversion.$mysqlminorversion")."\n");
+ }
+ return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,$mysql_unix_socket,$need_mysql_native);
+ } elsif ($need_mysql_native) {
+ print_and_log(&mt('[_1] needs mysql_native_password to be activated.',
+ "$mysqlname $mysqlversion.$mysqlminorversion")."\n");
}
}
} elsif ($DBI::err =~ /1045/) {
@@ -1737,7 +1751,7 @@
} elsif ($distro =~ /^ubuntu(\d+)$/) {
my $version = $1;
if ($1 > 12) {
- print_and_log(&mt('Restarting mysql, please be patient')."\n");
+ print_and_log(&mt('Restarting mysql, please be patient.')."\n");
if (open (PIPE, "service mysql restart 2>&1 |")) {
while (<PIPE>) {
print $_;
@@ -1748,12 +1762,15 @@
if ($dbh) {
$mysqlsetup = 'noroot';
$mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
+ if (($mysqlversion == 8) && ($mysqlminorversion >= 4)) {
+ $need_mysql_native = &check_mysql_native_pw($dbh);
+ }
} elsif ($DBI::err =~ /1045/) {
$has_pass = 1;
} else {
$mysqlsetup = 'needsrestart';
$mysql_has_wwwuser = &check_mysql_wwwuser();
- return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
+ return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,'',$need_mysql_native);
}
}
}
@@ -1777,6 +1794,7 @@
$mysqlsetup = 'rootok';
print_and_log(&mt('Password accepted.')."\n");
$mysql_has_wwwuser = &check_mysql_wwwuser($dbh);
+
} else {
if ($DBI::err =~ /1045/) {
print_and_log(&mt('Incorrect password.')."\n");
@@ -1790,7 +1808,18 @@
$mysqlsetup = 'rootfail';
$mysql_has_wwwuser = &check_mysql_wwwuser();
}
- return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser);
+ unless ($mysqlsetup eq 'rootfail') {
+ if ($dbh) {
+ if (($mysqlversion == 8) && ($mysqlminorversion >= 4)) {
+ $need_mysql_native = &check_mysql_native_pw($dbh);
+ if ($need_mysql_native) {
+ print_and_log(&mt('[_1] needs mysql_native_password to be activated',
+ "$mysqlname $mysqlversion.$mysqlminorversion")."\n");
+ }
+ }
+ }
+ }
+ return ($mysqlsetup,$has_pass,$dbh,$mysql_has_wwwuser,'',$need_mysql_native);
}
sub check_mysql_wwwuser {
@@ -1826,6 +1855,21 @@
return $has_lcdb;
}
+sub check_mysql_native_pw {
+ my ($dbh) = @_;
+ my $needed;
+ if (ref($dbh)) {
+ my $sth = $dbh->prepare("SELECT PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'mysql_native_password'");
+ $sth->execute();
+ my $status = $sth->fetchrow_array();
+ $sth->finish();
+ unless ($status eq 'ACTIVE') {
+ $needed = 1;
+ }
+ }
+ return $needed;
+}
+
sub get_pathto_iptables {
my $iptables;
if (-e '/sbin/iptables') {
@@ -2080,7 +2124,7 @@
my $dsn = "DBI:mysql:database=mysql";
my ($distro,$gotprereqs,$localecmd,$langcmd,$packagecmd,$updatecmd,$installnow,$mysqlrestart,
- $recommended,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$downloadstatus,
+ $need_mysql_native,$recommended,$dbh,$has_pass,$mysql_unix_socket,$has_lcdb,$downloadstatus,
$filetouse,$production,$testing,$apachefw,$uses_systemctl,$hostname,$hostip,
$sslhostsfiles,$has_std,$has_int,$rewritenum,$nochgstd,$nochgint) =
&check_required($instdir,$dsn);
@@ -2099,6 +2143,28 @@
&mt('Please run the install.pl script again, once you have restarted mysql.')."\n";
exit;
}
+if ($need_mysql_native) {
+ print "\n".&mt('Your MySQL configuration needs updating.')."\n";
+ my $updated = &update_mysql_config($distro);
+ if ($updated) {
+ print_and_log("\n".&mt('Your MySQL configuration was successfully updated.')."\n");
+ print_and_log(&mt('Restarting mysql, please be patient.')."\n");
+ if (open (PIPE, "systemctl restart mysql 2>&1 |")) {
+ while (<PIPE>) {
+ print $_;
+ }
+ close(PIPE);
+ } else {
+ print "\n".&mt('Restarting mysql failed.')."\n".
+ &mt('Stopping execution of install.pl script.')."\n";
+ exit;
+ }
+ } else {
+ print "\n".&mt('Your MySQL configuration needed updating, but the attempt to do so failed.')."\n".
+ &mt('Stopping execution of install.pl script.')."\n";
+ exit;
+ }
+}
if ($localecmd ne '') {
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";
if ($langcmd ne '') {
@@ -2836,7 +2902,7 @@
sub setup_mysql_permissions {
my ($dbh,$has_pass,$mysql_unix_socket,$distro, at mysql_lc_commands) = @_;
my ($mysqlversion,$mysqlminorversion,$mysqlsubver,$mysqlname) = &get_mysql_version($distro);
- my ($usescreate,$usesauth,$is_mariadb,$hasauthcol, at mysql_commands);
+ my ($usescreate,$usesauth,$is_mariadb,$hasauthcol,$check_native_pw, at mysql_commands);
if ($mysqlname =~ /^MariaDB/i) {
$is_mariadb = 1;
if ((($mysqlversion == 10) && ($mysqlminorversion >= 4)) || ($mysqlversion >= 11)) {
@@ -2854,6 +2920,9 @@
(($mysqlminorversion >= 6) || (($mysqlminorversion == 5) && ($mysqlsubver >= 7)))) {
$hasauthcol = 1;
}
+ if (($mysqlversion == 8) && ($mysqlminorversion >= 4)) {
+ $check_native_pw = 1;
+ }
}
if ($usescreate) {
@mysql_commands = ("CREATE USER 'www'\@'localhost' IDENTIFIED BY 'localhostkey'");
@@ -2880,6 +2949,18 @@
push(@mysql_commands,"DELETE FROM user WHERE host<>'localhost'");
if (($has_pass) || ($mysql_unix_socket)) {
if ($dbh) {
+ my $need_mysql_native;
+ if ($check_native_pw) {
+ $need_mysql_native = &check_mysql_native_pw($dbh);
+ }
+ if ($need_mysql_native) {
+ my $result = &set_native_perm($distro,$dbh);
+ if ($result eq 'fail') {
+ print_and_log(&mt('Problem configuring MySQL.')."\n".
+ &mt('Permissions not set.')."\n");
+ return;
+ }
+ }
push(@mysql_commands,"FLUSH PRIVILEGES");
if (@mysql_commands) {
foreach my $cmd (@mysql_commands) {
@@ -2925,6 +3006,18 @@
print_and_log(&mt('Failed to get MySQL root password from user input.')."\n");
}
if ($dbh) {
+ my $need_mysql_native;
+ if ($check_native_pw) {
+ $need_mysql_native = &check_mysql_native_pw($dbh);
+ }
+ if ($need_mysql_native) {
+ my $result = &set_native_perm($distro,$dbh);
+ if ($result eq 'fail') {
+ print_and_log(&mt('Problem configuring MySQL.')."\n".
+ &mt('Permissions not set.')."\n");
+ return;
+ }
+ }
if (@mysql_commands) {
foreach my $cmd (@mysql_commands) {
$dbh->do($cmd) || print $dbh->errstr."\n";
@@ -2978,6 +3071,9 @@
chomp($info);
close(PIPE);
($version,$minorversion,$subversion,$name) = ($info =~ /(\d+)\.(\d+)\.(\d+)(?:\-?(\w*),|)/);
+ if ($name eq '') {
+ $name = 'MySQL';
+ }
} else {
print &mt('Could not determine which version of MySQL is installed.').
"\n";
@@ -2985,6 +3081,218 @@
return ($version,$minorversion,$subversion,$name);
}
+sub set_native_perm {
+ my ($distro,$dbh) = @_;
+ my ($disconnected,$status);
+ if (ref($dbh)) {
+ if (!$dbh->disconnect) {
+ &print_and_log(&mt('Failed to disconnect from MySQL:')."\n".
+ $dbh->errstr);
+ } else {
+ $disconnected = 1;
+ }
+ }
+ my $result = &update_mysql_config($distro);
+ if ($result) {
+ if (open (PIPE, "systemctl restart mysql 2>&1 |")) {
+ while (<PIPE>) {
+ print $_;
+ }
+ close(PIPE);
+ } else {
+ print "\n".&mt('Restarting mysql failed.')."\n".
+ &mt('Stopping execution of install.pl script.')."\n";
+ $status = 'fail';
+ }
+ } else {
+ $status = 'fail';
+ }
+ if ($disconnected) {
+ my $dsn = "DBI:mysql:database=mysql";
+ my $currpass = &get_mysql_password(&mt('Please enter the password now'));
+ $dbh = DBI->connect($dsn,'root','',{'PrintError'=>0});
+ if ($DBI::err =~ /1045/) {
+ print &mt('You have already set a root password for the MySQL database.')."\n";
+ my $currpass = &get_mysql_password(&mt('Please enter the password now'));
+ $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
+ if ($dbh) {
+ print &mt('Password accepted.')."\n";
+ } else {
+ print &mt('Problem accessing MySQL.')."\n";
+ if ($DBI::err =~ /1045/) {
+ print &mt('Perhaps the password was incorrect?')."\n";
+ print &mt('Try again?').' ';
+ $currpass = &get_mysql_password(&mt('Re-enter password now'));
+ $dbh = DBI->connect($dsn,'root',$currpass,{'PrintError'=>0});
+ if ($dbh) {
+ print &mt('Password accepted.')."\n";
+ } else {
+ if ($DBI::err =~ /1045/) {
+ print &mt('Incorrect password.')."\n";
+ $status = 'fail';
+ }
+ }
+ }
+ }
+ }
+ }
+ return $status;
+}
+
+sub update_mysql_config {
+ my ($distro) = @_;
+ my $mysqlfile = '/etc/my.cnf';
+ my $mysqlconf = [{section =>'mysqld',
+ key =>'mysql_native_password=',
+ value =>'ON'}];
+ if ($distro =~ /^ubuntu(\d+)$/) {
+ my $version = $1;
+ $mysqlfile = '/etc/mysql/my.cnf';
+ if ($version > 14) {
+ $mysqlfile = '/etc/mysql/mysql.conf.d/mysqld.cnf';
+ }
+ } elsif ($distro =~ /^debian(\d+)$/) {
+ my $version = $1;
+ if ($version >= 10) {
+ $mysqlfile = '/etc/mysql/mariadb.conf.d/50-server.cnf';
+ }
+ }
+ if (-e $mysqlfile) {
+ my ($filedata) = &parse_config_file($mysqlfile);
+ if (ref($filedata)) {
+ my $modified = 0;
+ foreach my $data (@$mysqlconf) {
+ my $section = $data->{'section'};
+ my $key = $data->{'key'};
+ my $value = $data->{'value'};
+ my $result = &modify_config_file($filedata,$section,$key,$value);
+ if ($result) { $modified = 1; }
+ }
+ if ($modified) {
+ my $result = &write_config_file($mysqlfile,$filedata);
+ if (defined($result)) { print "**** Error when writing to $mysqlfile : $result\n"; return 0; }
+ }
+ return $modified;
+ } else {
+ print "**** Error: existing data could not be retrived from $mysqlfile\n";
+ return 0;
+ }
+ } else {
+ print "**** Error: $mysqlfile does not exist\n";
+ }
+}
+
+sub parse_config_file {
+ my ($file) = @_;
+ open(INFILE,$file) || return ('Unable to open '.$file.' for reading');
+ my @Input = <INFILE>;
+ close(INFILE);
+ my @Structure;
+ my %Sections;
+ while (my $line = shift(@Input)) {
+ chomp($line);
+ if ($line =~ /^\[([^\]]*)\]/) {
+ my $section_id = $1;
+ push(@Structure,'__section__'.$section_id);
+ while ($line = shift(@Input)) {
+ chomp($line);
+ if ($line =~ /^\[([^\]]*)\]/) {
+ unshift(@Input,$line);
+ last;
+ } else {
+ push(@{$Sections{$section_id}},$line);
+ }
+ }
+ } else {
+ push(@Structure,$line);
+ }
+ }
+ my $filedata = [\@Structure,\%Sections];
+ return $filedata;
+}
+
+sub modify_config_file {
+ my ($filedata,$section,$newkey,$newvalue)=@_;
+ my $modified = 0; # returned value - set to true if the file is modified
+ my ($structure,$sections) = @$filedata;
+ if (! defined($newvalue)) {
+ $newvalue = '';
+ }
+ my $newline = $newkey.$newvalue;
+ #
+ # Determine which array ref gets the item
+ my $target;
+ if (defined($section)) {
+ if (! exists($sections->{$section})) {
+ push(@$structure,'__section__'.$section);
+ $sections->{$section}=[];
+ }
+ $target = $sections->{$section};
+ } else {
+ $target = $structure;
+ }
+ #
+ # Put the item in or update it.
+ my $key_is_new = 1;
+ for (my $i=0;$i<scalar(@$target);$i++) {
+ if ($target->[$i] =~/^$newkey/) {
+ if ($target->[$i] ne $newline) {
+ $target->[$i]=$newline;
+ $modified = 1;
+ }
+ $key_is_new = 0;
+ last;
+ }
+ }
+ if ($key_is_new) {
+ if (! defined($section)) {
+ unshift(@$target,$newline);
+ } else {
+ # No need to put things after a blank line.
+ if (defined($target->[-1]) && $target->[-1] =~ /^\s*$/) {
+ $target->[-1] = $newline;
+ $modified = 1;
+ } else {
+ push(@$target,$newline);
+ $modified = 1;
+ }
+ }
+ }
+ return $modified;
+}
+
+sub write_config_file {
+ my ($file,$filedata) = @_;
+ my ($structure,$sections) = @$filedata;
+ if (! defined($structure) || ! ref($structure)) {
+ return 'Bad subroutine inputs';
+ }
+ open(OUTPUT,'>',$file) || return('Unable to open '.$file.' for writing');
+ for (my $i=0;$i<scalar(@$structure);$i++) {
+ my $line = $structure->[$i];
+ chomp($line);
+ if ($line =~ /^__section__(.*)$/) {
+ my $section_id = $1;
+ print OUTPUT ('['.$section_id.']'.$/);
+ foreach my $section_line (@{$sections->{$section_id}}) {
+ chomp($section_line);
+ print OUTPUT $section_line.$/;
+ }
+ # Deal with blank lines
+ if ($sections->{$section_id}->[-1] =~ /^\s*$/) {
+ # No need to output a blank line at the end if there is one
+ # already
+ } else {
+ print OUTPUT $/;
+ }
+ } else {
+ print OUTPUT $line.$/;
+ }
+ }
+ close OUTPUT;
+ return undef;
+}
+
sub check_systemd_update {
my ($distro) = @_;
my ($use_systemctl,$service);
More information about the LON-CAPA-cvs
mailing list