From 78eb57f55c68855f1d6369df6db48b872d0d55f0 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 10 Nov 2024 21:07:33 +0200 Subject: [PATCH 01/11] Fix to print nicer alerts --- bandwidth/index.cgi | 13 ++++++++----- bandwidth/lang/en | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bandwidth/index.cgi b/bandwidth/index.cgi index 04278e1ce..07fb71ea5 100755 --- a/bandwidth/index.cgi +++ b/bandwidth/index.cgi @@ -84,18 +84,21 @@ else { if (($missingrule || !$sysconf) && $access{'setup'}) { # Something is missing .. offer to set up - print "$text{'index_setupdesc'}\n"; if ($missingrule && !$sysconf) { - print $text{'index_missing3'}; + print &ui_alert_box($text{'index_missing3'}, 'success', + undef, undef, ''); } elsif ($missingrule) { - print $text{'index_missing2'}; + print &ui_alert_box($text{'index_missing2'}, 'success', + undef, undef, ''); } elsif (!$sysconf) { - print $text{'index_missing1'}; + print &ui_alert_box($text{'index_missing1'}, 'success', + undef, undef, ''); } + print &ui_alert_box($text{'index_setupdesc'}, 'info', undef, undef, ''); + print &ui_alert_box($text{'index_setupdesc2'}, 'warn'); print "

\n"; - print "$text{'index_setupdesc2'}

\n"; if ($iptableserr) { print $iptableserr,"

\n"; } diff --git a/bandwidth/lang/en b/bandwidth/lang/en index caced9afe..8a5b3d550 100644 --- a/bandwidth/lang/en +++ b/bandwidth/lang/en @@ -8,7 +8,7 @@ index_esyslog=Neither of the System Logs modules are installed on this system an index_firesys=Using $1 firewall and $2 index_setupcannot=However, you do not have permissions to set it up! index_setupdesc=Before this module can report on network usage on your system, it must be set up to monitor traffic on the selected external network interface. -index_setupdesc2=Warning - this module will log ALL network traffic sent or received on the selected interface. This will consume a large amount of disk space and CPU time on a fast network connection. +index_setupdesc2=This module will log all network traffic sent or received on the selected interface, which can consume a large amount of disk space and CPU time on a fast network connection. index_missing3=Several firewall rules must be added, and a syslog configuration entry created. index_missing2=Several firewall rules must be added. index_missing1=A syslog configuration entry must be created. From f152dafc3fefcd770454636b9f4d20b210b808db Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 10 Nov 2024 21:33:29 +0200 Subject: [PATCH 02/11] Fix to consider filter form only of hours been generated --- bandwidth/index.cgi | 444 +++++++++++++++++++++++--------------------- 1 file changed, 232 insertions(+), 212 deletions(-) diff --git a/bandwidth/index.cgi b/bandwidth/index.cgi index 07fb71ea5..06d833b4a 100755 --- a/bandwidth/index.cgi +++ b/bandwidth/index.cgi @@ -103,7 +103,7 @@ if (($missingrule || !$sysconf) && $access{'setup'}) { print $iptableserr,"

\n"; } print &ui_form_start("setup.cgi"); - print "$text{'index_iface'}\n"; + print "$text{'index_iface'}\n"; foreach $i (&net::active_interfaces(), &net::boot_interfaces()) { push(@ifaces, $i->{'fullname'}) if ($i->{'virtual'} eq '' && $i->{'fullname'}); @@ -168,222 +168,242 @@ if (@hours) { print &ui_table_end(); print &ui_form_end([ [ undef, $text{'index_search'} ] ]); + + # Find and show any results + if ($in{'by'}) { + print "

\n"; + # Work out the time range, if any + &error_setup($text{'index_err'}); + $fhour = &parse_hour("from"); + $thour = &parse_hour("to"); + + # First find traffic that matches the 'for' part + if ($in{'for'} eq 'host') { + if ($in{'what'} =~ /^(\d+)\.(\d+)\.(\d+)\.0$/) { + %forhost = map { ("$1.$2.$3.$_", 1) } (0 .. 255); + } + else { + $forhost = &to_ipaddress($in{'what'}); + $forhost || &error($text{'index_ehost'}); + $forhost{$forhost}++; + } + } + elsif ($in{'for'} eq 'proto') { + $forproto = uc($in{'what'}); + $forproto || &error($text{'index_eproto'}); + } + elsif ($in{'for'} eq 'iport' || $in{'for'} eq 'oport') { + if ($in{'what'} =~ /^\d+$/) { + $forportmin = $forportmax = $in{'what'}; + } + elsif ($in{'what'} =~ /^(\d+)\-(\d+)$/) { + $forportmin = $1; + $forportmax = $2; + } + else { + $forportmin = getservbyname($in{'what'}, 'tcp'); + $forportmin ||= getservbyname($in{'what'}, 'udp'); + $forportmin || &error($text{'index_eport'}); + $forportmax = $forportmin; + } + } + foreach $h (@hours) { + next if ($fhour && $h < $fhour); + next if ($thour && $h > $thour); + $hour = &get_hour($h); + + # Work out start time for this day + @tm = localtime($h*60*60); + $thisday = timelocal(0, 0, 0, $tm[3], $tm[4], $tm[5])/(60*60); + + # Scan all traffic for the hour + foreach $k (keys %$hour) { + # Skip this count if not relevant + ($host, $proto, $iport, $oport) = split(/_/, $k); + next if (!$proto); + next if (%forhost && !$forhost{$host}); + next if ($forproto && $proto ne $forproto); + next if ($in{'for'} eq 'iport' && + ($iport < $forportmin || + $iport >$forportmax)); + next if ($in{'for'} eq 'oport' && + ($oport < $forportmin || + $oport >$forportmax)); + + # Skip this count if classifying by port and there + # isn't one + next if ($in{'by'} eq 'iport' && !$iport || + $in{'by'} eq 'oport' && !$oport || + $in{'by'} eq 'port' && !$iport && !$oport); + + # Work out a nice service name + local ($nsname, $nsoname, $nsiname); + local $relport; + if ($in{'by'} eq 'iport') { + $nsname = $nsiname = + getservbyport($iport, lc($proto)); + } + elsif ($in{'by'} eq 'oport') { + $nsname = $nsoname = + getservbyport($oport, lc($proto)); + } + elsif ($in{'by'} eq 'port') { + $nsoname = getservbyport($oport, + lc($proto)); + $nsiname = getservbyport($iport, + lc($proto)); + $nsname = $nsoname || $nsiname; + } + + # Resolv the hostname + local $resolved; + if ($in{'resolv'} && $in{'by'} eq 'host') { + $resolved = &to_hostname($host); + } + + # Skip traffic to high ports, if requested + next if ($in{'low'} && $in{'by'} eq 'iport' && + $iport >= 1024 && !$nsname); + next if ($in{'low'} && $in{'by'} eq 'oport' && + $oport >= 1024 && !$nsname); + + # Update the relevant category + ($in, $out) = split(/ /, $hour->{$k}); + if ($in{'by'} eq 'hour') { + $count{$h} += $in+$out; + $icount{$h} += $in; + $ocount{$h} += $out; + } + elsif ($in{'by'} eq 'day') { + $count{$thisday} += $in+$out; + $icount{$thisday} += $in; + $ocount{$thisday} += $out; + } + elsif ($in{'by'} eq 'host') { + $count{$resolved || $host} += $in+$out; + $icount{$resolved || $host} += $in; + $ocount{$resolved || $host} += $out; + } + elsif ($in{'by'} eq 'proto') { + $count{$proto} += $in+$out; + $icount{$proto} += $in; + $ocount{$proto} += $out; + } + elsif ($in{'by'} eq 'iport') { + $count{$nsname || "$proto $iport"} += + $in+$out; + $icount{$nsname || "$proto $iport"} += + $in; + $ocount{$nsname || "$proto $iport"} += + $out; + } + elsif ($in{'by'} eq 'oport') { + $count{$nsname || "$proto $oport"} += + $in+$out; + $icount{$nsname || "$proto $oport"} += + $in; + $ocount{$nsname || "$proto $oport"} += + $out; + } + elsif ($in{'by'} eq 'port') { + if (!$in{'low'} || $oport < 1024 || + $nsoname) { + $count{$nsoname || + "$proto $oport"} += $in; + $icount{$nsoname || + "$proto $oport"} += $in; + } + if (!$in{'low'} || $iport < 1024 || + $nsiname) { + $count{$nsiname || + "$proto $iport"} += $out; + $ocount{$nsiname || + "$proto $iport"} += $out; + } + } + } + } + + # Find max and size + $max = 0; + foreach $k (keys %count) { + if ($count{$k} > $max) { + $max = $count{$k}; + } + } + $width = 500; + + # Fill in missing hours or days + if ($in{'by'} eq 'hour' || $in{'by'} eq 'day') { + @order = sort { $b <=> $a } keys %count; + $inc = $in{'by'} eq 'hour' ? 1 : 24; + $plus = $in{'by'} eq 'hour' ? 0 : 1; + for($i=$order[0]; $i>=$order[$#order]; $i-=$inc) { + $count{$i} = 0 if (!$count{$i} && + !$count{$i+$plus} && !$count{$i-$plus}); + } + } + + # Show graph + if ($in{'by'} eq 'hour' || $in{'by'} eq 'day') { + @order = sort { $b <=> $a } keys %count; + } + else { + @order = sort { $count{$b} <=> $count{$a} } keys %count; + } + if ($in{'by'} ne 'hour' && $in{'by'} ne 'day') { + @order = grep { $count{$_} } @order; + } + if (@order) { + print &ui_columns_start([ $text{'index_h'.$in{'by'}}, + $text{'index_usage'}, + $text{'index_in'}, + $text{'index_out'}, + $text{'index_total'} ], 100, 0); + $itotal = $ototal = $total = 0; + foreach $k (@order) { + my @cols; + if ($in{'by'} eq 'hour') { + push(@cols, &make_date($k*60*60)); + } + elsif ($in{'by'} eq 'day') { + $date = &make_date_day($k*60*60); + push(@cols, $date); + } + else { + push(@cols, $k); + } + my $bar = sprintf + "", + $max ? int($width * $icount{$k}/$max)+1 : 1; + $bar .= sprintf + "", + $max ? int($width * $ocount{$k}/$max)+1 : 1; + push(@cols, $bar); + push(@cols, &nice_size($icount{$k}), + &nice_size($ocount{$k}), + &nice_size($count{$k})); + $total += $count{$k}; + $itotal += $icount{$k}; + $ototal += $ocount{$k}; + print "\n"; + print &ui_columns_row(\@cols); + } + print &ui_columns_row([ undef, undef, + &nice_size($itotal), + &nice_size($ototal), + &nice_size($total) ]); + print &ui_columns_end(); + } + else { + print "$text{'index_nomatch'}

\n"; + } + } } elsif (!$missingrule && $sysconf) { print "$text{'index_none'}

\n"; } -# Find and show any results -if ($in{'by'}) { - # Work out the time range, if any - &error_setup($text{'index_err'}); - $fhour = &parse_hour("from"); - $thour = &parse_hour("to"); - - # First find traffic that matches the 'for' part - if ($in{'for'} eq 'host') { - if ($in{'what'} =~ /^(\d+)\.(\d+)\.(\d+)\.0$/) { - %forhost = map { ("$1.$2.$3.$_", 1) } (0 .. 255); - } - else { - $forhost = &to_ipaddress($in{'what'}); - $forhost || &error($text{'index_ehost'}); - $forhost{$forhost}++; - } - } - elsif ($in{'for'} eq 'proto') { - $forproto = uc($in{'what'}); - $forproto || &error($text{'index_eproto'}); - } - elsif ($in{'for'} eq 'iport' || $in{'for'} eq 'oport') { - if ($in{'what'} =~ /^\d+$/) { - $forportmin = $forportmax = $in{'what'}; - } - elsif ($in{'what'} =~ /^(\d+)\-(\d+)$/) { - $forportmin = $1; - $forportmax = $2; - } - else { - $forportmin = getservbyname($in{'what'}, 'tcp'); - $forportmin ||= getservbyname($in{'what'}, 'udp'); - $forportmin || &error($text{'index_eport'}); - $forportmax = $forportmin; - } - } - foreach $h (@hours) { - next if ($fhour && $h < $fhour); - next if ($thour && $h > $thour); - $hour = &get_hour($h); - - # Work out start time for this day - @tm = localtime($h*60*60); - $thisday = timelocal(0, 0, 0, $tm[3], $tm[4], $tm[5])/(60*60); - - # Scan all traffic for the hour - foreach $k (keys %$hour) { - # Skip this count if not relevant - ($host, $proto, $iport, $oport) = split(/_/, $k); - next if (!$proto); - next if (%forhost && !$forhost{$host}); - next if ($forproto && $proto ne $forproto); - next if ($in{'for'} eq 'iport' && - ($iport < $forportmin || $iport >$forportmax)); - next if ($in{'for'} eq 'oport' && - ($oport < $forportmin || $oport >$forportmax)); - - # Skip this count if classifying by port and there - # isn't one - next if ($in{'by'} eq 'iport' && !$iport || - $in{'by'} eq 'oport' && !$oport || - $in{'by'} eq 'port' && !$iport && !$oport); - - # Work out a nice service name - local ($nsname, $nsoname, $nsiname); - local $relport; - if ($in{'by'} eq 'iport') { - $nsname = $nsiname = getservbyport($iport, lc($proto)); - } - elsif ($in{'by'} eq 'oport') { - $nsname = $nsoname = getservbyport($oport, lc($proto)); - } - elsif ($in{'by'} eq 'port') { - $nsoname = getservbyport($oport, lc($proto)); - $nsiname = getservbyport($iport, lc($proto)); - $nsname = $nsoname || $nsiname; - } - - # Resolv the hostname - local $resolved; - if ($in{'resolv'} && $in{'by'} eq 'host') { - $resolved = &to_hostname($host); - } - - # Skip traffic to high ports, if requested - next if ($in{'low'} && $in{'by'} eq 'iport' && - $iport >= 1024 && !$nsname); - next if ($in{'low'} && $in{'by'} eq 'oport' && - $oport >= 1024 && !$nsname); - - # Update the relevant category - ($in, $out) = split(/ /, $hour->{$k}); - if ($in{'by'} eq 'hour') { - $count{$h} += $in+$out; - $icount{$h} += $in; - $ocount{$h} += $out; - } - elsif ($in{'by'} eq 'day') { - $count{$thisday} += $in+$out; - $icount{$thisday} += $in; - $ocount{$thisday} += $out; - } - elsif ($in{'by'} eq 'host') { - $count{$resolved || $host} += $in+$out; - $icount{$resolved || $host} += $in; - $ocount{$resolved || $host} += $out; - } - elsif ($in{'by'} eq 'proto') { - $count{$proto} += $in+$out; - $icount{$proto} += $in; - $ocount{$proto} += $out; - } - elsif ($in{'by'} eq 'iport') { - $count{$nsname || "$proto $iport"} += $in+$out; - $icount{$nsname || "$proto $iport"} += $in; - $ocount{$nsname || "$proto $iport"} += $out; - } - elsif ($in{'by'} eq 'oport') { - $count{$nsname || "$proto $oport"} += $in+$out; - $icount{$nsname || "$proto $oport"} += $in; - $ocount{$nsname || "$proto $oport"} += $out; - } - elsif ($in{'by'} eq 'port') { - if (!$in{'low'} || $oport < 1024 || $nsoname) { - $count{$nsoname || "$proto $oport"} += $in; - $icount{$nsoname || "$proto $oport"} += $in; - } - if (!$in{'low'} || $iport < 1024 || $nsiname) { - $count{$nsiname || "$proto $iport"} += $out; - $ocount{$nsiname || "$proto $iport"} += $out; - } - } - } - } - - # Find max and size - $max = 0; - foreach $k (keys %count) { - if ($count{$k} > $max) { - $max = $count{$k}; - } - } - $width = 500; - - # Fill in missing hours or days - if ($in{'by'} eq 'hour' || $in{'by'} eq 'day') { - @order = sort { $b <=> $a } keys %count; - $inc = $in{'by'} eq 'hour' ? 1 : 24; - $plus = $in{'by'} eq 'hour' ? 0 : 1; - for($i=$order[0]; $i>=$order[$#order]; $i-=$inc) { - $count{$i} = 0 if (!$count{$i} && - !$count{$i+$plus} && !$count{$i-$plus}); - } - } - - # Show graph - if ($in{'by'} eq 'hour' || $in{'by'} eq 'day') { - @order = sort { $b <=> $a } keys %count; - } - else { - @order = sort { $count{$b} <=> $count{$a} } keys %count; - } - if ($in{'by'} ne 'hour' && $in{'by'} ne 'day') { - @order = grep { $count{$_} } @order; - } - if (@order) { - print &ui_columns_start([ $text{'index_h'.$in{'by'}}, - $text{'index_usage'}, - $text{'index_in'}, - $text{'index_out'}, - $text{'index_total'} ], 100, 0); - $itotal = $ototal = $total = 0; - foreach $k (@order) { - my @cols; - if ($in{'by'} eq 'hour') { - push(@cols, &make_date($k*60*60)); - } - elsif ($in{'by'} eq 'day') { - $date = &make_date_day($k*60*60); - push(@cols, $date); - } - else { - push(@cols, $k); - } - my $bar = sprintf - "", - $max ? int($width * $icount{$k}/$max)+1 : 1; - $bar .= sprintf - "", - $max ? int($width * $ocount{$k}/$max)+1 : 1; - push(@cols, $bar); - push(@cols, &nice_size($icount{$k}), - &nice_size($ocount{$k}), - &nice_size($count{$k})); - $total += $count{$k}; - $itotal += $icount{$k}; - $ototal += $ocount{$k}; - print "\n"; - print &ui_columns_row(\@cols); - } - print &ui_columns_row([ undef, undef, - &nice_size($itotal), - &nice_size($ototal), - &nice_size($total) ]); - print &ui_columns_end(); - } - else { - print "$text{'index_nomatch'}

\n"; - } -} if (!$missingrule && $sysconf) { print &ui_hr(); From 5dbefb1d42febe07d2f66b155e00aefcd0bcd82c Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 10 Nov 2024 21:35:07 +0200 Subject: [PATCH 03/11] Fix to clarify language --- bandwidth/lang/en | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bandwidth/lang/en b/bandwidth/lang/en index 8a5b3d550..c7dfc4a49 100644 --- a/bandwidth/lang/en +++ b/bandwidth/lang/en @@ -7,12 +7,12 @@ index_emod=The Webmin module $1 is not installed on this system or is not suppor index_esyslog=Neither of the System Logs modules are installed on this system and supported by your OS. The Bandwidth Monitoring module cannot operate without one of them. index_firesys=Using $1 firewall and $2 index_setupcannot=However, you do not have permissions to set it up! -index_setupdesc=Before this module can report on network usage on your system, it must be set up to monitor traffic on the selected external network interface. +index_setupdesc=Before this module can report network usage, it needs to be set up to monitor traffic on the chosen network interface. index_setupdesc2=This module will log all network traffic sent or received on the selected interface, which can consume a large amount of disk space and CPU time on a fast network connection. index_missing3=Several firewall rules must be added, and a syslog configuration entry created. index_missing2=Several firewall rules must be added. index_missing1=A syslog configuration entry must be created. -index_iface=External network interface +index_iface=Chosen network interface index_other=Other.. index_setup=Setup Now index_by=Show traffic by @@ -22,7 +22,7 @@ index_proto=protocol index_iport=internal port index_oport=external port index_port=port -index_for=for +index_for=Filter by index_all=<everything> index_forhour=hour.. index_forhost=host.. From e7d8f7271a77caecd0d41e66854feb5b67ee3cd3 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Sun, 10 Nov 2024 22:19:00 +0200 Subject: [PATCH 04/11] Fix to use the same terminology and colors we use in dashboard --- bandwidth/index.cgi | 4 ++-- bandwidth/lang/en | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bandwidth/index.cgi b/bandwidth/index.cgi index 06d833b4a..4b46b5710 100755 --- a/bandwidth/index.cgi +++ b/bandwidth/index.cgi @@ -374,10 +374,10 @@ if (@hours) { push(@cols, $k); } my $bar = sprintf - "", + "", $max ? int($width * $icount{$k}/$max)+1 : 1; $bar .= sprintf - "", + "", $max ? int($width * $ocount{$k}/$max)+1 : 1; push(@cols, $bar); push(@cols, &nice_size($icount{$k}), diff --git a/bandwidth/lang/en b/bandwidth/lang/en index c7dfc4a49..285b2b2cb 100644 --- a/bandwidth/lang/en +++ b/bandwidth/lang/en @@ -40,9 +40,9 @@ index_to=For traffic before index_efrom=Invalid starting date and time index_eto=Invalid ending date and time index_err=Failed to generate report -index_usage=Network traffic downloaded and uploaded -index_in=Download -index_out=Upload +index_usage=Network traffic In and Out +index_in=In +index_out=Out index_total=Total index_hhour=Hour index_hhost=Host From 950122068d2666de8222bc6f491c6d590bb5f882 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 11 Nov 2024 16:09:43 +0200 Subject: [PATCH 05/11] Fix to support new `brand_string` in macOS #2311 --- proc/macos-lib.pl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/proc/macos-lib.pl b/proc/macos-lib.pl index 8839763fd..8f5e1a7ed 100755 --- a/proc/macos-lib.pl +++ b/proc/macos-lib.pl @@ -163,9 +163,16 @@ if ($out =~ /:\s*(\S.*)/) { } } -$out = &backquote_command("sysctl -a machdep.cpu.vendor"); -if ($out =~ /:\s*(\S.*)/) { - $rv[5] = $1; +$out = &backquote_command("sysctl -n machdep.cpu.brand_string"); +if (!$?) { + chomp($out); + $rv[5] = $out; + } +else { + $out = &backquote_command("sysctl -a machdep.cpu.vendor"); + if ($out =~ /:\s*(\S.*)/) { + $rv[5] = $1; + } } $out = &backquote_command("sysctl -a machdep.cpu.cache.size"); From c7a709c8379760e65a4a29e007d7c999057e029a Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Mon, 11 Nov 2024 23:48:18 +0200 Subject: [PATCH 06/11] Add support for displaying CPU and disk data on the latest macOS #2311 --- mount/macos-lib.pl | 35 +++++++++++++++++++++++++++++- mount/mount-lib.pl | 5 +++++ proc/macos-lib.pl | 19 ++++++++++++++++ system-status/system-status-lib.pl | 2 +- 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/mount/macos-lib.pl b/mount/macos-lib.pl index 506773230..45d2fc192 100755 --- a/mount/macos-lib.pl +++ b/mount/macos-lib.pl @@ -2,6 +2,8 @@ # Mount table functions for OSX # Only options for currently mounted filesystems are supported at the moment. +use POSIX; + # list_mounted() # Return a list of all the currently mounted filesystems and swap files. # The list is in the form: @@ -16,7 +18,38 @@ sub list_mounted local(@rv, $_); local $arch = &backquote_command("uname -m"); local $cmd; -if ($arch =~ /power/) { +if ($arch =~ /arm64/) { + my $expand_flags = sub { + my ($flags_str) = @_; + my @flags; + push(@flags, "ro") if ($flags_str =~ /\bread-only\b/); + push(@flags, "noexec") if ($flags_str =~ /\bnoexec\b/); + push(@flags, "nosuid") if ($flags_str =~ /\bnosuid\b/); + push(@flags, "nodev") if ($flags_str =~ /\bnodev\b/); + push(@flags, "sync") if ($flags_str =~ /\bsynchronous\b/); + push(@flags, "async") if ($flags_str =~ /\basynchronous\b/); + push(@flags, "quota") if ($flags_str =~ /\bquota\b/); + push(@flags, "union") if ($flags_str =~ /\bunion\b/); + return @flags ? join(",", @flags) : "-"; + }; + open(CMD, "mount |") || return @rv; + while () { + chomp; + # Parse the mount line output + if ($_ =~ /^(.+?) on (.+?) \((.+?)\)$/) { + my ($device, $mount_point, $type_and_flags) = + ($1, $2, $3); + my ($fstype, $flags_str) = + split(/, /, $type_and_flags, 2); + my $flags = $expand_flags->($flags_str); + push(@rv, [$mount_point, $device, $fstype, + "$flags, $flags_str"]); + } + } + close(CMD); + return @rv; + } +elsif ($arch =~ /power/) { $cmd = "macos-mounts"; &compile_program($cmd, '.*power.*'); } diff --git a/mount/mount-lib.pl b/mount/mount-lib.pl index d715a8c4f..8fb382e67 100755 --- a/mount/mount-lib.pl +++ b/mount/mount-lib.pl @@ -322,6 +322,7 @@ foreach my $m (@mounted) { $m->[2] eq "reiserfs" || $m->[2] eq "ufs" || $m->[2] eq "f2fs" || $m->[2] eq "zfs" || $m->[2] eq "simfs" || $m->[2] eq "vzfs" || $m->[2] eq "xfs" || $m->[2] eq "jfs" || $m->[2] eq "btrfs" || + $m->[2] eq "apfs" || $m->[1] =~ /^\/dev\// || &indexof($m->[1], @$always) >= 0) { my $zp; @@ -358,6 +359,10 @@ foreach my $m (@mounted) { # Skip CDs next; } + # apfs count only physical devices not containers shares + if ($m->[2] eq "apfs" && $m->[3] =~ /nobrowse/) { + next; + } # Get the size - for ZFS mounts, this comes from the underlying # total pool size and free my ($t, $f); diff --git a/proc/macos-lib.pl b/proc/macos-lib.pl index 8f5e1a7ed..cf7dda1f8 100755 --- a/proc/macos-lib.pl +++ b/proc/macos-lib.pl @@ -188,5 +188,24 @@ if ($out =~ /:\s*(\d+)/) { return @rv; } +# get_cpu_io_usage() +# Returns a list containing CPU user, system, and idle time +sub get_cpu_io_usage +{ +my ($user_time, $system_time, $idle_time); +my $out = &backquote_command("iostat -K 1 2 2>/dev/null"); +if (!$?) { + my @lines = split(/\r?\n/, $out); + my @last_line = split(/\s+/, $lines[$#lines]); + shift(@last_line) if ($last_line[0] eq ''); + if (@last_line >= 6) { + $user_time = $last_line[3]; # us + $system_time = $last_line[4]; # sy + $idle_time = $last_line[5]; # id + } + } +return ($user_time, $system_time, $idle_time, 0, 0); +} + 1; diff --git a/system-status/system-status-lib.pl b/system-status/system-status-lib.pl index 8baddba06..19bc5bb86 100755 --- a/system-status/system-status-lib.pl +++ b/system-status/system-status-lib.pl @@ -56,7 +56,7 @@ if (&foreign_check("proc")) { } # Disk space on local filesystems -if (&foreign_check("mount")) { +if (&foreign_check("mount", 1)) { &foreign_require("mount"); ($info->{'disk_total'}, $info->{'disk_free'}, $info->{'disk_fs'}, $info->{'disk_used'}) = From 1c991f9635c83534618b7a85a5f81df2488f7f8e Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 12 Nov 2024 01:05:19 +0200 Subject: [PATCH 07/11] Add check if some IOs related functions supported --- proc/freebsd-lib.pl | 14 ++++++++++++++ proc/linux-lib.pl | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/proc/freebsd-lib.pl b/proc/freebsd-lib.pl index 2d1f052b1..861006892 100755 --- a/proc/freebsd-lib.pl +++ b/proc/freebsd-lib.pl @@ -189,5 +189,19 @@ if (!$?) { return ( $w[-3], $w[-2], $w[-1], 0, 0, $bi, $bo ); } +# has_disk_stats() +# Returns 1 if disk I/O stats are available +sub has_disk_stats +{ +return &has_command("iostat") ? 1 : 0; +} + +# has_network_stats() +# Returns 1 if network I/O stats are available +sub has_network_stats +{ +return &has_command("netstat") ? 1 : 0; +} + 1; diff --git a/proc/linux-lib.pl b/proc/linux-lib.pl index f8855d1a0..97e333aa4 100755 --- a/proc/linux-lib.pl +++ b/proc/linux-lib.pl @@ -716,5 +716,19 @@ if (&has_command("vmstat")) { return undef; } +# has_disk_stats() +# Returns 1 if disk I/O stats are available +sub has_disk_stats +{ +return 1; +} + +# has_network_stats() +# Returns 1 if network I/O stats are available +sub has_network_stats +{ +return 1; +} + 1; From 1fb332ff051869875104b2627427885c8092efee Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 12 Nov 2024 01:48:26 +0200 Subject: [PATCH 08/11] Fix to support network I/O on macOS --- proc/macos-lib.pl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/proc/macos-lib.pl b/proc/macos-lib.pl index cf7dda1f8..f0abfc29c 100755 --- a/proc/macos-lib.pl +++ b/proc/macos-lib.pl @@ -207,5 +207,12 @@ if (!$?) { return ($user_time, $system_time, $idle_time, 0, 0); } +# has_network_stats() +# Returns 1 if network I/O stats are available +sub has_network_stats +{ +return &has_command("netstat") ? 1 : 0; +} + 1; From 816328b643bca44ae67bbaccc8797b9ebcae0b95 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 12 Nov 2024 03:51:47 +0200 Subject: [PATCH 09/11] Add an attempt to get disk IOs https://github.com/webmin/webmin/issues/2311#issuecomment-2469338370 [build] --- proc/macos-lib.pl | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/proc/macos-lib.pl b/proc/macos-lib.pl index f0abfc29c..f98102f37 100755 --- a/proc/macos-lib.pl +++ b/proc/macos-lib.pl @@ -194,6 +194,7 @@ sub get_cpu_io_usage { my ($user_time, $system_time, $idle_time); my $out = &backquote_command("iostat -K 1 2 2>/dev/null"); +# Get CPU usage if (!$?) { my @lines = split(/\r?\n/, $out); my @last_line = split(/\s+/, $lines[$#lines]); @@ -204,7 +205,36 @@ if (!$?) { $idle_time = $last_line[5]; # id } } -return ($user_time, $system_time, $idle_time, 0, 0); +# Get disk I/O +my ($bi, $bo) = (0, 0); +my $io_out = &backquote_command("fs_usage -w -f diskio -t 1 2>&1"); +if (!$?) { + my ($read_bytes, $write_bytes) = (0, 0); + foreach my $line (split(/\n/, $io_out)) { + # For writes: B=0x100000 means 1MB (1048576 bytes) + if ($line =~ /(?:WrData|WrMeta).*?B=0x([0-9a-f]+)/) { + my $bytes = hex($1); + $write_bytes += $bytes; + } + # For reads + elsif ($line =~ /(?:RdData|RdMeta).*?B=0x([0-9a-f]+)/) { + my $bytes = hex($1); + $read_bytes += $bytes; + } + } + + # Convert to KB/s + $bi = int($read_bytes / 1024); + $bo = int($write_bytes / 1024); + } +return ($user_time, $system_time, $idle_time, 0, 0, $bi, $bo); +} + +# has_disk_stats() +# Returns 1 if disk I/O stats are available +sub has_disk_stats +{ +return &has_command("fs_usage") ? 1 : 0; } # has_network_stats() From 54a72c5025fce8bca65c52fd8f5ae54e6709e7a3 Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 12 Nov 2024 03:56:19 +0200 Subject: [PATCH 10/11] Fix comment --- proc/macos-lib.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proc/macos-lib.pl b/proc/macos-lib.pl index f98102f37..c82af026a 100755 --- a/proc/macos-lib.pl +++ b/proc/macos-lib.pl @@ -189,7 +189,8 @@ return @rv; } # get_cpu_io_usage() -# Returns a list containing CPU user, system, and idle time +# Returns a list containing CPU user, system, and idle time, and disk read and +# write KB/s sub get_cpu_io_usage { my ($user_time, $system_time, $idle_time); From 591dda719990064d68c1782cd36238f83be0f00e Mon Sep 17 00:00:00 2001 From: Ilia Ross Date: Tue, 12 Nov 2024 04:05:37 +0200 Subject: [PATCH 11/11] Fix to remove deprecated call [build] --- proc/macos-lib.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proc/macos-lib.pl b/proc/macos-lib.pl index c82af026a..9d42df0df 100755 --- a/proc/macos-lib.pl +++ b/proc/macos-lib.pl @@ -175,7 +175,7 @@ else { } } -$out = &backquote_command("sysctl -a machdep.cpu.cache.size"); +$out = &backquote_command("sysctl hw.l1dcachesize"); if ($out =~ /:\s*(\d+)/) { $rv[6] = $1 * 1024; }