File manager - Edit - /usr/local/cpanel/bin/update-roundcube-db
Back
#!/usr/local/cpanel/3rdparty/bin/perl # Copyright 2024 WebPros International, LLC # All rights reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited. ## cpdev: installs to /usr/local/cpanel/base/3rdparty/roundcube package cpanel::bin::update_roundcube; use cPstrict; use Cpanel::Config::CpConfGuard (); use Cpanel::Config::LoadCpConf (); use Cpanel::Debug (); use Cpanel::Email::RoundCube (); use Cpanel::Email::RoundCube::DBI (); use Cpanel::LoadModule (); use Cpanel::MysqlUtils::InnoDB (); use Cpanel::MysqlUtils::MyCnf::Basic (); ## case 44546 use Cpanel::MysqlUtils::Version (); use Cpanel::Pkgr (); use Cpanel::Server::Type (); use Cpanel::Server::Type::Profile::Roles (); exit( script(@ARGV) // 0 ) unless caller(); sub script { # Handle help option if ( grep { $_ eq '--help' } @ARGV ) { require Pod::Usage; Pod::Usage::pod2usage( -exitval => 0, -verbose => 1 ); } return if _is_dnsonly(); return unless _has_needed_roles(); return unless _has_package(); my $daemonize = !grep { $_ eq '--foreground' } @ARGV; my $is_transfer = grep { $_ eq '--transfer' } @ARGV; my $cpconf = Cpanel::Config::LoadCpConf::loadcpconf(); my $mysql_version = Cpanel::MysqlUtils::Version::mysqlversion(); ## Exit if Roundcube has been converted to SQLite my $sqlite_version = $0 =~ s/-db/-sqlite-db/r; if ( exists $cpconf->{'roundcube_db'} && $cpconf->{'roundcube_db'} eq 'sqlite' ) { print "Roundcube is configured to use SQLite.\n"; print "This update is for Roundcube using MySQL. Running $sqlite_version.\n"; exec $sqlite_version, @ARGV; die "Failed to exec $sqlite_version"; } elsif ( !-e '/var/cpanel/i_accept_my_roundcube_may_be_broken_by_1_6' # if you want a probably broken roundcube, here you go && ( Cpanel::MysqlUtils::Version::cmp_versions( $mysql_version, '5.6' ) <= 0 # MySQL 5.6 and below do not support the key length || Cpanel::MysqlUtils::Version::cmp_versions( $mysql_version, '10.0' ) == 0 # MariaDB 10.0 has the same issue with the key length ) ) { print "Roundcube 1.6+ does not support the installed version of MySQL/MariaDB ($mysql_version).\n"; print "Your users' Roundcube databases will be converted to SQLite automatically!\n"; _daemonize() if $daemonize; Cpanel::LoadModule::load_perl_module('Cpanel::SafeRun::Object'); Cpanel::SafeRun::Object->new_or_die( 'program' => '/usr/local/cpanel/scripts/convert_roundcube_mysql2sqlite' ); return 0; } _daemonize() if $daemonize; # Pass the transfer flag to update_roundcube update_roundcube( is_transfer => $is_transfer ); if ( exists $cpconf->{'roundcube_db'} && $cpconf->{'roundcube_db'} eq 'mysql_plus_sqlite' ) { print "Update for Roundcube using MySQL complete. Now running $sqlite_version to update those.\n"; exec $sqlite_version, @ARGV; die "Failed to exec $sqlite_version"; } return 0; # for now preserved original behavior and always exit 0 } sub _is_dnsonly { return unless Cpanel::Server::Type::is_dnsonly(); Cpanel::Debug::log_warn("bin/update-roundcube-db is disabled on dnsonly server"); return 1; } sub _has_needed_roles { return 1 if Cpanel::Server::Type::Profile::Roles::is_role_enabled('MailReceive'); Cpanel::Debug::log_warn("bin/update-roundcube-db is disabled required MailReceive role is disabled."); return; } sub _has_package { return 1 if Cpanel::Pkgr::is_installed('cpanel-roundcubemail'); Cpanel::Debug::log_info("bin/update-roundcube-db requires the cpanel-roundcubemail package."); return; } #Named args: # dbh: optional, a DBD::mysql handle to use # is_transfer: optional, indicates the script is being called during a transfer operation sub update_roundcube (%opts) { return if _is_dnsonly(); my ( $dbh, $mysql_has_roundcube_db ) = _check_update_roundcube(%opts); return _do_update_roundcube( %opts, dbh => $dbh, mysql_has_roundcube_db => $mysql_has_roundcube_db ); } #opts can be: # dbh - a Cpanel::DBI::Mysql instance (useful for testing/mocking) sub _check_update_roundcube (%opts) { my $dbh = $opts{'dbh'}; if ( !$dbh ) { my $mysql_user = Cpanel::MysqlUtils::MyCnf::Basic::getmydbuser('root') || 'root'; my $mysql_host = Cpanel::MysqlUtils::MyCnf::Basic::getmydbhost('root') || 'localhost'; my $mysql_port = Cpanel::MysqlUtils::MyCnf::Basic::getmydbport('root') || 3306; $dbh = Cpanel::Email::RoundCube::DBI::mysql_db_connect( undef, $mysql_host, $mysql_user, Cpanel::MysqlUtils::MyCnf::Basic::getmydbpass('root'), undef, $mysql_port ); if ( !$dbh ) { Cpanel::Debug::log_die("Failed to connect to MySQL install at $mysql_host"); } } my $has_innodb = Cpanel::MysqlUtils::InnoDB::is_enabled_on_dbh($dbh); ## rcube has required InnoDB since 0.2-beta if ( !$has_innodb ) { die "Roundcube requires that MySQL support InnoDB tables, but your MySQL installation does not support them.\n"; } my $dbs_ar = $dbh->selectall_arrayref('SHOW DATABASES'); my $mysql_has_roundcube_db = grep { $_->[0] eq 'roundcube' } @$dbs_ar; return ( $dbh, $mysql_has_roundcube_db ); } # Case 117993, deal with partially installed RoundCube on install sub _attempt_chown_fix_for_roundcube { Cpanel::Email::RoundCube::lock_roundcube_for_update(); # case 103369, upgrading db "died" and left the updating lock # in place so roundcube could not run. # By doing this in an eval, we can report an error # and remove the locking file. my $eval_ret = eval { return Cpanel::Email::RoundCube::perform_chown_fix(); }; my $error_string = $@; # unlock always here Cpanel::Email::RoundCube::unlock_roundcube_after_update(); if ( !defined $eval_ret ) { Cpanel::Debug::log_info("Error occurred during chown fix\n$error_string"); return; # modeled after the schema update failure from above } else { Cpanel::Debug::log_info("Roundcube has succeeded doing the chown fix"); } return $eval_ret; } sub _do_update_roundcube (%opts) { my ( $dbh, $has_db, $is_transfer ) = @opts{qw( dbh mysql_has_roundcube_db is_transfer )}; my $version = Cpanel::Email::RoundCube::get_active_version(); ### Cpanel::Email::RoundCube::init_roundcube_data_dir(); my $version_before_update = Cpanel::Email::RoundCube::get_stored_version(); if ($version_before_update) { Cpanel::Debug::log_info("Roundcube update from $version_before_update to $version in progress."); } else { Cpanel::Debug::log_info("Roundcube $version install in progress."); } Cpanel::Email::RoundCube::lock_roundcube_for_update(); # case 103369, upgrading db "died" and left the updating lock # in place so roundcube could not run. # By doing this in an eval, we can report an error # and remove the locking file. my $eval_ret = eval { my $dest_dir = $Cpanel::Email::RoundCube::ROUNDCUBE_DEST_DIR; ############################## ## DATABASE my $valid_archive; if ( $ENV{'CPANEL_ROUNDCUBE_INSTALL_VERSION'} ) { # the RPM will have already archived the database # $valid_archive = 1; } else { $valid_archive = $has_db && Cpanel::Email::RoundCube::archive_mysql_roundcube($dbh); } Cpanel::Email::RoundCube::prune_mysql_roundcube_archives(); my ( $ok, $msg ) = _add_mysql_roundcube_grants($dbh); return ( 0, $msg ) if !$ok; my $success; if ($has_db) { $success = update_mysql_roundcube_db( $dbh, $is_transfer ); } else { $success = initialize_mysql_roundcube_db( $dbh, $is_transfer ); } if ($success) { Cpanel::Debug::log_info("Schema update to $version was successful"); } else { warn $dbh->errstr(); if ($valid_archive) { print "Restoring previous Roundcube data\n"; $dbh->do('DROP DATABASE roundcube'); _create_mysql_roundcube_db($dbh); Cpanel::Email::RoundCube::restore_latest_mysql_archive($dbh); } return; } ############################## my $cpconf_guard = Cpanel::Config::CpConfGuard->new(); if ( $cpconf_guard->{'data'}{'roundcube_db'} && $cpconf_guard->{'data'}{'roundcube_db'} eq 'mysql_plus_sqlite' ) { Cpanel::Email::RoundCube::generate_hybrid_config( $dest_dir, $dbh ); } else { Cpanel::Email::RoundCube::generate_roundcube_config_mysql( $dest_dir, $dbh ); } Cpanel::Email::RoundCube::write_version_file(); # process any install tasks after the new version is inplace, including schema backed up and updated # if ( Cpanel::Email::RoundCube::process_custom_roundcube_install_file($dest_dir) ) { return 1; } # Only set it if it isn't already set if ( !$cpconf_guard->{'data'}{'roundcube_db'} ) { $cpconf_guard->{'data'}{'roundcube_db'} = 'mysql'; $cpconf_guard->save(); } return 1; }; my $error_string = $@; # unlock always here Cpanel::Email::RoundCube::unlock_roundcube_after_update(); if ( !defined $eval_ret ) { Cpanel::Debug::log_info("Error occurred during upgrade\n$error_string"); return; # modeled after the schema update failure from above } else { Cpanel::Debug::log_info("Roundcube updated to $version"); } return $eval_ret; } sub _create_mysql_roundcube_db ( $dbh, $is_transfer = 0 ) { $dbh->do('CREATE DATABASE IF NOT EXISTS roundcube'); my $rc_dbh = $dbh->clone( { Username => 'roundcube', Password => Cpanel::Email::RoundCube::get_roundcube_password(), mysql_multi_statements => 1, database => 'roundcube', } ); # Will auto-apply initial schema in this case since nothing is in there. return update_mysql_roundcube_db( $dbh, $is_transfer ); } sub _add_mysql_roundcube_grants ($dbh) { return Cpanel::Email::RoundCube::handle_mysql_roundcube_grants( 'roundcube', $dbh, ); } #Call this to return a $dbh that always points to the `roundcube` db. sub _ensure_use_of_roundcube_db ($dbh) { my $db_all = $dbh->selectall_arrayref('SELECT DATABASE()'); if ( !$db_all->[0][0] || ( $db_all->[0][0] ne 'roundcube' ) ) { $dbh = $dbh->clone(); $dbh->do('USE roundcube'); } return $dbh; } #Call this when MySQL doesn't have the `roundcube` database. sub initialize_mysql_roundcube_db ( $dbh, $is_transfer = 0 ) { my $success = _create_mysql_roundcube_db( $dbh, $is_transfer ); $dbh = _ensure_use_of_roundcube_db($dbh); return $success; } #Call this when MySQL already has the `roundcube` database. sub update_mysql_roundcube_db ( $dbh, $is_transfer = 0 ) { my ($RCUBE_VERSION) = Cpanel::Email::RoundCube::get_version_info(); $dbh = _ensure_use_of_roundcube_db($dbh); my $success = Cpanel::Email::RoundCube::DBI::ensure_schema_update( $dbh, 'mysql', $RCUBE_VERSION ); # Apply transfer-specific SQL script if this is a transfer operation if ( $success && $is_transfer ) { $success = _apply_transfer_mysql_script($dbh); } return $success; } sub _apply_transfer_mysql_script ($dbh) { my $transfer_script = '/usr/local/cpanel/src/3rdparty/gpl/roundcube_schema/transfer/mysql.sql'; if ( !-f $transfer_script ) { Cpanel::Debug::log_warn("Transfer script not found: $transfer_script"); return 1; # Don't fail the entire operation for missing script } Cpanel::Debug::log_info("Applying transfer-specific MySQL script: $transfer_script"); require Cpanel::LoadFile; my $sql_content = Cpanel::LoadFile::loadfile($transfer_script); if ( !$sql_content ) { Cpanel::Debug::log_warn("Transfer script $transfer_script is empty or cannot be loaded"); return 1; } # Remove comments and split on semicolons $sql_content =~ s/--.*$//gm; # Remove single-line comments my @statements = split /;/, $sql_content; for my $statement (@statements) { $statement =~ s/^\s+|\s+$//g; # trim whitespace next if !$statement; # skip empty statements # Skip USE statements as we're already connected to the roundcube database next if $statement =~ /^\s*USE\s+/i; if ( !$dbh->do($statement) ) { Cpanel::Debug::log_warn( "Failed to execute transfer script statement: $statement - " . $dbh->errstr() ); # Continue with other statements rather than failing completely } else { Cpanel::Debug::log_info("Successfully executed transfer statement: $statement"); } } Cpanel::Debug::log_info("Transfer-specific MySQL script applied successfully"); return 1; } sub _daemonize { say STDERR "$0: running in the background."; require Cpanel::Daemonizer::Simple; Cpanel::Daemonizer::Simple::daemonize(); return; } 1; __END__ =encoding utf-8 =head1 NAME update-roundcube-db =head1 SYNOPSIS update-roundcube-db [--foreground] [--transfer] update-roundcube-db --help =head1 OPTIONS =over 4 =item --foreground Run the script in the foreground. The default behavior is to run in the background. =item --transfer Indicates that the script is being called during an account transfer operation. This flag affects the behavior of the database schema update process. =item --help Provides this help text. =back =head1 DESCRIPTION This script updates Roundcube MySQL database schema for the system.
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Generation time: 0.06 |
proxy
|
phpinfo
|
Settings