/usr/local/cpanel/scripts
NameSizeModeActions
cpan_sandbox/-0755rm
php_sandbox/-0755rm
activesync-invite-reply17340755editdlrm
adddns24180755editdlrm
addpop62280755editdlrm
addsystemuser33450755editdlrm
adduser920755editdlrm
add_dns24180755editdlrm
agent360.sh164100700editdlrm
apachelimits44100755editdlrm
archive_sync_zones31220755editdlrm
auto-adjust-mysql-limits18540755editdlrm
autorepair12740755editdlrm
backups_clean_metadata_for_missing_backups16120755editdlrm
backups_create_metadata161260755editdlrm
backups_list_user_files46710755editdlrm
backup_jobs_helper111390755editdlrm
balance_linked_node_quotas26430755editdlrm
biglogcheck17290755editdlrm
builddovecotconf98690755editdlrm
buildeximconf71670755editdlrm
buildhttpdconf26640755editdlrm
buildpureftproot5390755editdlrm
build_bandwidthdb_root_cache_in_background15610755editdlrm
build_cpnat34940755editdlrm
build_mail_sni39660755editdlrm
build_maxemails_config11690755editdlrm
call_pkgacct23060755editdlrm
ccs-check50310755editdlrm
checkalldomainsmxs24620755editdlrm
checkbashshell12050755editdlrm
checkccompiler12530755editdlrm
checkexim.pl31720755editdlrm
checklink13230755editdlrm
checkusers8560755editdlrm
check_cpanel_pkgs108560755editdlrm
check_domain_tls_service_domains.pl68410755editdlrm
check_immutable_files56210755editdlrm
check_mail_spamassassin_compiledregexps_body_01870755editdlrm
check_maxmem_against_domains_count36520755editdlrm
check_mount_procfs20720755editdlrm
check_mysql56970755editdlrm
check_plugin_pkgs25120755editdlrm
check_security_advice_changes84770755editdlrm
check_unmonitored_enabled_services46660755editdlrm
check_unreliable_resolvers36720755editdlrm
check_users_my_cnf61910755editdlrm
check_valid_server_hostname78400755editdlrm
chkpaths1410755editdlrm
chpass4160755editdlrm
ckillall11390755editdlrm
cleandns134290755editdlrm
cleandns84170755editdlrm
cleanmsglog7350755editdlrm
cleanphpsessions9320755editdlrm
cleanphpsessions.php6580644editdlrm
cleanquotas16510755editdlrm
cleansessions60320755editdlrm
cleanupinterchange27060755editdlrm
cleanupmysqlprivs7730755editdlrm
clean_dead_mailman_locks21410755editdlrm
clean_up_temp_wheel_users24980755editdlrm
clean_user_php_sessions48750755editdlrm
clear_orphaned_virtfs_mounts36450755editdlrm
comet_license_registration_sync17110755editdlrm
comet_protected_item_maintenance212810755editdlrm
comparecdb15610755editdlrm
compilers29320755editdlrm
compilerscheck9990755editdlrm
configure_firewall_for_cpanel5200755editdlrm
configure_rh_firewall_for_cpanel5200755editdlrm
configure_rh_ipv6_firewall_for_cpanel5200755editdlrm
convert2dovecot6820755editdlrm
convert_accesshash_to_token41710755editdlrm
convert_and_migrate_from_legacy_backup20170755editdlrm
convert_maildir_to_mdbox17030755editdlrm
convert_mdbox_to_maildir16980755editdlrm
convert_roundcube_mysql2sqlite267480755editdlrm
convert_to_dovecot_delivery44380755editdlrm
convert_whmxfer_to_sqlite14990755editdlrm
copy_user_mail_as_root12810755editdlrm
copy_user_mail_as_user13750755editdlrm
cpanelsync289910755editdlrm
cpanelsync_postprocessor16570755editdlrm
cpanel_initial_install695830755editdlrm
cpanpingtest9650755editdlrm
cpan_config28700755editdlrm
cpbackup458610755editdlrm
cpbackup_transport_file57810755editdlrm
cpdig28820755editdlrm
cpfetch12580755editdlrm
cphulkdblacklist4330755editdlrm
cphulkdwhitelist13360755editdlrm
cpservice29340755editdlrm
cpuser_port_authority197550755editdlrm
cpuser_service_manager111130755editdlrm
createacct319047600700editdlrm
create_default_featurelist119030700editdlrm
custom_backup_destination.pl.sample51820755editdlrm
custom_backup_destination.pl.skeleton29060755editdlrm
dcpumon-wrapper8500755editdlrm
delpop63500755editdlrm
detect_env_capabilities5080755editdlrm
disablefileprotect22410755editdlrm
disable_prelink28410755editdlrm
distro_changed_hook11850755editdlrm
dnscluster45460755editdlrm
dnsqueuecron13160755editdlrm
dnssec-cluster-keys38400755editdlrm
dovecot_maintenance78420755editdlrm
dovecot_set_defaults.pl9840755editdlrm
dumpcdb8660755editdlrm
dumpinodes6870755editdlrm
dumpquotas6160755editdlrm
dumpstor9130755editdlrm
ea4_fresh_install26990755editdlrm
editquota35120755editdlrm
edit_cpanelsync_exclude_list26410755editdlrm
elevate-cpanel4245770700editdlrm
email_archive_maintenance63000755editdlrm
email_hold_maintenance14950755editdlrm
enablefileprotect21490755editdlrm
enable_spf_dkim_globally90390755editdlrm
ensure_autoenabled_features33226320700editdlrm
ensure_conf_dir_crt_key49400755editdlrm
ensure_cpuser_file_ip26100755editdlrm
ensure_crontab_permissions11010755editdlrm
ensure_dovecot_memory_limits_meet_minimum32080755editdlrm
ensure_hostname_resolves25720755editdlrm
ensure_includes6010755editdlrm
ensure_vhost_includes138510755editdlrm
eximconfgen13500755editdlrm
eximstats_spam_check8670755editdlrm
exim_tidydb30360755editdlrm
expunge_expired_certificates_from_sslstorage36480755editdlrm
expunge_expired_pkgacct_sessions8520755editdlrm
expunge_expired_transfer_sessions10890755editdlrm
fastmail52810755editdlrm
featuremod19700755editdlrm
fetchfile4220755editdlrm
find_and_fix_rpm_issues71570755editdlrm
find_outdated_services66250755editdlrm
find_pids_with_inotify_watch_on_path37450755editdlrm
fix-cpanel-perl291120755editdlrm
fix-listen-on-localhost40360755editdlrm
fix-web-vhost-configuration62960755editdlrm
fixetchosts44240755editdlrm
fixheaders5720755editdlrm
fixmailinglistperms10080755editdlrm
fixmailman21440755editdlrm
fixnamedviews12470755editdlrm
fixndc4130755editdlrm
fixquotas188340755editdlrm
fixrelayd17840755editdlrm
fixrndc167800755editdlrm
fixtar5030755editdlrm
fixtlsversions48160755editdlrm
fixvaliases20470755editdlrm
fixwebalizer9660755editdlrm
fix_dns_zone_ttls13690755editdlrm
fix_innodb_tables41490755editdlrm
fix_reseller_acls109580755editdlrm
forcelocaldomain8950755editdlrm
ftpfetch22510755editdlrm
ftpquotacheck85110755editdlrm
ftpsfetch24160755editdlrm
ftpupdate2610755editdlrm
gather_update_logs_setupcrontab55820700editdlrm
gather_update_log_stats43540700editdlrm
gemwrapper17830755editdlrm
gencrt64100755editdlrm
generate_account_suspension_include58400755editdlrm
generate_google_drive_credentials11350755editdlrm
generate_google_drive_oauth_uri9840755editdlrm
generate_maildirsize149080755editdlrm
gensysinfo11850755editdlrm
getremotecpmove230840755editdlrm
get_locale_from_legacy_name_info20410755editdlrm
grpck12180755editdlrm
hackcheck30920755editdlrm
hook14870755editdlrm
httpspamdetect28910755editdlrm
hulk-unban-ip43014560700editdlrm
import_exim_data85930755editdlrm
increase_filesystem_limits8910755editdlrm
initacls51070755editdlrm
initfpsuexec4440755editdlrm
initialize_360monitoring28240700editdlrm
initquotas198110755editdlrm
initsuexec41230755editdlrm
installpkg5750755editdlrm
installpostgres67150755editdlrm
installsqlite318660755editdlrm
install_cpanel_analytics19730755editdlrm
install_dovecot_fts16050755editdlrm
install_plugin28690755editdlrm
install_tuxcare_els_php18890755editdlrm
ipcheck40200755editdlrm
ipusage76240755editdlrm
isdedicatedip6020755editdlrm
is_update_available33430755editdlrm
jetbackup-check37760755editdlrm
killdns4220755editdlrm
killdns-dnsadmin11800755editdlrm
killmysqluserprivs4330755editdlrm
killmysqlwildcard11800755editdlrm
killpvhost8530755editdlrm
killspamkeys9370755editdlrm
linksubemailtomainacct32480755editdlrm
link_3rdparty_binaries12710755editdlrm
listcheck5380755editdlrm
listsubdomains10740755editdlrm
litespeed-check39520755editdlrm
locale_export53310755editdlrm
locale_import48030755editdlrm
locale_info40860755editdlrm
logo.dat2050644editdlrm
log_retention217930755editdlrm
magicloader19850755editdlrm
maildir_converter62220755editdlrm
mailperm169230755editdlrm
mailscannerupdate24780755editdlrm
mainipcheck102360755editdlrm
maintenance534450755editdlrm
make_config4070644editdlrm
make_hostname_unowned11890755editdlrm
manage_extra_marketing130680700editdlrm
manage_greylisting167190755editdlrm
manage_mysql_profiles167270755editdlrm
mass_change_php_setting109040755editdlrm
migrate_ccs_to_cpdavd481860755editdlrm
migrate_local_ini_to_php_ini75870755editdlrm
migrate_whmtheme_file_to_userdata30250755editdlrm
MirrorSearch_pingtest24370755editdlrm
mkwwwacctconf23850755editdlrm
modify_accounts41690755editdlrm
modify_featurelist115970700editdlrm
modify_packages37260755editdlrm
modsec_vendor160080755editdlrm
mysqlconnectioncheck68770755editdlrm
mysqlpasswd42350755editdlrm
named.ca16030644editdlrm
named.rfc1912.zones7740644editdlrm
notify_expiring_certificates95920755editdlrm
notify_expiring_certificates_on_linked_nodes13610755editdlrm
oopscheck11420755editdlrm
optimize_eximstats39750755editdlrm
panel_ini42100755editdlrm
patchfdsetsize27840755editdlrm
patch_mail_spamassassin_compiledregexps_body_024520755editdlrm
pedquota23100755editdlrm
perform_sqlite_auto_rebuild_db_maintenance20310755editdlrm
perlinstaller5280755editdlrm
perlmods12040755editdlrm
phpini_tidy6870755editdlrm
php_fpm_config99680755editdlrm
pkgacct920650755editdlrm
post_snapshot21440755editdlrm
post_sync_cleanup59730755editdlrm
primary_virtual_host_migration25020755editdlrm
process_cpmove44190755editdlrm
process_pending_cpanel_php_pear_registration27930755editdlrm
proxydomains98220755editdlrm
ptycheck7240755editdlrm
purge_modsec_log15630755editdlrm
purge_old_config_caches21250755editdlrm
pwck7080755editdlrm
quickdnslookup11590755editdlrm
quickwhoisips23480755editdlrm
quotacheck229000755editdlrm
quota_auto_fix14400755editdlrm
rawchpass4600755editdlrm
rdate49130755editdlrm
realadduser57430755editdlrm
realchpass33360755editdlrm
realperlinstaller58050755editdlrm
realrawchpass4250755editdlrm
rebuilddnsconfig261100755editdlrm
rebuildhttpdconf26640755editdlrm
rebuildinstalledssldb29170755editdlrm
rebuildippool5090755editdlrm
rebuilduserssldb9480755editdlrm
rebuild_bandwidthdb_root_cache14870755editdlrm
rebuild_dbmap59370755editdlrm
rebuild_provider_openid_connect_links_db10390755editdlrm
rebuild_whm_chrome22770755editdlrm
refresh-dkim-validity-cache61100755editdlrm
regenerate_tokens22280755editdlrm
remote_log_transfer118750755editdlrm
removeacct296544000700editdlrm
remove_dovecot_index_files60280755editdlrm
rescan_user_dovecot_fts30480755editdlrm
resetmailmanurls20770755editdlrm
resetquotas47230755editdlrm
reset_mail_quotas_to_sane_values69820755editdlrm
restartsrv32660755editdlrm
restartsrv_apache4220755editdlrm
restartsrv_apache_php_fpm113689600755editdlrm
restartsrv_base113689600755editdlrm
restartsrv_bind113689600755editdlrm
restartsrv_chkservd4270755editdlrm
restartsrv_clamd113689600755editdlrm
restartsrv_cpanellogd113689600755editdlrm
restartsrv_cpanel_php_fpm113689600755editdlrm
restartsrv_cpdavd113689600755editdlrm
restartsrv_cpgreylistd113689600755editdlrm
restartsrv_cphulkd113689600755editdlrm
restartsrv_cpipv6113689600755editdlrm
restartsrv_cpsrvd113689600755editdlrm
restartsrv_crond113689600755editdlrm
restartsrv_dnsadmin113689600755editdlrm
restartsrv_dovecot113689600755editdlrm
restartsrv_exim113689600755editdlrm
restartsrv_eximstats5040755editdlrm
restartsrv_ftpd4260755editdlrm
restartsrv_ftpserver9110755editdlrm
restartsrv_httpd113689600755editdlrm
restartsrv_imap4370755editdlrm
restartsrv_inetd25250755editdlrm
restartsrv_ipaliases113689600755editdlrm
restartsrv_lmtp4370755editdlrm
restartsrv_mailman113689600755editdlrm
restartsrv_mysql113689600755editdlrm
restartsrv_named5790755editdlrm
restartsrv_nscd113689600755editdlrm
restartsrv_p0f113689600755editdlrm
restartsrv_pdns113689600755editdlrm
restartsrv_pop34370755editdlrm
restartsrv_postgres4270755editdlrm
restartsrv_postgresql113689600755editdlrm
restartsrv_powerdns4420755editdlrm
restartsrv_proftpd113689600755editdlrm
restartsrv_pureftpd113689600755editdlrm
restartsrv_queueprocd113689600755editdlrm
restartsrv_rsyslog113689600755editdlrm
restartsrv_rsyslogd4370755editdlrm
restartsrv_spamd113689600755editdlrm
restartsrv_sshd113689600755editdlrm
restartsrv_syslogd24580755editdlrm
restartsrv_tailwatchd113689600755editdlrm
restartsrv_unknown113689600755editdlrm
restartsrv_xinetd4220755editdlrm
restorecpuserfromcache20080755editdlrm
restorepkg511943600700editdlrm
rfc1912_zones.tar102400644editdlrm
rpmup51910755editdlrm
rsync-user-homedir.pl59030755editdlrm
runstatsonce4400755editdlrm
runweblogs10450755editdlrm
run_if_exists5120755editdlrm
run_plugin_lifecycle40600700editdlrm
sa-update_wrapper34180755editdlrm
safetybits.pl8440755editdlrm
secureit48340755editdlrm
securemysql45010755editdlrm
securerailsapps36610755editdlrm
securetmp171620755editdlrm
sendicq4740755editdlrm
servicedomains98220755editdlrm
setpostgresconfig61810755editdlrm
setupftpserver107260755editdlrm
setupmailserver96180755editdlrm
setupnameserver128980755editdlrm
setup_greylist_db167190755editdlrm
setup_modsec_db13350755editdlrm
setup_systemd_timer_for_plugins40150700editdlrm
set_mailman_archive_perms17960755editdlrm
show_php_settings37620755editdlrm
shrink_modsec_ip_database132850755editdlrm
simpleps31240755editdlrm
slurp_exim_mainlog59140755editdlrm
smartcheck154910755editdlrm
smtpmailgidonly83430755editdlrm
snapshot_prep60170755editdlrm
spamassassindisable38300755editdlrm
spamassassin_dbm_cleaner59930755editdlrm
spamboxdisable23240755editdlrm
sshcontrol147220755editdlrm
ssl_crt_status39280755editdlrm
suspendacct185160755editdlrm
suspendmysqlusers48900755editdlrm
swapip39140755editdlrm
sync-mysql-users-from-grants12250755editdlrm
synctransfers19710755editdlrm
sync_child_accounts18130755editdlrm
sync_contact_emails_to_cpanel_users_files11630755editdlrm
syslog_check13910755editdlrm
sysup6450755editdlrm
test_sa_compiled10930755editdlrm
transfermysqlusers106272960700editdlrm
transfer_accounts_as_root48700755editdlrm
transfer_account_as_user23980755editdlrm
transfer_in_progress31560755editdlrm
transfer_in_progress.pod3120644editdlrm
try-later81400755editdlrm
unblockip6670755editdlrm
uninstall_cpanel_analytics12300755editdlrm
uninstall_dovecot_fts5620755editdlrm
uninstall_plugin29070755editdlrm
unlink_service_account26820755editdlrm
unpkgacct47130755editdlrm
unslavenamedconf8630755editdlrm
unsuspendacct183870755editdlrm
unsuspendmysqlusers72660755editdlrm
upcp440380755editdlrm
upcp-running27680755editdlrm
upcp.static9772510755editdlrm
update-packages51910755editdlrm
updatedomainips6050755editdlrm
updatenameserverips16960755editdlrm
updatenow53020755editdlrm
updatenow.static21167080755editdlrm
updatesigningkey19960755editdlrm
updatessldomains18560755editdlrm
updatesupportauthorizations25520755editdlrm
updateuserdatacache25290755editdlrm
updateuserdomains7740755editdlrm
update_apachectl4800755editdlrm
update_db_cache4300755editdlrm
update_dkim_keys14850755editdlrm
update_exim_rejects12420755editdlrm
update_existing_mail_quotas_for_account48910755editdlrm
update_feature_flags9570755editdlrm
update_freebusy_data53760755editdlrm
update_known_proxy_ips10020755editdlrm
update_local_rpm_versions46690755editdlrm
update_mailman_cache85450755editdlrm
update_mysql_systemd_config10940755editdlrm
update_neighbor_netblocks4870755editdlrm
update_sa_config21960755editdlrm
update_spamassassin_config109880755editdlrm
update_users_jail6910755editdlrm
update_users_vhosts8010755editdlrm
upgrade_bandwidth_dbs22720755editdlrm
upgrade_subaccount_databases27970755editdlrm
userdata_wildcard_cleanup58770755editdlrm
userdirctl51340755editdlrm
validate_sshkey_passphrase12440755editdlrm
verify_api_spec_files7570755editdlrm
verify_pidfile20080755editdlrm
verify_vhost_includes75170755editdlrm
vps_optimizer80070755editdlrm
vzzo-fixer7250755editdlrm
whmlogin23900755editdlrm
whoowns11550755editdlrm
wwwacct319047600700editdlrm
wwwacct2880755editdlrm
xferpoint32010755editdlrm
xfertool166240755editdlrm
xfer_rcube_schema_migrate.pl24600755editdlrm
xfer_rcube_uid_resolver.pl18460755editdlrm
zoneexists8000755editdlrm
Edit: /usr/local/cpanel/scripts/maintenance (53445B)
#!/usr/local/cpanel/3rdparty/bin/perl # Copyright 2026 WebPros International, LLC # All rights reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited. package scripts::maintenance; use cPstrict; use Try::Tiny; use Cpanel::iContact::Class::Update::EndOfLife (); use Cpanel::AccessIds (); use Cpanel::Binaries (); use Cpanel::TimeHiRes (); use Cpanel::Config::LoadCpConf (); use Cpanel::ConfigFiles (); use Cpanel::Crypt::GPG::Settings (); use Cpanel::Crypt::GPG::VendorKeys::TimestampCache (); use Cpanel::Env (); use Cpanel::IOCallbackWriteLine (); use Cpanel::Leika (); use Cpanel::MysqlUtils::Version (); use Cpanel::Notify (); use Cpanel::OS (); use Cpanel::Pkgr (); use Cpanel::Rand::Get (); use Cpanel::SafeRun::Object (); use Cpanel::SafeRun::BG (); use Cpanel::Server::Type (); use Cpanel::ServerTasks (); use Cpanel::Services::Enabled (); use Cpanel::Sync::CheckRestore (); use Cpanel::Update::Config (); use Cpanel::Config::Crontab (); use Cpanel::Update::Logger (); use Whostmgr::Exim::Sysconfig (); use IO::Handle (); use IO::Select (); # hash we'll use to process each request our $RPM_IS_BROKEN = 0; our $_UPGRADE_IN_PROGRESS_FILE = '/usr/local/cpanel/upgrade_in_progress.txt'; my $DRY_RUN; our $SQLITE_AUTO_REBUILD_LAST_RAN_FILE = '/var/cpanel/.last_ran_sqlite_auto_rebuild_from_maintenance'; # Internal documentation: https://cpanel.wiki/x/zwwFAw sub script { my ( $class, @args ) = @_; if ( $> != 0 ) { print "This cPanel maintenance script must be run as root, not uid $>.\n"; return 2; } umask(0022); my $security_token = $ENV{'cp_security_token'} || ''; # default pcent when none are defined my $starting_pbar = 0; my $finishing_pbar = 100; # in case we are called before and outside of upcp setupenv(); my $only_run; # create a default logfile path, if called from upcp, use the log it passes my $now = time(); my $logfile_path = '/var/cpanel/updatelogs/maintenance' . $now . '.log'; my $custom_pbar; foreach my $arg (@args) { if ( $arg =~ m/^--log\=(.*)/ ) { $logfile_path = $1; } elsif ( $arg =~ m/^--pbar-start=([0-9]+)/ ) { $custom_pbar = 1; $starting_pbar = int($1); } elsif ( $arg =~ m/^--pbar-stop=([0-9]+)/ ) { $custom_pbar = 1; $finishing_pbar = int($1); } elsif ( $arg =~ m/^--dry-run$/ ) { # no doc required: dev only $DRY_RUN = 1; } elsif ( $arg =~ m/^--pre$/ ) { # no doc required: upcp only $only_run = 'pre'; } elsif ( $arg =~ m/^--post$/ ) { # no doc required: upcp only $only_run = 'post'; } elsif ( $arg =~ m/^--help/ ) { return usage(); } } open( STDERR, ">&STDOUT" ); $| = 1; # when start pbar is unset progress bar is not displayed setup_logger( $logfile_path, $custom_pbar ? $starting_pbar : undef ); # helper which normalize all percentage to be in [ $starting_pbar .. $finishing_pbar ] # the only thing that we should care are the capping values which should be between [ 0..100 ] my $increment_pbar; # initialize later as we can count how many tasks to run my $do_progress_bar = sub { my (@args) = @_; return bless sub { $increment_pbar->(@args) }, 'PBAR'; }; ############################################################################# # maintenance actions are split in 2 groups: pre and post # by default maintenance is going to run both groups: pre than post # /scripts/maintenance is similar to run # 1. ~maintenance --pre # 2. ~maintenance --post # but we can now run only one of these groups, this allow to run post_sync_cleanup earlier during upcp # /scripts/upcp is going to use maintenance script using 2 different calls # 1. update.now # 2. maintenance --pre # 3. post_sync_cleanup # 4. maintenance --post my $blocks = { pre => [ _default_pre_actions() ], post => [ _default_post_actions() ] }; if ( !Cpanel::Server::Type::is_dnsonly() ) { push @{ $blocks->{'post'} }, ( action_sprite_generator(), action_update_rdns_ips_cache(), show_status('Updating services and databases'), '/usr/local/cpanel/scripts/listcheck', action_purge_modsec(), ( $ENV{'CPANEL_BASE_INSTALL'} ? () : ( action_ftpquotacheck() ) ), '/usr/local/cpanel/scripts/updateuserdomains', '/usr/local/cpanel/bin/empty_user_trash --quiet --all', '/usr/local/cpanel/scripts/build_maxemails_config', '/usr/local/cpanel/scripts/updateuserdatacache --force', show_status('Checking system maxmem setting'), '/usr/local/cpanel/scripts/check_maxmem_against_domains_count --always-fix', show_status('Running various cleanup scripts'), '/usr/local/cpanel/scripts/resetmailmanurls', show_status('Checking MySQL to ensure we can connect'), ( # Base install does this in the background before upcp $ENV{'CPANEL_BASE_INSTALL'} ? () : ( '/usr/local/cpanel/scripts/mysqlconnectioncheck' # POST or leave it there ?? # We must update the rules before we compile them ) ), action_update_spamassassin_rules(), show_status('Checking PostgreSQL to ensure we can connect'), '/usr/local/cpanel/bin/postgrescheck --check-auth --reset-pass-on-fail', # POST or leave it there ?? action_repair_mailman(), action_repair_mysql(), show_status('Running sanity checks and notifications'), # status update '/usr/local/cpanel/scripts/chkpaths', '/usr/local/cpanel/scripts/hackcheck', '/usr/local/cpanel/scripts/oopscheck', '/usr/local/cpanel/scripts/fixetchosts', '/usr/local/cpanel/scripts/check_unreliable_resolvers --notify', '/usr/local/cpanel/bin/is_script_stuck --script=autossl_check --time=3h --kill --notify=root', ( $ENV{'CPANEL_BASE_INSTALL'} ? () : ('/usr/local/cpanel/scripts/quotacheck') ), '/usr/local/cpanel/scripts/email_archive_maintenance', '/usr/local/cpanel/scripts/email_hold_maintenance', '/usr/local/cpanel/scripts/expunge_expired_certificates_from_sslstorage', '/usr/local/cpanel/scripts/notify_expiring_certificates', '/usr/local/cpanel/scripts/notify_expiring_certificates_on_linked_nodes', '/usr/local/cpanel/scripts/expunge_expired_transfer_sessions', '/usr/local/cpanel/scripts/expunge_expired_pkgacct_sessions', '/usr/local/cpanel/scripts/smartcheck', '/usr/local/cpanel/scripts/compilerscheck', '/usr/local/cpanel/scripts/check_mount_procfs', sqlite_auto_rebuild_if_needed(), '/usr/local/cpanel/scripts/setup_modsec_db', '/usr/local/cpanel/scripts/modsec_vendor update --auto', '/usr/local/cpanel/bin/check_cpstore_in_sync_with_local_storage', action_purge_dead_comet_files(), action_update_freshclam(), show_status('Restoring compiler permissions'), '/usr/local/cpanel/scripts/compilers restore', show_status('Cleaning up mailbox trash'), '/usr/local/cpanel/scripts/dovecot_maintenance --background', show_status('Checking MySQL Version'), sub { check_mysql_version() }, show_status('Cleaning up root datastores and caches'), '/usr/local/cpanel/bin/clean-datastores --background root', ); } # end !dnsonly push @{ $blocks->{'post'} }, ( action_buildexim(), action_eximstats(), action_exim_purge_old_tracker_files(), action_exim_sysconfig(), sub { Cpanel::Sync::CheckRestore::check_and_restore("img-sys/powered_by_cpanel.svg") }, action_cleanup_signature(), ); if ( !Cpanel::Server::Type::is_dnsonly() ) { # not dnsonly push @{ $blocks->{'post'} }, ( ( $ENV{'CPANEL_BASE_INSTALL'} ? () : ( show_status('Cleaning SpamAssassin DBM files'), '/usr/local/cpanel/scripts/spamassassin_dbm_cleaner' ) ), show_status('Cleaning Roundcube attachment directory'), \&clean_roundcube_attachment_directory, ( # This was causing an OOM on fresh install on the # $5/mo DO instance # There will be no one to notify on a fresh install # and this will run a few hours after the install # anyways $ENV{'CPANEL_BASE_INSTALL'} ? () : ( show_status('Checking for new security advice'), '/usr/local/cpanel/scripts/check_security_advice_changes --notify --background', ) ), show_status('Running former postinstall scripts'), '/usr/local/cpanel/bin/dcpumon --killproc', '/usr/local/cpanel/bin/setupdbmap', '/usr/local/cpanel/bin/fix_userdata_perms', '/usr/local/cpanel/scripts/detect_env_capabilities', ( # Base install does this in the background before upcp $ENV{'CPANEL_BASE_INSTALL'} ? () : ( show_status('Updating cPGreyList Common Mail Providers'), '/usr/local/cpanel/scripts/manage_greylisting --init --update_common_mail_providers' ) ), show_status('Checking for deprecated PHP local.ini'), '/usr/local/cpanel/scripts/migrate_local_ini_to_php_ini --run --verbose', show_status('Ensuring an "Active" MySQL profile is set'), \&ensure_active_mysql_profile_is_present, run( '/usr/local/cpanel/scripts/check_mysql', { 'exit_ok' => [ 2, 255 ] } ), action_cloudlinux_update(), show_status('Updating plugins data cache'), '/usr/local/cpanel/bin/refresh_plugin_cache', show_status('Ensuring SSL certificate information for CCS is up to date.'), '/usr/local/cpanel/scripts/ccs-check --run --ssl', show_status('Ensure cpanel-plugins yum repo exists'), \&_create_cpanel_plugins_repo, show_status('Checking Addon Licenses'), check_addon_licenses(), show_status('Updating Public Suffix List'), update_public_suffix_list(), show_status('Ensuring ELS PHP State Matches License'), \&ensure_els_php_state, ); } push @{ $blocks->{'post'} }, ( show_status('Checking End Of Life for current version.'), \&check_end_of_life, ); my $maintenance_complete = Cpanel::Server::Type::is_dnsonly() ? q{DNSONLY maintenance complete.} : q{Maintenance complete.}; # build the todo list depending which block we want to run # default = pre + post my @todo = ( @{ $blocks->{'pre'} }, @{ $blocks->{'post'} } ); # Remove the todo once done if ( $only_run && ref $blocks->{$only_run} ) { @todo = @{ $blocks->{$only_run} }; $maintenance_complete .= " [state=$only_run]"; } # we have now reach 100%, move the progress bar push @todo, ( $do_progress_bar->( complete => 1 ), show_status("\n\n$maintenance_complete\n"), ); # how many actions do we have to run which are neither a status nor a pbar item my $total_actions = grep { my $ref = ref $_; $ref ne 'PBAR' && $ref !~ /Action::(?:Status|Command)/ } @todo; # initialize progress bar with: from % to % and number of elements $increment_pbar = increment_pbar( $starting_pbar, $finishing_pbar, $total_actions ); run_actions( \@todo, $increment_pbar ); return logger()->get_need_notify() ? 1 : 0; } # Encapsulate to pick up "a few dollars more" of cover, especially because # cplint complained about it in CPANEL-38056. Oh no, I lost cover otherwise. # Original comment below: # This is the only pre block in this script. Only things that MUST happen before post_sync_cleanup should live here. sub _default_pre_actions { return ( show_status('Assuring needed symlinks in 3rdparty/bin are in place.'), '/usr/local/cpanel/scripts/link_3rdparty_binaries', show_status('Setting clock'), '/usr/local/cpanel/scripts/rdate', # Process any possibly pending PHP PEAR updates from cpanel-php pear RPMs in the background, # as they should have already been installed during update.now action_update_pear_registry_in_the_background(), action_set_up_dns_resolver_workarounds(), action_background_refresh_dkim_validity_cache(), show_status('Ensuring cPanel package manager variables are in place'), \&_ensure_yum_vars, action_find_and_fix_rpm_issues(), # set RPM_IS_BROKEN (at run time): used by sysup and check_cpanel_pkgs action_update_packages(), action_ensure_mysql_upgrade_hook(), ); } sub _default_post_actions { return ( \&purge_upcp_logs, show_status('Processing web server log retention'), '/usr/local/cpanel/scripts/log_retention --run', action_updatesigningkey(), action_sysup(), action_update_feature_flags(), #We do it right after post sync cleanup and sysup #to ensure cPanel services have been restarted before we #do any system ones so that they can access cPanel #and monitor the system while the system services are #being restarted. show_status('Restarting any outdated services'), $ENV{'CPANEL_BASE_INSTALL'} ? () : ( run( '/usr/local/cpanel/scripts/find_outdated_services --auto', { exit_ok => [1] } ) ), # Base install does this in the background before upcp action_vps_optimizer(), # not on dnsonly show_status('Checking for a valid C Compiler.'), '/usr/local/cpanel/scripts/checkccompiler', action_build_locale_databases(), show_status('Migrating feature lists to current version (if needed)'), '/usr/local/cpanel/bin/migrate_all_feature_lists_to_current', show_status('Checking for main IP changes'), '/usr/local/cpanel/scripts/mainipcheck', show_status('Updating neighbor netblocks'), '/usr/local/cpanel/scripts/update_neighbor_netblocks', show_status('Updating known proxy ips'), '/usr/local/cpanel/scripts/update_known_proxy_ips', show_status('Validating server hostname'), # No need to check this on a fresh install since we already validate in the installer ( $ENV{'CPANEL_BASE_INSTALL'} ? () : ('/usr/local/cpanel/scripts/check_valid_server_hostname --notify') ), show_status('Validating cPanel system users'), '/usr/local/cpanel/scripts/checkusers', action_fixrndc(), action_init_wwwacct_conf(), action_ipaliases(), action_check_cpanel_pkgs(), action_check_plugin_packages(), show_status('Running env auto repair'), '/usr/local/cpanel/scripts/vzzo-fixer', '/usr/local/cpanel/scripts/quota_auto_fix', '/usr/local/cpanel/scripts/clear_orphaned_virtfs_mounts --inactiveonly', '/usr/local/cpanel/scripts/disable_prelink', show_status('Cleaning up orphaned filesystem quotas'), '/usr/local/cpanel/scripts/cleanquotas', ( $ENV{'CPANEL_BASE_INSTALL'} ? () : ('/usr/local/cpanel/scripts/autorepair autorepair') ), '/usr/local/cpanel/scripts/purge_old_config_caches', '/usr/local/cpanel/scripts/cleansessions', '/usr/local/cpanel/scripts/checkbashshell', action_passwd(), \&setupcrontab, '/usr/local/cpanel/scripts/dnsqueuecron', show_status('Rebuild WHM chrome cache'), '/usr/local/cpanel/scripts/rebuild_whm_chrome', # checkallsslcerts needs to run on DNSONLY # because we need an ssl cert for dovecot for it to startup # Ensure /var/cpanel/ssl/*-SIGNATURE_CHAIN_VERIFIED and # /var/cpanel/ssl/*-NO_AFTER is updated so Cpanel::Redirect # can make good descisions. This also ensures that # admins get timely notice of the expire time being # reached on their ssl certificates. action_checkallsslcerts(), show_status('Purging invalid or soon-to-expire Domain TLS entries for service domains'), '/usr/local/cpanel/scripts/check_domain_tls_service_domains.pl --prune', show_status('Cleaning up temporary wheel/sudo users'), '/usr/local/cpanel/scripts/clean_up_temp_wheel_users', action_check_for_long_running_package_locks(), ); } sub check_end_of_life { # EOL # Send a notification if this version is nearing end of life local $@; eval { open my $mainip_fh, '<', '/var/cpanel/mainip' or die "Can't open < /var/cpanel/mainip: $!"; my $ip = <$mainip_fh>; close $mainip_fh; chomp $ip; my $icontact_class = 'Update::EndOfLife'; Cpanel::Notify::notification_class( constructor_args => [ origin => 'upcp', source_ip_address => $ip ], map { $_ => $icontact_class } qw(class application), ); 1; } or logger()->warning("Error while checking end of life: $@"); return; } sub sqlite_auto_rebuild_if_needed { return if !_is_saturday_or_sunday(); #If the touch file is newer than the current time #we assume the system had a clock issue and run. my $now = time(); my $last_ran = ( stat $SQLITE_AUTO_REBUILD_LAST_RAN_FILE )[9] || 0; return if $last_ran < $now && $now < ( $last_ran + ( 5 * 86400 ) ); do { open( my $fh, '>', $SQLITE_AUTO_REBUILD_LAST_RAN_FILE ) or warn "open($SQLITE_AUTO_REBUILD_LAST_RAN_FILE): $!" }; #This gets a longer timeout because on heavily populated #servers it can take over an hour to finish. return run( '/usr/local/cpanel/scripts/perform_sqlite_auto_rebuild_db_maintenance', { timeout => 10000, }, ); } #mocked in tests sub _is_saturday_or_sunday { #Only run on Saturday or Sunday my $wday = (localtime)[6]; return ( ( $wday == 0 ) || ( $wday == 6 ) ); } our %touch_file_mock; # Used to fake if touch files are present. sub touch_file_exists { my ($file) = @_; $file or return; # Provide an easy way to mock file existance. return $touch_file_mock{$file} if exists $touch_file_mock{$file}; return -e $file; } sub file_is_executable { my $file = shift; # for now use the same mock hash return $touch_file_mock{$file} if exists $touch_file_mock{$file}; return -x $file; } sub populated_touch_file_exists { my ($file) = @_; $file or return; # Provide an easy way to mock file existance. return $touch_file_mock{$file} if exists $touch_file_mock{$file}; return -e $file && !-z _; } ################################################################ ####[ Subroutines ]############################################# ################################################################ sub run_action { # avoid to use array ref when using it from a single action my (@todo) = @_; return run_actions( \@todo ); } sub run_actions { my ( $todo, $increment_pbar ) = @_; die unless ref $todo; foreach my $cmd (@$todo) { my $start_time = Cpanel::TimeHiRes::time(); my $type = ref $cmd; my $action = {}; if ( $type eq 'Action::Command' ) { $action = {%$cmd}; $cmd = $action->{'cmd'}; } elsif ( $type eq 'Action::Status' ) { $action = { status => $cmd->[0] }; $cmd = undef; } elsif ($type) { if ( $type eq 'CODE' ) { if ($DRY_RUN) { print "[dry-run mode] CodeRef\n"; } else { # custom cases with some extra code around the action # let them do what they want local $@; # Ensure that we do not allow a single action to # cause the entire script to fail. eval { $cmd->(); }; warn if $@; } $increment_pbar->() if ref $increment_pbar; my $runtime = sprintf( "%0.3f", Cpanel::TimeHiRes::time() - $start_time ); logger()->info(" - Finished in $runtime seconds"); } elsif ( $type eq 'PBAR' ) { $cmd->(); } next; } $action->{cmd} = [ split( /\s+/, $cmd ) ] if $cmd; process($action); my $runtime = sprintf( "%0.3f", Cpanel::TimeHiRes::time() - $start_time ); logger()->info(" - Finished command `$cmd` in $runtime seconds") if $cmd; $increment_pbar->() if ref $increment_pbar; } return; } sub show_status { my $msg = shift; return unless defined $msg or length $msg; my $status = [$msg]; bless $status, 'Action::Status'; return $status; } sub run { my ( $cmd, $options ) = @_; $options //= {}; my $status = { %$options, cmd => $cmd }; bless $status, 'Action::Command'; return $status; } sub process { my ($action) = @_; $action->{'status'} = '' if !defined $action->{'status'}; if ( length( $action->{'status'} ) ) { logger()->info("Processing: $action->{'status'}"); return; } my @cmd = @{ $action->{'cmd'} }; if ($DRY_RUN) { print "[dry-run mode] " . join( ' ', @cmd, "\n" ); return; } logger()->info(" - Processing command `@cmd`"); my ( $program, @args ) = @cmd; my $logger = logger(); my $run = eval { Cpanel::SafeRun::Object->new( 'program' => $program, 'args' => \@args, 'stdout' => Cpanel::IOCallbackWriteLine->new( sub { $logger->info(" [$program] $_[0]"); } ) ); }; $? = -1; ## no critic qw(Variables::RequireLocalizedPunctuationVars) -- needed for compat if ($@) { logger()->error( " [$program] $@", 1 ); logger()->set_need_notify(); return; } $? = $run->CHILD_ERROR(); ## no critic qw(Variables::RequireLocalizedPunctuationVars) -- needed for compat if ( my $exit = $run->CHILD_ERROR() ) { $exit >>= 8; return if $exit && $action->{'exit_ok'} && grep { $exit == $_ } @{ $action->{'exit_ok'} }; if ( my $stderr = $run->stderr() ) { foreach my $line ( split( m{\n}, $stderr ) ) { logger()->error( " [$program] " . $line ); } } logger()->error( " [$program] " . $run->autopsy(), 1 ); logger()->set_need_notify(); return; } } # list of actions which need some extra logic or being postponed sub action_vps_optimizer { return if Cpanel::Server::Type::is_dnsonly(); # idea move this check to the script itself return ( show_status('Running platform specific optimizations'), '/usr/local/cpanel/scripts/vps_optimizer' ); } sub action_update_feature_flags { return if $ENV{'CPANEL_BASE_INSTALL'}; return ( show_status('Updating the available feature flags'), '/usr/local/cpanel/scripts/update_feature_flags' ); } sub action_update_spamassassin_rules { return if $ENV{'CPANEL_BASE_INSTALL'}; return unless Cpanel::Update::Config::is_permitted( 'SARULESUP', get_update_conf() ); return sub { return run_action( show_status('Updating Apache SpamAssassin™ rules'), background_update_spamassassin_rules(), ); }; } sub action_update_rdns_ips_cache { return sub { return run_action( show_status('Updating Reverse DNS Cache'), background_update_rdns_ips_cache(), ); }; } sub background_update_rdns_ips_cache { return sub { warn if !eval { Cpanel::ServerTasks::queue_task( ['DNSTasks'], "update_reverse_dns_cache" ); 1; }; warn if !eval { Cpanel::ServerTasks::schedule_task( ['CpDBTasks'], 600, "update_userdomains" ); 1; }; }; } sub background_update_spamassassin_rules { return sub { warn if !eval { Cpanel::ServerTasks::queue_task( ['SpamassassinTasks'], 'update_spamassassin_rules' ); 1 }; }; } sub background_sprite_generator { return sub { eval { Cpanel::ServerTasks::queue_task( ['SpriteTasks'], 'sprite_generator' ); }; }; } sub action_set_up_dns_resolver_workarounds { return sub { return run_action( show_status('Setting up resolver workarounds'), background_set_up_dns_resolver_workarounds(), ); }; } sub background_set_up_dns_resolver_workarounds { return sub { warn if !eval { Cpanel::ServerTasks::queue_task( ['DNSTasks'], "set_up_dns_resolver_workarounds" ); 1; }; }; } sub action_sprite_generator { return sub { return run_action( show_status('Rebuilding sprites'), background_sprite_generator(), ); }; } sub background_freshclam { return sub { eval { Cpanel::ServerTasks::queue_task( ['ClamTasks'], 'freshclam --quiet -l /var/log/clam-update.log' ); }; }; } sub action_background_refresh_dkim_validity_cache { return sub { eval { Cpanel::ServerTasks::queue_task( ['DKIMTasks'], 'refresh_entire_dkim_validity_cache' ); }; }; } sub action_update_freshclam { return sub { # postpone the check if the binary is restored by RPM transaction my $freshclam_bin = Cpanel::Binaries::path('freshclam'); return unless file_is_executable($freshclam_bin); return run_action( show_status('Updating virus patterns'), background_freshclam(), ); } } sub action_purge_dead_comet_files { return ( show_status('Purging old comet files'), '/usr/local/cpanel/bin/purge_dead_comet_files --quiet', ); } sub action_update_packages { return sub { # need RPM_IS_BROKEN to be set return unless Cpanel::Update::Config::is_permitted( 'RPMUP', get_update_conf() ); return if $RPM_IS_BROKEN; return run_action( show_status('Running update-packages'), '/usr/local/cpanel/scripts/update-packages' ); }; } sub action_ensure_mysql_upgrade_hook { return sub { require Cpanel::MariaDB; my $config = scalar Cpanel::Config::LoadCpConf::loadcpconf(); my $set_version = $config->{'mysql-version'}; return if $set_version < 5.7; if ( Cpanel::MariaDB::version_is_mariadb($set_version) ) { require Cpanel::MariaDB::Install; my $mysql_install_obj = Cpanel::MariaDB::Install->new( 'output_obj' => logger() ); $mysql_install_obj->install_upgrade_hook(); return 1; } require Cpanel::Mysql::Install; my $mysql_install_obj = Cpanel::Mysql::Install->new( 'output_obj' => logger() ); $mysql_install_obj->install_upgrade_hook(); return 1; } } sub action_update_pear_registry_in_the_background { return sub { return Cpanel::SafeRun::BG::nooutputsystembg('/usr/local/cpanel/scripts/process_pending_cpanel_php_pear_registration'); }; } # The package manager expands these when it reads any cPanel repository file, # so they have to be restored before the first package operation of the run. sub _ensure_yum_vars { local $@; eval { require Cpanel::Yum::Vars; Cpanel::Yum::Vars::install(); 1; } or logger()->warning("Failed to install the cPanel package manager variables: $@"); return; } sub _create_cpanel_plugins_repo { local $@; eval { require Cpanel::Plugins::Repo; Cpanel::Plugins::Repo::install(); 1; } or logger()->warning("Failed to install the cpanel-plugins repository: $@"); return; } sub action_sysup { return if $ENV{'CPANEL_BASE_INSTALL'}; # This will already have been run on initial install return sub { # need RPM_IS_BROKEN to be set if ($RPM_IS_BROKEN) { logger()->error('RPM is not functioning. Skipping sysup.'); return; } return run_action( show_status('Updating system packages: sysup'), '/usr/local/cpanel/scripts/sysup' ); }; } sub _find_and_fix_rpm_issue_script { # for testing purpose return '/usr/local/cpanel/scripts/find_and_fix_rpm_issues'; } sub action_find_and_fix_rpm_issues { return unless Cpanel::OS::is_rpm_based(); return if $ENV{'CPANEL_BASE_INSTALL'}; # we will not get here if rpm is broken return sub { local $?; process( { 'status' => 'Checking RPM DB for corruption' } ); process( { 'cmd' => [ _find_and_fix_rpm_issue_script() ] } ); if ( ( $? >> 8 ) > 0 ) { logger()->error('RPM is not functioning and automatic repair failed.'); logger()->error('Tasks for update-packages, sysup, and check_cpanel_pkgs will be skipped.'); $RPM_IS_BROKEN = 1; } return; }; } sub action_updatesigningkey { # Update signing keys, if enabled. return unless Cpanel::Crypt::GPG::Settings::signature_validation_enabled(); return ( show_status('Updating cPanel signing keys.'), '/usr/local/cpanel/scripts/updatesigningkey' ); } sub action_cloudlinux_update { return unless Cpanel::OS::supports_or_can_become_cloudlinux(); return ( show_status('Checking CloudLinux installation'), '/usr/local/cpanel/bin/cloudlinux_update', '/usr/local/cpanel/install/SetupCageFS.pm', ); } sub action_checkallsslcerts { # Base install does this in the background before upcp return if $ENV{'CPANEL_BASE_INSTALL'}; my $max_delay_seconds = 18 * 60 * 60; # 18 hours my $bytes_to_get = length($max_delay_seconds) + 1; my $rand_int = Cpanel::Rand::Get::getranddata( $bytes_to_get, [ 0 .. 9 ] ); my $delay_seconds = $rand_int % $max_delay_seconds; # Should be between 1 and $max_delay_seconds # scheduling a task for 0 seconds will cause queueprocd to throw an error $delay_seconds++; return ( show_status('Scheduling task to check service default SSL/TLS certificates'), sub { Cpanel::ServerTasks::schedule_task( ['SSLTasks'], $delay_seconds, 'checkallsslcerts' ); } ); } sub action_build_locale_databases { return if $ENV{'CPANEL_BASE_INSTALL'}; return ( show_status('Ensuring locale databases are up to date'), sub { Cpanel::ServerTasks::schedule_task( ['LocaleTasks'], 300, "build_locale_databases" ); } ); } sub action_init_wwwacct_conf { return if touch_file_exists('/etc/wwwacct.conf'); return ( show_status('Creating account configuration file /etc/wwwacct.conf'), '/usr/local/cpanel/scripts/mkwwwacctconf', ); } sub action_fixrndc { return if touch_file_exists('/etc/nameddisable') or touch_file_exists('/etc/binddisable'); return if $ENV{'CPANEL_BASE_INSTALL'}; # Base install does this in the background before upcp my $status = 'Checking and repairing nameserver config'; if ( !touch_file_exists( Cpanel::OS::dns_named_basedir() ) ) { return sub { my $named_perms = Cpanel::OS::var_named_permissions(); mkdir( Cpanel::OS::dns_named_basedir(), $named_perms->{'mode'} ); # probably safe to do it earlier and simplify this code return run_action( show_status($status), '/usr/local/cpanel/scripts/fixrndc -f', ); }; } return ( show_status($status), '/usr/local/cpanel/scripts/fixrndc' ); } sub action_ipaliases { return ( show_status('Setting up IP aliases startup'), '/usr/local/cpanel/whostmgr/bin/setupipaliases', ); } sub action_check_cpanel_pkgs { return if $ENV{'CPANEL_BASE_INSTALL'}; return sub { # need RPM_IS_BROKEN to be set my $cpconf = get_cpconf(); if ($RPM_IS_BROKEN) { logger()->error('RPM is not functional. Skipping check_cpanel_pkgs.'); } elsif ( $cpconf->{'maintenance_rpm_version_check'} ) { my $status = 'Checking cPanel packages'; my @rpmcheck_args = (qw{ --list-only --long-list --notify }); my $its_a_weekday = _is_saturday_or_sunday() ? 0 : 1; if ( !$cpconf->{'maintenance_rpm_version_digest_check'} || $ENV{'CPANEL_BASE_INSTALL'} || $its_a_weekday ) { # the user doesn't want a digest check and we're not being forced into it # # In order to minimize server load and reduce install times we only do # a full digest check on the weekends if the user hasn't disabled it. $status .= ' (with no digest check or broken check)'; push @rpmcheck_args, '--no-digest'; push @rpmcheck_args, '--no-broken'; } return run_action( show_status($status), join( ' ', '/usr/local/cpanel/scripts/check_cpanel_pkgs', @rpmcheck_args ), ); } else { logger()->info('Skipping cPanel package check due to configuration'); } return; }; } sub get_auto_remove_plugins { my $auto_remove_plugins = Cpanel::Leika::get_config('plugins.auto-remove-extensions'); if ( $auto_remove_plugins && ref $auto_remove_plugins eq 'HASH' ) { # Filter out any keys with value 0 return [ sort keys(%$auto_remove_plugins) ]; } return []; } sub get_auto_install_plugins { my %default_auto_install_plugins = ( 'cpanel-comet-backup-plugin' => 1, 'cpanel-koality-plugin' => 1, 'cpanel-monitoring-plugin' => 1, 'cpanel-sitejet-plugin' => 1, 'cpanel-socialbee-plugin' => 1, 'cpanel-xovi-plugin' => 1, ); my $auto_install_plugins = Cpanel::Leika::get_config('plugins.auto-install-extensions'); if ( $auto_install_plugins && ref $auto_install_plugins eq 'HASH' ) { my %cmb = ( %default_auto_install_plugins, %$auto_install_plugins ); # cpanel-nova-plugin is installed by the license-gated install_nova # task (scheduled in action_check_plugin_packages), so drop it here to # keep a stale or lingering auto-install-extensions.cpanel-nova-plugin # experiment from installing it through this path. delete $cmb{'cpanel-nova-plugin'}; # Filter out any keys with value 0 return [ sort grep { $cmb{$_} } keys(%cmb) ]; } # For now we will provide the current list if the server # does not have a valid leika config here. return [ sort keys %default_auto_install_plugins ]; } sub action_check_plugin_packages { return sub { # need RPM_IS_BROKEN to be set if ($RPM_IS_BROKEN) { logger()->error('RPM is not functional. Skipping check_plugin_pkgs.'); return; } my @pkgs_to_check = ( 'cpanel-analytics', 'cpanel-banners-plugin', ); # Remove obsolete plugins or plugins clients have requested # we remove from them on a targeted basis. my $auto_remove_plugins = get_auto_remove_plugins(); if (@$auto_remove_plugins) { run_action( show_status('Removing obsolete packages'), sub { require Cpanel::Plugins; foreach my $pkg (@$auto_remove_plugins) { if ( Cpanel::Plugins::is_plugin_installed($pkg) ) { Cpanel::Plugins::uninstall_plugins($pkg); } } }, ); } # Get the list of plugins to install my $auto_install_plugins = get_auto_install_plugins(); # Check if the admin has limited which extensions can be installed. require Cpanel::FeatureFlags; foreach my $plugin (@$auto_install_plugins) { push( @pkgs_to_check, $plugin ) if !Cpanel::FeatureFlags::is_feature_enabled("disable-$plugin"); } # Nova is license-gated, so schedule its own install task here instead # of adding it to the auto-install list above. if ( Cpanel::Server::Type::is_licensed_for_product('nova_op') ) { Cpanel::ServerTasks::schedule_task( ['PluginTasks'], 1, 'install_nova' ); } # Install any missing extension packages. # Note: Packages presence on a server does not mean the features in the extension # are active on the server. Most extensions implement a complex set of rules for # activation inside the RPM/DEB installer for each extension. return run_action( show_status('Checking plugin packages'), join( ' --pkg ', '/usr/local/cpanel/scripts/check_plugin_pkgs', @pkgs_to_check ), ); }; } sub action_ftpquotacheck { return unless Cpanel::Services::Enabled::is_enabled('ftp'); return '/usr/local/cpanel/scripts/ftpquotacheck'; } sub action_repair_mailman { return sub { # postpone it as can binary can be there only once RPM is fixed my $cpconf = get_cpconf(); return unless ( !$cpconf->{'skipmailman'} && file_is_executable("$Cpanel::ConfigFiles::MAILMAN_ROOT/bin/check_perms") ); chdir("$Cpanel::ConfigFiles::MAILMAN_ROOT/bin"); my $ok = run_action( show_status('Repairing Mailman Permissions'), './check_perms -f --noarchives', ); chdir('/usr/local/cpanel'); # return where we should be ? return $ok; }; } sub _mysqld_sh_path { return '/usr/local/etc/rc.d/mysqld.sh' } # for unit test purpose only sub action_repair_mysql { return unless touch_file_exists( _mysqld_sh_path() ); return sub { unlink _mysqld_sh_path(); return run_action( show_status('Repairing MySQL startup'), '/usr/local/cpanel/scripts/restartsrv mysql', ); }; } sub action_purge_modsec { return if $ENV{'CPANEL_BASE_INSTALL'}; return '/usr/local/cpanel/scripts/purge_modsec_log'; } # for unit test purpose only sub _passwd_files_to_chmod { return [ '/etc/shadow.tmpeditlib', '/etc/master.passwd.tmpeditlib' ]; } sub action_passwd { return sub { my $files = _passwd_files_to_chmod(); # Quick security check on the tmpeditlib files in case they are there foreach my $f (@$files) { chmod( 0600, $f ) if touch_file_exists($f); } return; }; } sub action_buildexim { return sub { # postponed if the file is created/touched by one rpm (hook)... to preserve original behavior return if populated_touch_file_exists('/etc/exim.conf') and populated_touch_file_exists('/etc/exim.pl.local'); # run only if one of the file is missing / empty return run_action( show_status('EXIM sanity checking'), '/usr/local/cpanel/scripts/buildeximconf --no_chown_spool', ); }; } sub action_eximstats { return sub { # Eximstats recover of /var/cpanel/sql/eximstats.sql, if it exists return unless touch_file_exists('/var/cpanel/sql/eximstats.sql'); return run_action( show_status('Recovering data stored in /var/cpanel/sql/eximstats.sql'), '/usr/local/cpanel/scripts/restartsrv_eximstats' ); }; } # If eximstats is disabled, we need to handle clearing of old tracker files here. sub action_exim_purge_old_tracker_files { return sub { my $cpconf = get_cpconf(); return unless $cpconf->{'skipeximstats'} && $cpconf->{'skipeximstats'} eq '1'; require Cpanel::EmailTracker::Purge; logger()->info('Purging old email tracker files'); Cpanel::EmailTracker::Purge::purge_old_tracker_files(); return; }; } # If /etc/sysconfig/exim needs to be rewritten, do that. sub action_exim_sysconfig { return sub { my $cp_config = get_cpconf(); if ( defined $cp_config->{'exim-retrytime'} ) { logger()->info('Ensuring Exim startup environment is valid'); Whostmgr::Exim::Sysconfig::update_sysconfig( $cp_config->{'exim-retrytime'} ); } else { logger()->info('No Exim retry time exists in the cPanel configuration file; skipping rebuild of /etc/sysconfig/exim'); } return; }; } sub action_cleanup_signature { return ( show_status('Cleaning Signature Timestamp Cache'), sub { my $sig_cache = Cpanel::Crypt::GPG::VendorKeys::TimestampCache->new(); $sig_cache->cleanup_signature_cache(); return; }, ); } sub action_check_for_long_running_package_locks { return ( show_status('Checking for long-running package manager locks'), sub { my %locks = Cpanel::Pkgr::get_active_locks(); my @long_running_locks; foreach my $lock_file ( keys %locks ) { if ( $locks{$lock_file} > 12 * 60 * 60 ) { # 12 hours push @long_running_locks, $lock_file; } } if (@long_running_locks) { Cpanel::Notify::notification_class( 'class' => 'PackageManager::LongRunningLocks', 'application' => 'PackageManager::LongRunningLocks', 'constructor_args' => [ 'lock_files' => \@long_running_locks, ] ); } return; }, ); } # # local cache configuration to be able to use them { my $conf; # state like variable sub get_update_conf { $conf = { Cpanel::Update::Config::load() } if !defined $conf; return $conf; } sub reset_update_conf { # for testing purpose undef($conf); return; } } # loadcpconf already caches this so we don't need to re-cache it here. *get_cpconf = \&Cpanel::Config::LoadCpConf::loadcpconf; { my $logger; sub setup_logger { my ( $logfile_path, $starting_pbar ) = @_; return $logger = Cpanel::Update::Logger->new( { 'logfile' => $logfile_path, 'stdout' => 1, 'log_level' => 'info', defined $starting_pbar ? ( 'pbar' => $starting_pbar ) : () } ); } sub logger { $logger = setup_logger() unless defined $logger; # mainly for mocking return $logger; } } sub increment_pbar { my ( $start, $end, $items ) = @_; my $_current_ratio = $start; my $_last_update = 0; # do a -1 to the total to leave it to the end my $points = ( $end - $start - 1 ) || 1; $items ||= $points; # number of elements in our array my $w = $points / $items; # default points to increase +1 return sub { my (%opts) = @_; if ( $opts{complete} ) { # we reach the end we can now use the final result $_last_update = $_current_ratio = $end; logger()->update_pbar($end); return; } my $previous = $_current_ratio; $_current_ratio += $w; $_current_ratio = $end if $_current_ratio > $end; my $normalize = int($_current_ratio); # includes a protection to avoid displaying duplicates logger()->update_pbar($normalize); return; } } sub setupenv { Cpanel::Env::clean_env(); delete $ENV{'DOCUMENT_ROOT'}; delete $ENV{'SERVER_SOFTWARE'}; if ( $ENV{'WHM50'} ) { $ENV{'GATEWAY_INTERFACE'} = 'CGI/1.1'; } ( $ENV{'USER'}, $ENV{'HOME'} ) = ( getpwuid($>) )[ 0, 7 ]; $ENV{'PATH'} .= ':/sbin:/usr/sbin:/usr/bin:/bin:/usr/local/bin'; $ENV{'LANG'} = 'C'; $ENV{'LC_ALL'} = 'C'; return; } sub setupcrontab { logger()->info('Setting up cronjobs'); logger()->info('Setting Up update_db_cache Crontab'); logger()->info('Setting Up update_maiman_cache Crontab'); logger()->info('Setting Up dcpumon Crontab'); try { Cpanel::Config::Crontab::sync_root_crontab(); } catch { warn "Failed to sync root crontab: $_"; }; # Set up cron.d entries for short-lived SSL certificate re-issuance try { require Cpanel::SSL::Reissue::Cron; Cpanel::SSL::Reissue::Cron->ensure_that_entry_exists(); } catch { warn "Failed to set up SSL reissue cron: $_"; }; return; } sub clean_roundcube_attachment_directory { my $roundcube_tmp = '/var/cpanel/roundcube/tmp'; opendir my $dh, $roundcube_tmp or return; my @old_files = grep { -M $_ > 7.0 } map { "$roundcube_tmp/$_" } grep { !m/^\.{1,2}$/ } readdir $dh; closedir $dh; my $clean = sub { unlink @old_files }; return Cpanel::AccessIds::do_as_user( 'cpanelroundcube', $clean ); } sub check_mysql_version { # no need to check on first install return if $ENV{'CPANEL_BASE_INSTALL'}; my ( $reco_version, $current_version, $version_is_mysql, $display_name, $err ); try { $current_version = Cpanel::MysqlUtils::Version::current_mysql_version(); } catch { $err = $_; }; if ($err) { logger()->info("Unable to determine MySQL version because of an error: $err. Skipping MySQL version check..."); return; } elsif ( !$current_version->{'short'} ) { logger()->info("Unable to determine MySQL version. Skipping MySQL version check..."); return; } # We check the remote mysql version in Install::CheckRemoteMySQLVersion, # so we'll skip the check here return if $current_version->{'is_remote'}; $current_version = $current_version->{'short'}; $version_is_mysql = Cpanel::MysqlUtils::Version::version_is_mysql(); $display_name = $version_is_mysql ? "MySQL" : "MariaDB"; $reco_version = $version_is_mysql ? $Cpanel::MysqlUtils::Version::MINIMUM_RECOMMENDED_MYSQL_RELEASE : $Cpanel::MysqlUtils::Version::MINIMUM_RECOMMENDED_MARIADB_RELEASE; # if less than the minimum recommended version, recommend an update. if ( Cpanel::MysqlUtils::Version::is_at_least( $current_version, $reco_version ) ) { logger()->info("“$display_name” version “$current_version” is greater than or equal to the recommended minimum version, “$reco_version”."); } else { logger()->info("“$display_name” version “$current_version” is less than the recommended minimum version, “$reco_version”."); my @outdated = (); push @outdated, { 'label' => $display_name, 'current_version' => $current_version, 'min_reco_version' => $reco_version, 'upgrade_url' => 'https://go.cpanel.net/whmdocsUpgradeDBVersion', }; require Cpanel::Notify; Cpanel::Notify::notification_class( 'class' => 'OutdatedSoftware::Notify', 'application' => 'OutdatedSoftware::Notify', 'constructor_args' => [ 'origin' => 'scripts/maintenance', 'outdated_software' => \@outdated, ] ); } return; } sub ensure_active_mysql_profile_is_present { eval { require Cpanel::MysqlUtils::RemoteMySQL::ProfileManager; Cpanel::MysqlUtils::RemoteMySQL::ProfileManager->new()->generate_active_profile_if_none_set(); }; return 1; } ############################################################################# our $upcp_log_dir = '/var/cpanel/updatelogs'; sub purge_upcp_logs { my ($days) = @_; if ( !defined $days ) { my $cpconf = get_cpconf(); $days = $cpconf->{'upcp_log_retention_days'}; } # On initial upgrade, upcp_log_retention_days isn't set yet. We'll enforce the default here. if ( $days < 3 ) { logger()->warning("upcp_log_retention_days unexpectedly set to $days. Temporarily setting to 45 days."); $days = 45; } logger()->info("Purging upcp logs older than $days days."); my $purge_older_than = time - ( 86400 * $days ); opendir( my $dir_fh, $upcp_log_dir ) or do { logger()->warning("Cannot read '$upcp_log_dir' for purging."); }; while ( my $file = readdir($dir_fh) ) { # Special files we don't purge next if ( $file eq '.' or $file eq '..' or $file eq 'summary.log' ); # Skip if the file is new enough. my @stats = lstat("$upcp_log_dir/$file"); next unless ( @stats && $stats[9] < $purge_older_than ); # The file can be removed. unlink "$upcp_log_dir/$file"; } closedir($dir_fh); return; } sub check_addon_licenses { return sub { # Base install does this in the background before upcp if ( !$ENV{'CPANEL_BASE_INSTALL'} ) { # Fire these off in a taskqueue so as not to hold up the rest of the script eval { Cpanel::ServerTasks::queue_task( ['ScriptTasks'], 'run_script /usr/local/cpanel/scripts/litespeed-check --run' ); }; eval { Cpanel::ServerTasks::queue_task( ['ScriptTasks'], 'run_script /usr/local/cpanel/scripts/jetbackup-check --run' ); }; } }; } sub update_public_suffix_list { try { require IO::Socket::SSL::PublicSuffix; IO::Socket::SSL::PublicSuffix::update_self_from_url(); require Cpanel::PublicSuffix; Cpanel::PublicSuffix::clear_cache(); } catch { logger()->info('Unable to update the Pubic Suffix list'); }; return; } sub ensure_els_php_state { return if Cpanel::OS::php_els_is_part_of_the_base_os(); # Since Imunify360 includes hardened PHP from TuxCare, do not # manage ELS PHP state on Imunify360-licensed servers. require Whostmgr::Imunify360; return if Whostmgr::Imunify360::is_imunify360_licensed(); require Whostmgr::Store::Product::PHPELS; if ( Whostmgr::Store::Product::PHPELS->is_product_licensed() ) { if ( !Whostmgr::Store::Product::PHPELS->is_product_installed ) { logger->info("Queuing Install of ELS PHP"); _queue_task_or_warn( ['ScriptTasks'], 'run_script /usr/local/cpanel/scripts/install_tuxcare_els_php' ); return; } } else { if ( Whostmgr::Store::Product::PHPELS->is_product_installed ) { logger->info("Queuing Uninstall of ELS PHP"); _queue_task_or_warn( ['ScriptTasks'], 'run_script /usr/local/cpanel/scripts/install_tuxcare_els_php --delete' ); return; } } return; } sub _queue_task_or_warn { my @queue_task_args = @_; warn if !eval { Cpanel::ServerTasks::queue_task(@queue_task_args); 1; }; return; } sub usage { print <script(@ARGV) || 0 ) if !caller(); 1;