Linux evo.fastest-server.com 5.14.0-284.1101.el9.tuxcare.11.els11.x86_64 #1 SMP PREEMPT_DYNAMIC Fri Aug 14 13:30:35 UTC 2026 x86_64
LiteSpeed
Server IP : 103.249.112.113 & Your IP : 216.73.217.135
Domains : 988 Domain
User : tanishks
Terminal
Auto Root
Create File
Create Folder
Localroot Suggester
Backdoor Destroyer
Readme
/
usr /
share /
l.v.e-manager /
cpanel /
resource_usage /
Delete
Unzip
Name
Size
Permission
Date
Action
plugin
[ DIR ]
drwxr-xr-x
2026-09-04 11:42
LVEInfo.pm
53.14
KB
-rw-r--r--
2026-08-11 11:38
plugin.tar.bz2
1.87
KB
-rw-r--r--
2026-09-25 05:25
resource_usage.live.pl
1.71
KB
-rw-r--r--
2026-08-11 11:38
Save
Rename
package Cpanel::LVEInfo; BEGIN { unshift @INC, '/usr/local/cpanel', '/usr/local/cpanel/whostmgr/docroot/3rdparty/cloudlinux', '/usr/share/l.v.e-manager/cpanel/cgi'; #use CGI::Carp qw(fatalsToBrowser); # for detail comments } # cpanel - Cpanel/LVEInfo.pm Copyright(c) 2011 CloudLinux, Inc. # All Rights Reserved. # info@cloudlinux.com http://www.cloudlinux.com # This module is free software; you can redistribute it and/or modify it under # the same terms as Perl itself. See http://dev.perl.org/licenses/artistic.html # CloudLinux LVE Manager VERSION:0.83 use experimental 'smartmatch'; use JSON::XS; use Cpanel::Math (); use Cpanel::Locale (); use Cpanel::JSON (); use version; use CloudLinux; # safe import Cpanel::StatsBar fo support check syntax by /usr/local/cpanel/3rdparty/bin/perl -cw LVEInfo.pm if ( eval{ require Cpanel::StatsBar; 1; } ) { Cpanel::StatsBar->import() }; my $mark_phrase_module; # On some early cPanel versions, 'Locale::Maketext::Utils::MarkPhrase' does not exist # and 'Cpanel::CPAN::Locale::Maketext::Utils::MarkPhrase' is used instead BEGIN { eval { require Locale::Maketext::Utils::MarkPhrase; Locale::Maketext::Utils::MarkPhrase->import(); $mark_phrase_module = 'Locale::Maketext::Utils::MarkPhrase'; 1; } or do { require Cpanel::CPAN::Locale::Maketext::Utils::MarkPhrase; Cpanel::CPAN::Locale::Maketext::Utils::MarkPhrase->import(); $mark_phrase_module = 'Cpanel::CPAN::Locale::Maketext::Utils::MarkPhrase'; }; } my @lve; my @def; my @quota; my $locale; my $inside_openvz = CloudLinux::safeRun('/usr/bin/cldetect', '--check-openvz'); if ($inside_openvz + 0 ne $inside_openvz) {$inside_openvz = 0}; # $inside_openvz must be a number sub get_cpanel_version{ my $filename = '/usr/local/cpanel/version'; my $version = Cpanel::LoadFile::loadfile($filename); chomp $version; return $version; } my $cpanel_version = get_cpanel_version(); sub max { my $x = shift; my $y = shift; return ( $x > $y ? $x : $y ); } sub version_compare { my $ver1 = shift || 0; my $ver2 = shift || 0; my @v1 = split /[.+:~-]/, $ver1; my @v2 = split /[.+:~-]/, $ver2; for ( my $i = 0 ; $i < max( scalar(@v1), scalar(@v2) ) ; $i++ ) { # Add missing version parts if one string is shorter than the other # i.e. 0 should be lt 0.2.1 and not equal, so we append .0 # -> 0.0.0 <=> 0.2.1 -> -1 push( @v1, 0 ) unless defined( $v1[$i] ); push( @v2, 0 ) unless defined( $v2[$i] ); if ( int( $v1[$i] ) > int( $v2[$i] ) ) { return 1; } elsif ( int( $v1[$i] ) < int( $v2[$i] ) ) { return -1; } } return 0; } sub get_lve_info { my ($id) = @_; @quota = @{ get_quota_info($id) }; if ( open my $fh, '<', '/var/lve/info' ) { while ( my $line = readline $fh ) { chomp $line; my @vals = split( /,/, $line ); if ( $vals[0] == $id ) { close $fh; return @vals; } elsif ( $vals[0] eq '0' ) { @def = @vals; } } close $fh; } return; } sub get_quota_info { my ($id) = @_; my @params = ('/usr/bin/cl-quota', "--user-id=$id", '--csv'); my $rv = CloudLinux::safeRun(@params); my ($header, $data) = split(/\n/, $rv, 2); chomp $data; return [split(/,/, $data)]; } sub api2_getSummary { my %OPTS = @_; $locale ||= Cpanel::Locale->get_handle(); my $inodes = $OPTS{'lveinodes'}; my @fields = qw/id mep lep cpu_usage lcpu mem_usage lmem mem_fault mep_fault lmemphy memphy memphy_fault lnproc nproc nproc_fault lcpuw iousage iolimit liops iops cpuf iopsf iof/; my %data = ( cpu => { t => 'CPU Usage', u => 'cpu_usage', l => 'lcpu', f => 'cpuf' }, mep => { t => 'Entry Processes', u => 'mep', l => 'lep', f => 'mep_fault' }, vmem => { t => 'Virtual Memory Usage', u => 'mem_usage', l => 'lmem', f => 'mem_fault' }, pmem => { t => 'Physical Memory Usage', u => 'memphy', l => 'lmemphy', f => 'memphy_fault' }, nproc => { t => 'Number of Processes', u => 'nproc', l => 'lnproc', f => 'nproc_fault' }, io => { t => 'I/O Usage', u => 'iousage', l => 'iolimit', f => 'iof' }, iops => { t => 'IOPS', u => 'iops', l => 'liops', f => 'iopsf'}, ); if ($inside_openvz) { %data = filter_dict(\%data, 'mep') }; my $normalized_user_cpu = is_normalize_user_cpu(); my $doRoundK = sub { my $v = shift; if ( $v < 1024 ) { return sprintf "%0.2fk", $v; } elsif ( $v >= 1024 and $v < 1048576 ) { return sprintf "%0.2fM", $v / 1024; } else { return sprintf "%0.2fG", $v / 1048576; } }; if ( open my $fh, '<', '/var/lve/info' ) { my %vals = (); while ( my $line = readline $fh ) { chomp $line; my @v = split( /,/, $line ); my $key = $v[0] == 0 ? 'default' : $v[0]; for my $i ( 1 .. $#v ) { $vals{$key}->{ $fields[$i] } = $v[$i]; } } close $fh; my $user = getuid(); if ($inodes) { $data{inodes} = { t => 'inodes usage', u => 'inodesusage', l => 'inodeslimit' }; my @quota = @{ get_quota_info($user) }; for my $key ( keys %vals ) { $vals{$key}->{inodesusage} = $quota[1]; $vals{$key}->{inodeslimit} = $quota[2]; } } my $arref = []; my $keyname = ( defined $user and exists $vals{$user} ) ? $user : 'default'; for my $key ( sort keys %data ) { #next if $vals{$keyname}->{ $data{$key}->{l} } == 0; my $usage = 0; my $limit = 0; if ($key eq 'cpu') { if ($normalized_user_cpu) { $usage = sprintf("%.1f", ( $vals{$keyname}->{ $data{$key}->{u} } * 100 / ( $vals{$keyname}->{ $data{$key}->{l} } || 1 ) ) ).'%'; $limit = '100%'; } else { $usage = sprintf("%.1f", ( $vals{$keyname}->{ $data{$key}->{u} } / 100 ) ).'%'; $limit = ($vals{$keyname}->{ $data{$key}->{l} } / 100).'%'; } } elsif ($key eq 'io') { $usage = sprintf("%.1f", ( $vals{$keyname}->{ $data{$key}->{u} } ) ).' KB/s'; $limit = sprintf("%.1f", ( $vals{$keyname}->{ $data{$key}->{l} } ) ).' KB/s'; } else { $usage = (($key eq 'pmem' or $key eq 'vmem') ? $doRoundK->( $vals{$keyname}->{ $data{$key}->{u} } * 4 ) : $vals{$keyname}->{ $data{$key}->{u} } ); $limit = (($key eq 'pmem' or $key eq 'vmem') ? $doRoundK->( $vals{$keyname}->{ $data{$key}->{l} } * 4 ) : $vals{$keyname}->{ $data{$key}->{l} }); } push @{ $arref }, { title=>$locale->maketext($data{$key}->{t}), usage=>$usage, limit=>$limit, faults=>(exists $data{$key}->{f} ? $vals{$keyname}->{ $data{$key}->{f} } : '-'), } unless $vals{$keyname}->{ $data{$key}->{l} } == 0; } return $arref; } return; } sub LVEInfo_init { my $uid = getuid(); @lve = get_lve_info($uid); Cpanel::StatsBar::_load_stats_ref(); if (has_new_config_value("hideLVEUserStat", "uiSettings")) { return; } $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'module'} = 'LVEInfo'; $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'_count'} = \&Cpanel::LVEInfo::_cpu; $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'_max'} = \&Cpanel::LVEInfo::_cpu_limit; $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'langkey'} = 'CPU Usage'; # $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'_max'} = '100 %'; # $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'units'} = '%'; # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'phrase'} = $mark_phrase_module->can('translatable')->('CPU Usage'); # for cPanel 11.54+ $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'pc'} = percent(_cpu(), _cpu_limit()); $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lvecpu'}{'file'} = "cpu"; if (!_is_mem_unlimited()) { $Cpanel::StatsBar::rSTATS->{'lvemem'}{'_count'} = \&Cpanel::LVEInfo::_mem; $Cpanel::StatsBar::rSTATS->{'lvemem'}{'_max'} = \&Cpanel::LVEInfo::_mem_limit; $Cpanel::StatsBar::rSTATS->{'lvemem'}{'langkey'} = 'Virtual Memory Usage'; $Cpanel::StatsBar::rSTATS->{'lvemem'}{'module'} = 'LVEInfo'; if (version_compare($cpanel_version, '11.57') == 1){ $Cpanel::StatsBar::rSTATS->{'lvemem'}{'units'} = 'MB'; } # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lvemem'}{'phrase'} = $mark_phrase_module->can('translatable')->('Virtual Memory Usage'); # for cPanel 11.54+ $Cpanel::StatsBar::rSTATS->{'lvemem'}{'pc'} = percent(_mem(), _mem_limit()); $Cpanel::StatsBar::rSTATS->{'lvemem'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lvemem'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lvemem'}{'file'} = "mem"; } if (!Cpanel::LVEInfo::_is_pmem_unlimited()) { $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'module'} = 'LVEInfo'; $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'_count'} = \&Cpanel::LVEInfo::_pmem; $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'_max'} = \&Cpanel::LVEInfo::_pmem_limit; $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'langkey'} = 'Physical Memory Usage'; if (version_compare($cpanel_version, '11.57') == 1){ $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'units'} = 'MB'; } # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'phrase'} = $mark_phrase_module->can('translatable')->('Physical Memory Usage'); # for cPanel 11.54+ $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'pc'} = percent(_pmem(), _pmem_limit()); $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lvepmem'}{'file'} = "pmem"; } if (!Cpanel::LVEInfo::_is_mep_unlimited()) { $Cpanel::StatsBar::rSTATS->{'lvemep'}{'module'} = 'LVEInfo'; $Cpanel::StatsBar::rSTATS->{'lvemep'}{'_count'} = \&Cpanel::LVEInfo::_mep; $Cpanel::StatsBar::rSTATS->{'lvemep'}{'_max'} = \&Cpanel::LVEInfo::_mep_limit; $Cpanel::StatsBar::rSTATS->{'lvemep'}{'langkey'} = 'Entry Processes'; # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lvemep'}{'phrase'} = $mark_phrase_module->can('translatable')->('Entry Processes'); # for cPanel 11.54+ $Cpanel::StatsBar::rSTATS->{'lvemep'}{'pc'} = percent(_mep(), _mep_limit()); $Cpanel::StatsBar::rSTATS->{'lvemep'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lvemep'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lvemep'}{'file'} = "mep"; } if (!Cpanel::LVEInfo::_is_iop_unlimited()) { $Cpanel::StatsBar::rSTATS->{'lveiop'}{'module'} = 'LVEInfo'; $Cpanel::StatsBar::rSTATS->{'lveiop'}{'_count'} = \&Cpanel::LVEInfo::_iop; $Cpanel::StatsBar::rSTATS->{'lveiop'}{'_max'} = \&Cpanel::LVEInfo::_iop_limit; $Cpanel::StatsBar::rSTATS->{'lveiop'}{'langkey'} = 'I/O Usage'; # CPANEL use UNITS as a marker for MB and IF units exists - interpretate information as a memory in bytes (ver 11.65\11.66) # so it does not metter what unit here $Cpanel::StatsBar::rSTATS->{'lveiop'}{'units'} = 'KB/s'; # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lveiop'}{'phrase'} = $mark_phrase_module->can('translatable')->('I/O Usage'); # for cPanel 11.54+ # Cpanel does not use this function in version (11.65\11.66) # for percent calculation Cpanel use _count and _max. If there are some strings - percent will be always 0 $Cpanel::StatsBar::rSTATS->{'lveiop'}{'pc'} = percent(_iop(), _iop_limit()); $Cpanel::StatsBar::rSTATS->{'lveiop'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lveiop'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lveiop'}{'file'} = "iop"; } if (!Cpanel::LVEInfo::_is_proc_unlimited()) { $Cpanel::StatsBar::rSTATS->{'lveproc'}{'module'} = 'LVEInfo'; $Cpanel::StatsBar::rSTATS->{'lveproc'}{'_count'} = \&Cpanel::LVEInfo::_proc; $Cpanel::StatsBar::rSTATS->{'lveproc'}{'_max'} = \&Cpanel::LVEInfo::_proc_limit; $Cpanel::StatsBar::rSTATS->{'lveproc'}{'langkey'} = 'Number of Processes'; # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lveproc'}{'phrase'} = $mark_phrase_module->can('translatable')->('Number of Processes'); # for cPanel 11.54+ $Cpanel::StatsBar::rSTATS->{'lveproc'}{'pc'} = percent(_proc(), _proc_limit()); $Cpanel::StatsBar::rSTATS->{'lveproc'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lveproc'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lveproc'}{'file'} = "proc"; } if (!has_config_value("file_usage") && has_new_config_value("showUserInodesUsage", "inodeLimits") && !Cpanel::LVEInfo::_is_quota_unlimited()) { $Cpanel::StatsBar::rSTATS->{'lvequota'}{'module'} = 'LVEInfo'; $Cpanel::StatsBar::rSTATS->{'lvequota'}{'_count'} = \&Cpanel::LVEInfo::_quota; $Cpanel::StatsBar::rSTATS->{'lvequota'}{'_max'} = \&Cpanel::LVEInfo::_quota_limit; $Cpanel::StatsBar::rSTATS->{'lvequota'}{'langkey'} = 'inodes'; # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lvequota'}{'phrase'} = $mark_phrase_module->can('translatable')->('inodes'); # for cPanel 11.54+ $Cpanel::StatsBar::rSTATS->{'lvequota'}{'pc'} = percent(_quota(), _quota_limit()); $Cpanel::StatsBar::rSTATS->{'lvequota'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lvequota'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lvequota'}{'file'} = "quota"; } if (!Cpanel::LVEInfo::_is_iops_unlimited()) { $Cpanel::StatsBar::rSTATS->{'lveiops'}{'module'} = 'LVEInfo'; $Cpanel::StatsBar::rSTATS->{'lveiops'}{'_count'} = \&Cpanel::LVEInfo::_iops; $Cpanel::StatsBar::rSTATS->{'lveiops'}{'_max'} = \&Cpanel::LVEInfo::_iops_limit; $Cpanel::StatsBar::rSTATS->{'lveiops'}{'langkey'} = 'IOPS'; # for cPanel >= 11.46 $Cpanel::StatsBar::rSTATS->{'lveiops'}{'phrase'} = $mark_phrase_module->can('translatable')->('IOPS'); # for cPanel 11.54+ $Cpanel::StatsBar::rSTATS->{'lveiops'}{'pc'} = percent(_iops(), _iops_limit()); $Cpanel::StatsBar::rSTATS->{'lveiops'}{'itemdesc'} = $Cpanel::StatsBar::rSTATS->{'lveiops'}{'phrase'}; $Cpanel::StatsBar::rSTATS->{'lveiops'}{'file'} = "iops"; } } # Format of line in /var/lve/info (formed by lvestats-server): # (id, mep, lep, cpu_usage, lcpu, mem_usage, lmem, # mem_fault, mep_fault, lmemphy, memphy, memphy_fault, # lnproc, nproc, nproc_fault, lcpuw, ioread, iowrite) use constant ID_INDEX => 0; use constant MEP_INDEX => 1; use constant LEP_INDEX => 2; use constant CPU_INDEX => 3; use constant LCPU_INDEX => 4; use constant MEM_INDEX => 5; use constant LMEM_INDEX => 6; use constant MEMF_INDEX => 7; use constant MEPF_INDEX => 8; use constant LPMEM_INDEX => 9; use constant PMEM_INDEX => 10; use constant PMEMF_INDEX => 11; use constant LNPROC_INDEX => 12; use constant NPROC_INDEX => 13; use constant NPROCF_INDEX => 14; use constant LCPUW_INDEX => 15; use constant IOUSAGE_INDEX => 16; use constant IOLIMIT_INDEX => 17; use constant IOPSLIMIT_INDEX => 18; use constant IOPSUSAGE_INDEX => 19; sub convert_mem_for_cpanel_11_57{ my ( $val ) = @_; my $rv = $val * 4 * 1024; return sprintf $rv; } sub _mem { if (version_compare($cpanel_version, '11.57') == 1){ return convert_mem_for_cpanel_11_57($lve[MEM_INDEX]) if (@lve); } return k_to_m($lve[MEM_INDEX] << 2) if (@lve); return 0; } sub round_mem { return RoundMemK( $lve[MEM_INDEX] << 2 ) if (@lve); return 0; } sub LVEInfo_mem { print round_mem(); } sub _mem_limit { if (version_compare($cpanel_version, '11.57') == 1){ return convert_mem_for_cpanel_11_57($lve[LMEM_INDEX]) if (@lve); return convert_mem_for_cpanel_11_57($def[LMEM_INDEX]); } return k_to_m($lve[LMEM_INDEX] << 2).' MB' if (@lve); return k_to_m($def[LMEM_INDEX] << 2).' MB'; } sub _is_mem_unlimited { if (@lve) { return ($lve[LMEM_INDEX] == 0); } if (@def) { return ($def[LMEM_INDEX] == 0); } return 1; } sub round_mem_limit { return RoundMemK( $lve[LMEM_INDEX] << 2 ) if (@lve); return RoundMemK( $def[LMEM_INDEX] << 2 ); } sub LVEInfo_mem_limit { print round_mem_limit(); } sub _cpu { if (is_normalize_user_cpu()) { return (@lve && $lve[LCPU_INDEX] != 0) ? int($lve[CPU_INDEX] / $lve[LCPU_INDEX] * 100) : 0; } else { return int($lve[CPU_INDEX]/100); } } sub LVEInfo_cpu { print _cpu(); } sub _cpu_limit { if (is_normalize_user_cpu()) { if (version_compare($cpanel_version, '11.57') == 1){ return '100'; } return '100%'; } else { if (version_compare($cpanel_version, '11.57') == 1){ return ($lve[LCPU_INDEX] / 100); } return ($lve[LCPU_INDEX] / 100).'%'; } } sub LVEInfo_cpu_limit { print _cpu_limit(); } sub getuid() { my $user = $Cpanel::user; return ( Cpanel::PwCache::getpwnam($user) )[2]; } sub LVEInfo_start { } sub _mep { if (@lve) { return $lve[MEP_INDEX]; } else { return 0; } } sub LVEInfo_mep { print _mep(); } sub _mep_limit { if (@lve) { return $lve[LEP_INDEX]; } else { return $def[LEP_INDEX]; } } sub _is_mep_unlimited { if (@lve) { return ($lve[LEP_INDEX] == 0); } if (@def) { return ($def[LEP_INDEX] == 0); } return 1; } sub LVEInfo_mep_limit { print _mep_limit(); } sub _pmem { if (version_compare($cpanel_version, '11.57') == 1){ return convert_mem_for_cpanel_11_57($lve[PMEM_INDEX]) if (@lve); } return k_to_m($lve[PMEM_INDEX] << 2) if (@lve); return 0; } sub LVEInfo_pmem { print _pmem(); } sub _pmem_limit { if (version_compare($cpanel_version, '11.57') == 1){ return convert_mem_for_cpanel_11_57($lve[LPMEM_INDEX]) if (@lve); return convert_mem_for_cpanel_11_57($def[LPMEM_INDEX]); } return k_to_m($lve[LPMEM_INDEX] << 2).' MB' if (@lve); return k_to_m($def[LPMEM_INDEX] << 2).' MB'; } sub LVEInfo_pmem_limit { print _pmem_limit(); } sub _is_pmem_unlimited { if (@lve) { return ($lve[LPMEM_INDEX] == 0); } if (@def) { return ($def[LPMEM_INDEX] == 0); } return 1; } sub _proc { if (@lve) { return $lve[NPROC_INDEX]; } else { return 0; } } sub LVEInfo_proc { print _proc(); } sub _proc_limit { if (@lve) { return $lve[LNPROC_INDEX]; } else { return $def[LNPROC_INDEX]; } } sub LVEInfo_proc_limit { print _proc_limit(); } sub _is_proc_unlimited { if (@lve) { return ($lve[LNPROC_INDEX] == 0); } if (@def) { return ($def[LNPROC_INDEX] == 0); } return 1; } sub _iops { if (@lve) { return $lve[IOPSUSAGE_INDEX]; } else { return 0; } } sub LVEInfo_iops { print _iops(); } sub _iops_limit { if (@lve) { return $lve[IOPSLIMIT_INDEX]; } else { return $def[IOPSLIMIT_INDEX]; } } sub LVEInfo_iops_limit { print _iops_limit(); } sub _is_iops_unlimited { if (@lve) { return ($lve[IOPSLIMIT_INDEX] == 0); } if (@def) { return ($def[IOPSLIMIT_INDEX] == 0); } return 1; } sub _iop { if (@lve) { return $lve[IOUSAGE_INDEX] << 10; } else { return 0; } } sub LVEInfo_iop { print _iop(); } sub _iop_limit { if (@lve) { return $lve[IOLIMIT_INDEX] << 10; } else { return $def[IOLIMIT_INDEX] << 10; } } sub _is_iop_unlimited { if (@lve) { return ($lve[IOLIMIT_INDEX] == 0); } if (@def) { return ($def[IOLIMIT_INDEX] == 0); } return 1; } sub LVEInfo_iop_limit { print _iop_limit(); } sub _quota { if (@quota) { return $quota[1]; } else { return 0; } } sub LVEInfo_quota { print _quota(); } sub _quota_limit { if (@quota) { return $quota[2]; } else { return 0; } } sub _is_quota_unlimited { return 1 unless @quota; return 1 if $quota[2] == 0; return 0; } sub LVEInfo_quota_limit { print _quota_limit(); } sub isError { my $x = shift; return $x ? 'errors' : 'lveok'; } # Validate a cPanel account name before it is spliced into a selectorctl # command line. cPanel WHM restricts account names to a leading lowercase # letter followed by up to 15 lowercase-alphanumeric characters, so the # `getpwuid($<)` lookup that feeds these api2 handlers will always satisfy # this in a default deployment. Returns the validated name, or undef if the # system passwd database has been hand-edited to contain a name with shell # metacharacters — callers turn an undef into the same empty-list response # the existing check_license() path already returns, so a bad name fails # safe instead of escaping into /bin/sh via the shell-form `open` pipes # below. sub _safe_cpanel_user { my $name = shift; return undef unless defined $name && $name =~ /\A[a-z][a-z0-9]{0,15}\z/; return $name; } sub api2_hideIfNative { my $user = _safe_cpanel_user(scalar getpwuid($<)); return [{state => q##}] unless defined $user; # argv-form list-pipe: /bin/sh never sees $user, so even a passwd-db # entry that slipped a shell metacharacter past _safe_cpanel_user # (regex changes, future cPanel relaxation) is exec'd as a literal # argv element, not parsed by the shell. open my $p, '-|', '/usr/bin/selectorctl', '--user-current', '--interpreter=php', "--user=$user" or return [{state => q##}]; my $raw_string = do { local $/; <$p> }; close $p; return [{state => $raw_string =~ /native/ ? q#style=display:none;# : q##}]; } sub api2_getUsage2 { my %CFG = @_; my @RSD; my %attrs = ( lEP => [ qw/aEP mEP lEP/ ], lVMem => [ qw/aVMem mVMem lVMem/ ], lPMem => [ qw/aPMem mPMem lPMem/ ], lNproc => [ qw/aNproc mNproc lNproc/ ], lIO => [ qw/aIO mIO lIO/ ], lIOPS =>[ qw/aIOPS mIOPS lIOPS/ ], ); my $show_headers_filter = '.*'; if ($inside_openvz) { $show_headers_filter = 'From|To|aEP|mEP|lEP|EPf'; } push @RSD, lvestats_ver(); my $lveid = getuid(); my $period = !exists $CFG{'period'} || $CFG{'period'} eq '' ? '1d' : $CFG{'period'}; my $timeUnit = !exists $CFG{'timeUnit'} || $CFG{'timeUnit'} eq '' ? '1h' : $CFG{'timeUnit'}; # period/timeUnit come from the cPanel api2 query string and are interpolated # into @command, which CloudLinux::safeRun runs via `bash -c "<joined>"` — any # shell metacharacter would be interpreted (command injection in the user's # context, reachable even by no-shell accounts). Constrain to lveinfo's # <number><unit> grammar; fall back to the default for anything else so # legitimate UI requests keep working. $period = '1d' unless $period =~ /^[0-9]+[smhdw]$/; $timeUnit = '1h' unless $timeUnit =~ /^[0-9]+[smhdw]$/; my @command = ( '/usr/sbin/lveinfo', '--csv', '--compat=v2', '--style=user', '--show-all', "--id=$lveid", "--time-unit=$timeUnit"); if(grep {$period eq $_} qw(7d 30d)){ $endTimestamp = time(); $startTimestamp = $endTimestamp - 86400 * $period; my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($startTimestamp); $year += 1900; $mon += 1; $startDate = "$year-$mon-$mday 00:00"; my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($endTimestamp); $year += 1900; $mon += 1; $endDate = "$year-$mon-$mday 23:59"; push @command, ( '--from', "$startDate", '--to', "$endDate" ); } else { push @command, ( "--period=$period" ); } my $INPUT = CloudLinux::safeRun( @command ); my @results = split( /\n+/, $INPUT ); my @header = split( /,/, shift @results); $header[$#header] =~ s/^\s+//; $header[$#header] =~ s/\s+$//; return if !@results; # return undef if there has been no activity my @show_column_index = grep { $header[$_] =~ /$show_headers_filter/ } 0..$#header; my @header_filtered = map {$header[$_]} @show_column_index; my %limits = ( lEP => 0, lVMem => 0, lPMem => 0, lNproc => 0, lIO => 0, lIOPS => 0 ); for my $i (@results) { my @data = split( /,/, $i ); $data[0] =~ s/\s/ /; $data[1] =~ s/\s/ /; my %struct = map { $header[$_] => ( $header[$_] =~ /(?:a|m)(?:v|p)mem/i ? sprintf("%0.2f",$data[$_]/1048576) : $header[$_] =~ /l(?:v|p)mem/i ? sprintf("%d",$data[$_]/1048576) : $data[$_] ) } @show_column_index; for my $k ( keys %limits ) { $limits{$k} += $struct{$k}; } push @RSD, \%struct; } my @limits_keys = keys %limits; for my $i ( @RSD ) { for my $k ( @limits_keys ) { if ( $limits{$k} == 0 ) { for my $j ( @{ $attrs{$k} } ) { delete $i->{$j}; } } } } return \@RSD; } sub api2_getUsage { my %CFG = @_; my @RSD; my $show_columns_v1 = "From To aCPU mCPU lCPU aEP mEP lEP aVMem mVMem lVMem VMemF EPf aPMem mPMem lPMem aNproc mNproc lNproc PMemF NprocF aIO mIO lIO aIOPS mIOPS lIOPS"; my $show_columns_v2 = "From,To,aCPU,mCPU,lCPU,aEP,mEP,lEP,aVMem,mVMem,lVMem,VMemF,EPf,aPMem,mPMem,lPMem,aNproc,mNproc,lNproc,PMemF,NprocF,aIO,mIO,lIO,aIOPS,mIOPS,lIOPS,CPUf,IOf"; my $lveid = getuid(); my $period = !exists $CFG{'period'} || $CFG{'period'} eq '' ? '1d' : $CFG{'period'}; # See api2_getUsage2: period is interpolated into a CloudLinux::safeRun # `bash -c` command. Constrain to lveinfo's <number><unit> grammar. $period = '1d' unless $period =~ /^[0-9]+[smhdw]$/; my @command = ( '/usr/sbin/lveinfo', '--csv', "--period=$period", "--id=$lveid", "--style=user" ); if ( lvestats_ver() > 1 ) { push @command, ("--compat=v2" , "--limit=0", "--show-columns=".$show_columns_v2); } my $INPUT = CloudLinux::safeRun( @command ); my @results = split( /\n+/, $INPUT ); shift @results; foreach my $i (@results) { my ( $from, $to, $acpu, $mcpu, $lcpu, $aep, $mep, $lep, $aMem, $mMem, $lMem, $memf, $mepf, $aPmem, $mPmem, $lPmem, $aNproc, $mNproc, $lNproc, $pmemf, $nprocf, $aIO, $mIO, $lIO, $aIOPS, $mIOPS, $lIOPS, $cpuf, $IOf ) = split( /,/, $i ); my ( $apcpu, $mpcpu ) = ( 0, 0 ); $lcpu = 100 if ( $lcpu == 0 ); $apcpu = Cpanel::Math::ceil( $acpu * 100 / $lcpu ); $mpcpu = Cpanel::Math::ceil( $mcpu * 100 / $lcpu ); my $stack = { 'from' => $from, 'to' => $to, 'acpu' => $acpu, 'mcpu' => $mcpu, 'lcpu' => $lcpu, 'aep' => $aep, 'mep' => $mep, 'lep' => $lep, 'aMem' => $aMem, 'mMem' => $mMem, 'lMem' => $lMem, 'aPMem' => $aPmem, 'mPMem' => $mPmem, 'lPMem' => $lPmem, 'aNproc' => $aNproc, 'mNproc' => $mNproc, 'lNproc' => $lNproc, 'aIO' => $aIO, 'mIO' => $mIO, 'lIO' => $lIO, 'cpuf' => $cpuf, 'memf' => $memf, 'pmemf' => $pmemf, 'mepf' => $mepf, 'nprocf' => $nprocf, 'IOf' => $IOf, 'aIOPS' => $aIOPS, 'mIOPS' => $mIOPS, 'lIOPS' => $lIOPS, 'apcpu' => $apcpu, 'mpcpu' => $mpcpu, 'aMemStr' => RoundMemB($aMem), 'mMemStr' => RoundMemB($mMem), 'lMemStr' => RoundMemB($lMem), 'eapcpu' => isError( $apcpu > 75 ), 'empcpu' => isError( $mpcpu > 90 ), 'eaep' => isError( ( $lep > 0 ) && ( $aep * 2 > $lep ) ), 'emep' => isError( ( $lep > 0 ) && ( $mep > $lep * .9 ) ), 'eaMem' => isError( ( $lMem > 0 ) && ( $aMem * 2 > $lMem ) ), 'emMem' => isError( ( $lMem > 0 ) && ( $mMem > $lMem * .9 ) ), 'ememf' => isError( $memf > 0 ), 'emepf' => isError( $mepf > 0 ) }; # filtering the data actual for OpenVZ if ($inside_openvz) { $stack = filter_dict($stack, 'from|to|aep|mep|lep|mepf|pmemf|eaep|emep|emepf'); } unshift(@RSD, $stack); } return \@RSD; } sub api2 { my ($func) = @_; my %API = ( 'getUsage' => { 'func' => 'api2_getUsage', 'engine' => 'hasharray', }, 'getUsage2' => { 'func' => 'api2_getUsage2', 'engine' => 'hasharray', }, getSummary => { 'func' => 'api2_getSummary', 'engine'=> 'hasharray', }, processPHPVersionSelect => { 'func' => 'api2_processPHPVersionSelect', 'engine'=> 'hasharray', }, showPHPExtTable => { 'func' => 'api2_showPHPExtTable', 'engine'=> 'hasharray', }, showPHPOptTable => { 'func' => 'api2_showPHPOptTable', 'engine'=> 'hasharray', }, hideIfNative => { 'func' => 'api2_hideIfNative', 'engine'=> 'hasharray', }, rubySelector => { 'func' => 'api2_rubySelector', 'engine'=> 'hasharray', }, pythonSelector => { 'func' => 'api2_pythonSelector', 'engine'=> 'hasharray', }, getRubyInterpreters => { 'func' => 'api2_getRubyInterpreters', 'engine'=> 'hasharray', }, isRubyEnabled => { 'func' => "api2_isRubyEnabled", 'engine' => 'hasharray', }, getPythonInterpreters => { 'func' => 'api2_getPythonInterpreters', 'engine'=> 'hasharray', }, getLvemanagerVersion => { 'func' => 'api2_getLvemanagerVersion', 'engine'=> 'hasharray', }, getHomeDir => { 'func' => 'api2_getHomeDir', 'engine'=> 'hasharray', }, ); return \%{ $API{$func} }; } sub get_user_domain { my $path = shift; my $user = getpwuid($<); my $full_path = qq#$path/users/$user#; my $dns; return unless -e $full_path; open my $f, '<', $full_path or return; while (my $line = <$f>) { if ($line =~ /^DNS\s?=\s?(\S*)/) { $dns = $1; last; } } close $f; return $dns; } sub api2_getRubyInterpreters { my %opts = @_; my @params = ('/usr/bin/selectorctl', '--interpreter', 'ruby', '--list', '--json'); my $rv = CloudLinux::safeRun(@params); #return [map +{version=>$_}, keys %{Cpanel::JSON::Load($rv)}]; my %data = %{Cpanel::JSON::Load($rv)}; return $data{status} eq 'OK' ? [map +{version=>$_}, sort {$b cmp $a} keys %{$data{data}}] : []; } sub api2_isRubyEnabled { return not has_new_config_value('hideRubyApp', 'uiSettings'); } sub api2_getLvemanagerVersion { return CloudLinux::safeRun('cat', '/usr/share/l.v.e-manager/version'); } sub api2_getPythonInterpreters { my %opts = @_; my @params = ('/usr/bin/selectorctl', '--interpreter', 'python', '--list', '--json'); my $rv = CloudLinux::safeRun(@params); my %data = %{Cpanel::JSON::Load($rv)}; return $data{status} eq 'OK' ? [map +{version=>$_}, sort keys %{$data{data}}] : []; } sub api2_rubySelector { my %opts = @_; my $user = getpwuid($<); my $versions = api2_getRubyInterpreters(); my @params = ('/usr/bin/selectorctl', '--interpreter', 'ruby', '--user', $user, '--user-summary', '--json'); my $rv = CloudLinux::safeRun(@params); my $process = sub { my $data = shift; my $rv = []; if (exists $data->{status} and $data->{status} eq 'ERROR') { return [{status=>'ERROR', message=>$data->{message}}]; } elsif (exists $data->{status} and $data->{status} eq 'OK') { for my $k ( keys %{ $data->{data} } ) { my $domain = get_user_domain('/var/cpanel'); $data->{data}->{$k}->{domain} = substr($domain, -1) ne '/' ? $domain . '/' : $domain unless exists $data->{data}->{$k}->{domain}; push @{ $rv }, {name=>$k, data=>$data->{data}->{$k}, versions=>$versions}; } } return $rv; }; return $process->(Cpanel::JSON::Load($rv)); } sub api2_pythonSelector { my %opts = @_; my $user = getpwuid($<); my $versions = api2_getPythonInterpreters(); my @params = ('/usr/bin/selectorctl', '--interpreter', 'python', '--user', $user, '--user-summary', '--json'); my $rv = CloudLinux::safeRun(@params); my $process = sub { my $data = shift; my $rv = []; if (exists $data->{status} and $data->{status} eq 'ERROR') { return [{status=>'ERROR', message=>$data->{message}}]; } elsif (exists $data->{status} and $data->{status} eq 'OK') { for my $k ( keys %{ $data->{data} } ) { my $domain = get_user_domain('/var/cpanel'); $data->{data}->{$k}->{domain} = substr($domain, -1) ne '/' ? $domain . '/' : $domain unless exists $data->{data}->{$k}->{domain}; push @{ $rv }, {name=>$k, data=>$data->{data}->{$k}, versions=>$versions}; } } return $rv; }; return $process->(Cpanel::JSON::Load($rv)); } sub api2_processPHPVersionSelect { $locale ||= Cpanel::Locale->get_handle(); # returns alternatives state for a user # and applies alternatives selection if # the form is submitted unless (check_license()) { return [ { errmsg => $locale->maketext('PHP Selector disabled, please contact hoster') } ] } # get parameters from calling side my %opts = @_; # check correct php version if (exists $opts{lveversion} && $opts{lveversion} !~ m/(^(\d\.\d)?( \(.*\))?$)|(^native \(\d\.\d\)$)/ ) { $data = { errmsg => "ERROR: php version is incorrect" }; my $native = get_native_version(); $data->{native} = $native if $native ne q{}; return [ $data ]; }; # get current user name my $user = _safe_cpanel_user(scalar getpwuid($<)); return [ { errmsg => "ERROR: invalid user" } ] unless defined $user; # Build the selectorctl argv. argv-form spawn means /bin/sh never sees # $user or $version, so this code path no longer depends on # strip_version()/the lveversion regex above to keep shell metacharacters # out of the call. Default branch displays summary; the form-submit # branch applies a version + prints summary. my @cmd = ('/usr/bin/selectorctl', '--user-summary', '--interpreter=php', "--user=$user", '--show-native-version'); if ( $opts{lveversion} and $opts{lveversion} ne 'none' ) { my $version = strip_version($opts{lveversion}); @cmd = ('/usr/bin/selectorctl', '--interpreter=php', "--set-user-current=$version", "--user=$user", '--print-summary', '--show-native-version'); } # Spawn argv-form and merge child stderr into the captured stdout so the # downstream `index($raw_string, 'ERROR')` / `WARN` parser still sees the # same diagnostic text the original `qq#... 2>&1|#` pipe surfaced; the # merge is done in the child via dup2 of STDERR -> STDOUT, *not* via # /bin/sh, so no shell quoting is involved. my $raw_string = q{}; my $pid = open my $p, '-|'; if (!defined $pid) { return [ { errmsg => "ERROR: cannot spawn selectorctl" } ]; } elsif ($pid == 0) { open STDERR, '>&', \*STDOUT; exec { $cmd[0] } @cmd; exit 127; } $raw_string = do { local $/; <$p> }; close $p; my @options; # if returned string starts with 'ERROR', something wrong has happened # Strip 'ERROR' word and send error string to be displayed if ( index( $raw_string, 'ERROR' ) >= 0 ) { $raw_string =~ s/^.*ERROR:(.*?)\n/$1/s; $data = { errmsg => $raw_string }; my $native = get_native_version(); $data->{native} = $native if $native ne q{}; return [ $data ]; } elsif ( $raw_string =~ s/WARN:(.*?)\n// ) { push @options, { warnmsg => $1 }; } # if no error then parse returned string into array of arrays my @raw_options = map { [ split(/\s+/,$_,5) ] } split( /\n/, $raw_string ); # data is returned in the following form for entry: 'version e d s' # 'e' stands for enabled, 'd' for default and 's' for selected. # opposite value is marked with a hyphen ('-') # process already structured data taking into account # if entry is marked as 'selected' or 'disabled' for my $i ( @raw_options ) { my $ver = $i->[0]; my $state = $i->[1] ne 'e' ? q#disabled# : $i->[3] eq 's' ? q#selected# : '' ; my $name_modifier = $i->[4]; # and save'em in array push @options, { state=>$state, ver=>$ver, name_modifier=>$name_modifier }; } return \@options; } # Safely load JSON output from a subprocess; returns the parsed Perl # structure on success, or undef on any parse failure. Used by the # api2_showPHP*Table handlers below to avoid eval'ing subprocess output # (finding [24] — defense-in-depth against selectorctl format drift). sub _safe_json_load { my $r; eval { $r = Cpanel::JSON::Load(shift) }; return $r } sub api2_showPHPExtTable { # returns extension table unless (check_license()) { return [] } # get current user my $user = _safe_cpanel_user(scalar getpwuid($<)); return [] unless defined $user; # argv-form spawn replaces the shell-form `open ... qq#... 2>&1|#` # pipe (finding F-81 — defense-in-depth against a passwd-db username # carrying shell metacharacters). stderr is dup'd to stdout in the # child to preserve the original 2>&1 semantic the ERROR/WARN parser # below depends on, without involving /bin/sh. my $raw_string = q{}; my $pid = open my $p, '-|'; if (!defined $pid) { return []; } elsif ($pid == 0) { open STDERR, '>&', \*STDOUT; exec '/usr/bin/selectorctl', '--list-user-extensions', '--interpreter=php', "--user=$user", '--all'; exit 127; } $raw_string = do { local $/; <$p> }; close $p; # if returned string starts with 'ERROR', something wrong has happened # We are not about to show anything if error if ( index( $raw_string, 'ERROR' ) == 0 or index( $raw_string, 'WARN' ) == 0) { return []; } # Switched from `eval` of `--perl` output to `Cpanel::JSON::Load` of # `--json` output (finding [24] — eliminates Perl code-exec gadget # if the cl-phpextdesc text source ever contains untrusted bytes). # cl-phpextdesc --json and --perl produce identically-shaped data # ([{title:..., description:...}, ...]), so downstream map unchanged. my $data = _safe_json_load(scalar `/usr/bin/cl-phpextdesc --json`); $data = [] unless ref $data eq 'ARRAY'; my %data_desc = map { $_->{title} => $_->{description} } @{ $data }; # if no error then parse returned string into array of hashes my @ext = sort { $a->{title} cmp $b->{title} } map { my ( $s, $n ) = split; { title => $n, state => ( $s eq '+' ? 1 : 0 ), desc => ( $data_desc{$n} || q{} ) }; } split( /\n/, $raw_string ); return \@ext; } sub api2_showPHPOptTable { # returns options table unless (check_license()) { return [] } # get current user my $user = _safe_cpanel_user(scalar getpwuid($<)); return [] unless defined $user; # open pipe for command and grab output to string # Switched from `eval` of `--perl` to `Cpanel::JSON::Load` of `--json` # (finding [24] — eliminates Perl code-exec gadget on selectorctl # format drift). The two CLI flags emit different schemas: # --perl: [{title=>name, key=>val, ...}, ...] # --json: {"status":"OK", "data": {name: {key: val, ...}}} # Reshape the JSON form back to the array-of-records shape the api2 # 'hasharray' engine expects (same transform pattern used by # api2_pythonSelector above). # argv-form list-pipe replaces the backtick command so /bin/sh never # sees $user (same class-of-bug fix as the showPHPExtTable handler). my $raw_json = q{}; if (open my $sp, '-|', '/usr/bin/selectorctl', '--print-options-safe', "--user=$user", '--json') { $raw_json = do { local $/; <$sp> }; close $sp; } my $parsed = _safe_json_load($raw_json); return [] unless ref $parsed eq 'HASH' && exists $parsed->{status} && $parsed->{status} eq 'OK' && ref $parsed->{data} eq 'HASH'; # Per-entry hashref guard. `%{ $parsed->{data}->{$_} }` dies at # runtime if any value in $parsed->{data} is not a hashref (scalar, # undef, arrayref, ...). Filter via grep so a selectorctl format # drift downgrades to "fewer rows returned" rather than "api2 # handler dies and the whole table errors out" — matches the # fail-safe spirit of the pre-fix `return $data` code, which also # returned whatever the subprocess emitted without claiming # per-element validity. return [ map +{ title => $_, %{ $parsed->{data}->{$_} } }, grep { ref $parsed->{data}->{$_} eq 'HASH' } sort keys %{ $parsed->{data} } ]; } sub api2_snapshot_list { return []; } sub api2_snapshot_one { return []; } sub api2_getHomeDir { my @data = getpwuid($<); return $data[7]; } sub LVEInfo_PHPExtDesc { # print titles for extensions (for javascript) open my $p,qq#/usr/bin/cl-phpextdesc --json|#; print do { local $/; <$p>; }; close $p; } sub get_usage_info { my $res = api2_getUsage2( 'period' => '1d' ); shift @$res; # remove version number in first element return $res; } sub check_license { my @params = ('/usr/bin/cldetect', '--check-license'); my $result = CloudLinux::safeRun(@params); chomp $result; if ($result eq 'OK') { return 1; } return 0; } sub LVEInfo_print_usage_overview { $locale ||= Cpanel::Locale->get_handle(); unless (check_license()) { print '<strong>'.$locale->maketext('Resource Usage monitoring disabled, please contact hoster').'</strong>'; return; } my $usage = get_usage_info(); my $snapshot_link; my $lvestats_ver_ = lvestats_ver(); if ( $lvestats_ver_ > 1 ) { $snapshot_link = q# or <a href="snapshots/index.html">[#.$locale->maketext('Snapshots').q#]</a>#; } unless (@$usage) { print '<h3>'.$locale->maketext('There has been no activity on your site within the past 24 hours').'</h3><br/>'; print q#<p><a href="resourceusagedetails.html">[#.$locale->maketext('Details').q#]</a>#.$snapshot_link.q#</p>#; return; } my $cpu_limited_flag = 0; my $io_limited_flag = 0; my $iops_limited_flag = 0; my $cpuf_total = 0; my $memf_total = 0; my $mepf_total = 0; my $iof_total = 0; my $iopsf_total = 0; my $cpu_max = 0; my $mem_max = 0; my $lmem_max = 0; my $ep_max = 0; my $lep_max = 0; my $pmem_max = 0; my $lpmem_max = 0; my $pmemf_total = 0; my $nproc_max = 0; my $lnproc_max = 0; my $nprocf_total = 0; my $iousage_max = 0; my $iolimit_max = 0; my $iopsusage_max = 0; my $iopslimit_max = 0; foreach my $hash (@$usage) { # use this algorithm detecting limits overflow for old lvestats $cpu_limited_flag = 1 if ( $lvestats_ver_ <= 1 ) && ( $hash->{'mCPU'} >= $hash->{'lCPU'} ); $io_limited_flag = 1 if ( $lvestats_ver_ <= 1 ) && ( $hash->{'lIO'} && $hash->{'mIO'} >= $hash->{'lIO'} ); $iops_limited_flag = 1 if ( $lvestats_ver_ <= 1 ) && ( $hash->{'lIOPS'} && $hash->{'mIOPS'} >= $hash->{'lIOPS'} ); $cpuf_total += $hash->{'CPUf'}; $memf_total += $hash->{'VMemF'}; $mepf_total += $hash->{'EPf'}; $pmemf_total += $hash->{'PMemF'}; $nprocf_total += $hash->{'NprocF'}; $iof_total += $hash->{'IOf'}; $iopsf_total += $hash->{'IOPSf'}; $cpu_max = $hash->{'mCPU' } if ( $hash->{'mCPU' } > $cpu_max ); $mem_max = $hash->{'mVMem' } if ( $hash->{'mVMem' } > $mem_max ); $lmem_max = $hash->{'lVMem' } if ( $hash->{'lVMem' } > $lmem_max ); $ep_max = $hash->{'mEP' } if ( $hash->{'mEP' } > $ep_max ); $lep_max = $hash->{'lEP' } if ( $hash->{'lEP' } > $lep_max ); $lpmem_max = $hash->{'lPMem' } if ( $hash->{'lPMem' } > $lpmem_max ); $pmem_max = $hash->{'mPMem' } if ( $hash->{'mPMem' } > $pmem_max ); $nproc_max = $hash->{'mNproc'} if ( $hash->{'mNproc'} > $nproc_max ); $lnproc_max = $hash->{'lNproc'} if ( $hash->{'lNproc'} > $lnproc_max ); $iousage_max = $hash->{'mIO'} if ( $hash->{'mIO'} > $iousage_max ); $iolimit_max = $hash->{'lIO'} if ( $hash->{'lIO'} > $iolimit_max ); $iopsusage_max = $hash->{'mIOPS'} if ( $hash->{'mIOPS'} > $iopsusage_max ); $iopslimit_max = $hash->{'lIOPS'} if ( $hash->{'lIOPS'} > $iopslimit_max ); } if ( ($cpu_limited_flag || $cpuf_total) || ( $memf_total > 0 ) || ( $pmemf_total > 0 ) || ( $mepf_total > 0 ) || ( $nprocf_total > 0 ) || ($io_limited_flag || $iof_total > 0) || ($iops_limited_flag || $iopsf_total > 0) ) { print '<h3>'.$locale->maketext('Your site has been limited within the past 24 hours').'</h3>'; if ($cpu_limited_flag || $cpuf_total) { print '<p>'.$locale->maketext('CPU resources were limited for your site'); } if ( $memf_total > 0 ) { print '<p>'.$locale->maketext('Virtual memory resources were limited for your site'); } if ( $pmemf_total > 0 ) { print '<p>'.$locale->maketext('Physical memory resources were limited for your site'); } if ( $mepf_total > 0 ) { print '<p>'.$locale->maketext('You have reached entry processes (number of simultaneously running php and cgi scripts, as well as cron jobs and shell sessions) limit <b>[_1]</b> times', $mepf_total); } if ( $nprocf_total > 0 ) { print '<p>'.$locale->maketext('You have reached processes number limit <b>[_1]</b> times', $nprocf_total); } if ( $io_limited_flag || $iof_total > 0 ) { print '<p>'.$locale->maketext('I/O usage resources were limited for your site'); } if ( $iops_limited_flag || $iopsf_total > 0 ) { print '<p>'.$locale->maketext('I/O operations per second were limited for your site'); } } else { print '<h3>'.$locale->maketext('Your site had no issues in the past 24 hours').'</h3>'; } my $cpu_warn = (!$cpu_limited_flag) && ($cpu_max > 90) && !$cpuf_total; my $mem_warn = ( $memf_total == 0 ) && ( $lmem_max > 0 ) && ( $mem_max > $lmem_max * 0.9 ); my $pmem_warn = ( $pmemf_total == 0 ) && ( $lpmem_max > 0 ) && ( $pmem_max > $lpmem_max * 0.9 ); my $mep_warn = ( $mepf_total == 0 ) && ( $lep_max > 0 ) && ( $ep_max > $lep_max * 0.9 ); my $nproc_warn = ( $nprocf_total == 0 ) && ( $lnproc_max > 0 ) && ( $nproc_max > $lnproc_max * 0.9 ); my $io_warn = ( $iolimit_max > 0 ) && (!$io_limited_flag) && ( $iousage_max > $iolimit_max * 0.9 ) && !$iof_total ; my $iops_warn = ( $iopslimit_max > 0 ) && (!$iops_limited_flag) && ( $iopsusage_max > $iopslimit_max * 0.9 ) && !$iopsf_total ; if ( $cpu_warn || $mem_warn || $pmem_warn || $mep_warn || $nproc_warn || $io_warn || $iops_warn) { print '<p><h3>'.$locale->maketext('Your site might hit resource limits soon').'</h3>'; if ( $cpu_warn ) { print '<p>'.$locale->maketext('Your CPU usage was at [_1]% out of 100%', $cpu_max); } if ( $mem_warn ) { print '<p>'.$locale->maketext('Your Virtual Memory usage was at [_1] out of [_2]', RoundMemB($mem_max), RoundMemB($lmem_max)); } if ( $pmem_warn ) { print '<p>'.$locale->maketext('Your Physical Memory usage was at [_1] out of [_2]', RoundMemB($pmem_max), $lpmem_max); } if ( $mep_warn ) { print '<p>'.$locale->maketext('You had [_1] entry processes (number of simultaneously running php and cgi scripts, as well as cron jobs and shell sessions) out of [_2] max entry processes allowed', $ep_max, $lep_max); } if ( $nproc_warn ) { print '<p>'.$locale->maketext('You had [_1] processes out of [_2] max processes allowed', $nproc_max, $lnproc_max); } if ( $io_warn ) { print '<p>'.$locale->maketext('You had [_1] I/O usage out of [_2] max I/O usage allowed', $iousage_max, $iolimit_max); } if ( $iops_warn ) { print '<p>'.$locale->maketext('You had [_1] I/O operations per second out of [_2] max I/O operations per second allowed', $iopsusage_max, $iopslimit_max); } } if ( $lvestats_ver_ > 1 ) { $snapshot_link = q# #.$locale->maketext('or').q# <a href="snapshots/index.html">[#.$locale->maketext('Snapshots').q#]</a>#; } print q#<p><a href="resourceusagedetails.html">[#.$locale->maketext('Details').q#]</a>#.$snapshot_link.q#</p>#; } # Function converts bytes to kilobytes, megabytes or gigabytes (if needed) # and appends appropriate suffix (K, M, G) # Parameter $_[1] = memory in bytes sub RoundMemB { my $mem = shift; if ( $mem >= ( 1024 * 1024 * 1024 ) ) { return sprintf( "%.1fG", $mem / ( 1024 * 1024 * 1024 ) ); } if ( $mem >= 1024 * 1024 ) { return sprintf( "%.1fM", $mem / ( 1024 * 1024 ) ); } if ( $mem >= 1024 ) { return sprintf( "%.0fK", $mem / 1024 ); } return "$mem"; } # Function converts kilobytes to megabytes or gigabytes (if needed) # and appends appropriate suffix (K, M, G) # Parameter $_[1] = memory in kilobytes sub RoundMemK { my $mem = shift; if ( $mem >= ( 1024 * 1024 ) ) { return sprintf( "%.1fG", $mem / ( 1024 * 1024 ) ); } if ( $mem >= 1024 ) { return sprintf( "%.1fM", $mem / 1024 ); } return "$mem" . 'K'; } # check sub has_config_value { my ($key) = @_; return 0 if !$key; my $cpanel_config = '/var/cpanel/cpanel.config'; return 0 if ! -e $cpanel_config; # precompile regexp for efficiency my $key_pattern = qr/^$key\s*=\s*1\s*$/; my $enabled = 0; open my $f, '<', $cpanel_config or return 0; while (my $line = <$f>) { if ($line =~ /$key_pattern/) { $enabled = 1; last; } } close $f; return $enabled; } # check new config file sub has_new_config_value { my ($key, $parent_key) = (@_); return 0 if !$key or !$parent_key; my $json; my $status = 0; if (open my $fh, "<", "/usr/share/l.v.e-manager/lvemanager-config.json") { $json = <$fh>; $status = JSON::XS::decode_json($json)->{'ui_config'}->{$parent_key}->{$key}; } return $status; } sub k_to_m { my ( $val ) = @_; my $rv = $val / 1024; my $fmt = ($rv == int $rv) ? "%d" : "%.1f"; return sprintf $fmt, $rv; } sub get_native_version { my $version = q{}; my $open_string = qq#/usr/bin/selectorctl --show-native-version|#; eval { open $p, $open_string; $version = do { local $/; <$p>; }; chomp $version; close $p; }; return $version if $version =~ /\d\.\d+/; return q{}; } sub strip_version { # stripts parens part e.g. '(5.3)' from version string my ($version) = @_; my $pos = index($version, '('); return $version if $pos == -1; return substr($version, 0, $pos); } # function to filter dict per keys, using regexp sub filter_dict { my ( $dict_rel, $regexp ) = @_; my %dict = %$dict_rel; return map {$_=>$dict{$_}} (grep {$_ =~ /$regexp/} keys %dict) } # return integer lvestats version sub lvestats_ver { if (-e '/usr/sbin/lve-read-snapshot') { return 2 }; return 1 } sub is_normalize_user_cpu { # by default - TRUE open CONFIG_FILE, '</etc/sysconfig/cloudlinux' || return 1; while (<CONFIG_FILE>) { chomp; if (/normalized_user_cpu[ ]*=[ ]*(Y|N)/is) { return (uc($1) eq 'Y') ? 1 : 0; } } return 1; } sub percent { my ($value, $max) = @_; $value = int($value); $max = int($max); return ($max == 0 ? 0 : int($value / $max * 100)); } 1;