diff options
| author | 2021-12-14 22:01:01 -0500 | |
|---|---|---|
| committer | 2021-12-14 22:01:01 -0500 | |
| commit | ad23217950d54d653851fd37f4b924e883acee1d (patch) | |
| tree | 048596a83c6f26466c784f8090648957ede539f5 /inxi | |
| parent | 19c5b6157eba9a68ae9e5fc37ae40892404c7d54 (diff) | |
New upstream version 3.3.10-1.upstream/3.3.10-1
Diffstat (limited to 'inxi')
| -rwxr-xr-x | inxi | 5033 |
1 files changed, 3106 insertions, 1927 deletions
@@ -30,6 +30,7 @@ use 5.008; use Cwd qw(abs_path); # #abs_path realpath getcwd use Data::Dumper qw(Dumper); # print_r +$Data::Dumper::Sortkeys = 1; # NOTE: load in SystemDebugger unless encounter issues with require/import # use File::Find; use File::stat; # needed for Xorg.0.log file mtime comparisons @@ -46,11 +47,10 @@ use POSIX qw(ceil uname strftime ttyname); ## INXI INFO ## my $self_name='inxi'; -my $self_version='3.3.07'; -my $self_date='2021-10-11'; +my $self_version='3.3.10'; +my $self_date='2021-12-13'; my $self_patch='00'; ## END INXI INFO ## - my ($b_pledge,@pledges); if (eval {require OpenBSD::Pledge}){ OpenBSD::Pledge->import(); @@ -70,12 +70,12 @@ if (eval {require OpenBSD::Pledge}){ my ($self_path,$user_config_dir,$user_config_file,$user_data_dir); ## Hashes -my (%alerts,%build_prop,%client,%colors,%disks_bsd,%dboot,%devices,%dl, -%dmmapper,%force,%loaded,%mapper,%program_values,%rows,%sensors_raw, -%service_tool,%show,%sysctl,%system_files,%usb); +my (%alerts,%build_prop,%client,%colors,,%cpuinfo_machine,%disks_bsd, +%dboot,%devices,%dl,%dmmapper,%force,%loaded,%mapper,%program_values,%risc, +%rows,%sensors_raw,%service_tool,%show,%sysctl,%system_files,%usb); ## System Arrays -my (@app,@dmi,@gpudata,@ifs,@ifs_bsd,@paths,@ps_aux,@ps_cmd,@ps_gui, +my (@app,@cpuinfo,@dmi,@gpudata,@ifs,@ifs_bsd,@paths,@ps_aux,@ps_cmd,@ps_gui, @sensors_exclude,@sensors_use,@uname); ## Disk/Logical/Partition/RAID arrays @@ -100,8 +100,7 @@ if (eval {require Time::HiRes}){ @t0 = eval 'Time::HiRes::gettimeofday()' if $b_hires; # let's start it right away ## Booleans [busybox_ps not used actively] -my ($b_admin,$b_android,$b_arm,$b_busybox_ps,$b_cygwin,$b_display,$b_irc, -$b_mips,$b_ppc,$b_root,$b_running_in_display,$b_sparc); +my ($b_admin,$b_android,$b_busybox_ps,$b_cygwin,$b_display,$b_irc,$b_root); ## System my ($bsd_type,$device_vm,$language,$os,$pci_tool,$wan_url) = ('','','','','',''); @@ -135,17 +134,20 @@ my %sep = ( ); #$show{'host'} = 1; my %size = ( -'console' => 115, +'console' => 80, # In display, orig: 115 # Default indentation level. NOTE: actual indent is 1 greater to allow for # spacing 'indent' => 11, -'wrap-max' => 90, +'indents' => 2, 'irc' => 100, # shorter because IRC clients have nick lists etc -'max' => 0, -'no-display' => 130, -# these will be set dynamically in set_display_width() -'term' => 80, -'term-lines' => 100, +'lines' => 1, # for active output line counter for -Y +'max-cols' => 0, +'max-lines' => 0, +'max-wrap' => 110, +'no-display' => 100, # No Display, orig: 130 +# this will be set dynamically in set_display_size() +'term-cols' => 80, # orig: 80 +'term-lines' => 40, # orig: 100 ); my %use = ( 'update' => 1, # switched off/on with maintainer config ALLOW_UPDATE @@ -198,7 +200,7 @@ sub initialize { set_system_files(); Configs::set(); # set_downloader(); - set_display_width('live'); + set_display_size(); } ## CheckTools @@ -211,7 +213,7 @@ sub set { my ($action,$program,$message,@data); foreach my $test (keys %commands){ ($action,$program) = ('use',''); - $message = main::row_defaults('tool-present'); + $message = main::message('tool-present'); if ($commands{$test}->[1] && ( ($commands{$test}->[1] eq 'linux' && $os ne 'linux') || ($commands{$test}->[1] eq 'bsd' && $os eq 'linux'))){ @@ -222,6 +224,8 @@ sub set { # my $cmd = "$program $commands{$test} >/dev/null"; # print "$cmd\n"; $pci_tool = $test if $test =~ /pci/; + # this test is not ideal because other errors can make program fail, but + # we can't test for root since could be say, wheel permissions needed if ($commands{$test}->[0] eq 'exec-sys'){ $action = 'permissions' if system("$program $commands{$test}->[2] >/dev/null 2>&1"); } @@ -243,13 +247,13 @@ sub set { $alerts{$test}->{'action'} = $action; $alerts{$test}->{'path'} = $program; if ($action eq 'missing'){ - $alerts{$test}->{'message'} = main::row_defaults('tool-missing-recommends',"$test"); + $alerts{$test}->{'message'} = main::message('tool-missing-recommends',"$test"); } elsif ($action eq 'permissions'){ - $alerts{$test}->{'message'} = main::row_defaults('tool-permissions',"$test"); + $alerts{$test}->{'message'} = main::message('tool-permissions',"$test"); } elsif ($action eq 'platform'){ - $alerts{$test}->{'message'} = main::row_defaults('tool-missing-os', $uname[0] . " $test"); + $alerts{$test}->{'message'} = main::message('tool-missing-os', $uname[0] . " $test"); } } print Data::Dumper::Dumper \%alerts if $dbg[25]; @@ -290,13 +294,13 @@ sub set_dmidecode { } if ($action ne 'use' && $action ne 'permissions'){ if ($action eq 'smbios'){ - $alerts{'dmidecode'}->{'message'} = main::row_defaults('dmidecode-smbios'); + $alerts{'dmidecode'}->{'message'} = main::message('dmidecode-smbios'); } elsif ($action eq 'no-data'){ - $alerts{'dmidecode'}->{'message'} = main::row_defaults('dmidecode-dev-mem'); + $alerts{'dmidecode'}->{'message'} = main::message('dmidecode-dev-mem'); } elsif ($action eq 'unknown-error'){ - $alerts{'dmidecode'}->{'message'} = main::row_defaults('tool-unknown-error','dmidecode'); + $alerts{'dmidecode'}->{'message'} = main::message('tool-unknown-error','dmidecode'); } } return $action; @@ -444,63 +448,56 @@ sub set_basics { $ppid = getppid(); } -# args: $1 - default OR override default cols max integer count. $_[0] -# is the display width override. -sub set_display_width { - my ($width) = @_; - if ($width eq 'live'){ - ## sometimes tput will trigger an error (mageia) if irc client - if (!$b_irc){ - if (my $program = check_program('tput')){ - # Arch urxvt: 'tput: unknown terminal "rxvt-unicode-256color"' - # trips error if use qx(); in FreeBSD, if you use 2>/dev/null - # it makes default value 80x24, who knows why? - chomp($size{'term'} = qx{$program cols}); - chomp($size{'term-lines'} = qx{$program lines}); - $size{'term-cols'} = $size{'term'}; - } - # print "tc: $size{'term'} cmc: $size{'console'}\n"; - # double check, just in case it's missing functionality or whatever - if (!is_int($size{'term'} || $size{'term'} == 0)){ - $size{'term'}=80; - # we'll be using this for terminal dimensions later so don't set default. - # $size{'term-lines'}=100; - } - } - # this lets you set different size for in or out of display server - if (!$b_running_in_display && $size{'no-display'}){ - $size{'console'} = $size{'no-display'}; - } - # term_cols is set in top globals, using tput cols - # print "tc: $size{'term'} cmc: $size{'console'}\n"; - if ($size{'term'} < $size{'console'}){ - $size{'console'} = $size{'term'}; - } - # adjust, some terminals will wrap if output cols == term cols - $size{'console'} = ($size{'console'} - 2); - # echo cmc: $size{'console'} - # comes after source for user set stuff - if (!$b_irc){ - $size{'max'} = $size{'console'}; - } - else { - $size{'max'} = $size{'irc'}; - } +sub set_display_size { + ## sometimes tput will trigger an error (mageia) if irc client + if (!$b_irc){ + if (my $program = check_program('tput')){ + # Arch urxvt: 'tput: unknown terminal "rxvt-unicode-256color"' + # trips error if use qx(); in FreeBSD, if you use 2>/dev/null + # it makes default value 80x24, who knows why? + chomp($size{'term-cols'} = qx{$program cols}); + chomp($size{'term-lines'} = qx{$program lines}); + } + # print "tc: $size{'term-cols'} cmc: $size{'console'}\n"; + # double check, just in case it's missing functionality or whatever + if (!is_int($size{'term-cols'} || $size{'term-cols'} == 0)){ + $size{'term-cols'} = 80; + } + if (!is_int($size{'term-lines'} || $size{'term-lines'} == 0)){ + $size{'term-lines'} = 24; + } + } + # this lets you set different size for in or out of display server + if (!$b_display && $size{'no-display'}){ + $size{'console'} = $size{'no-display'}; + } + # term_cols is set in top globals, using tput cols + # print "tc: $size{'term-cols'} cmc: $size{'console'}\n"; + if ($size{'term-cols'} < $size{'console'}){ + $size{'console'} = $size{'term-cols'}; + } + # adjust, some terminals will wrap if output cols == term cols + $size{'console'} = ($size{'console'} - 1); + # echo cmc: $size{'console'} + # comes after source for user set stuff + if (!$b_irc){ + $size{'max-cols'} = $size{'console'}; } else { - $size{'max'} = $width; + $size{'max-cols'} = $size{'irc'}; } - # print "tc: $size{'term'} cmc: $size{'console'} cm: $size{'max'}\n"; + # print "tc: $size{'term-cols'} cmc: $size{'console'} cm: $size{'max-cols'}\n"; } sub set_os { @uname = uname(); $os = lc($uname[0]); $cpu_arch = lc($uname[-1]); - if ($cpu_arch =~ /arm|aarch/){$b_arm = 1;} - elsif ($cpu_arch =~ /mips/){$b_mips = 1} - elsif ($cpu_arch =~ /power|ppc/){$b_ppc = 1} - elsif ($cpu_arch =~ /sparc/){$b_sparc = 1} + if ($cpu_arch =~ /arm|aarch/){$risc{'arm'} = 1;$risc{'id'} = 'arm';} + elsif ($cpu_arch =~ /mips/){$risc{'mips'} = 1;$risc{'id'} = 'mips';} + elsif ($cpu_arch =~ /power|ppc/){$risc{'ppc'} = 1;$risc{'id'} = 'ppc';} + elsif ($cpu_arch =~ /riscv/){$risc{'riscv'} = 1;$risc{'id'} = 'riscv';} + elsif ($cpu_arch =~ /sparc/){$risc{'sparc'} = 1;$risc{'id'} = 'sparc';} # aarch32 mips32 intel/amd handled in cpu if ($cpu_arch =~ /(armv[1-7]|32|sparc_v9)/){ $bits_sys = 32; @@ -856,7 +853,7 @@ sub set_colors { } } # force 0 for | or > output, all others prints to irc or screen - if (!$b_irc && ! -t STDOUT){ + if (!$b_irc && !$force{'colors'} && ! -t STDOUT){ $color_scheme = 0; } set_color_scheme($color_scheme); @@ -1003,8 +1000,7 @@ sub get_selection { ); main::print_basic(\@data); @data = (); - my $response = <STDIN>; - chomp($response); + chomp(my $response = <STDIN>); if (!main::is_int($response) || $response > ($count + 3)){ @data = ( [0, '', '', "Error - Invalid Selection. You entered this: $response. Hit <ENTER> to continue."], @@ -1178,6 +1174,7 @@ sub set { # args: 0: key; 1: value sub process_item { my ($key,$val) = @_; + ## UTILITIES ## if ($key eq 'ALLOW_UPDATE' || $key eq 'B_ALLOW_UPDATE'){ $use{'update'} = $val if main::is_int($val)} elsif ($key eq 'ALLOW_WEATHER' || $key eq 'B_ALLOW_WEATHER'){ @@ -1245,7 +1242,7 @@ sub process_item { $weather_unit = $val; } } - # layout + ## COLORS/SEP ## elsif ($key eq 'CONSOLE_COLOR_SCHEME'){ $colors{'console'} = $val if main::is_int($val)} elsif ($key eq 'GLOBAL_COLOR_SCHEME'){ @@ -1267,7 +1264,7 @@ sub process_item { $sep{'s2-irc'} = $val} elsif ($key eq 'SEP2_CONSOLE'){ $sep{'s2-console'} = $val} - # size + ## SIZES ## elsif ($key eq 'COLS_MAX_CONSOLE'){ $size{'console'} = $val if main::is_int($val)} elsif ($key eq 'COLS_MAX_IRC'){ @@ -1276,8 +1273,19 @@ sub process_item { $size{'no-display'} = $val if main::is_int($val)} elsif ($key eq 'INDENT'){ $size{'indent'} = $val if main::is_int($val)} - elsif ($key eq 'WRAP_MAX' || $key eq 'INDENT_MIN'){ - $size{'wrap-max'} = $val if main::is_int($val)} + elsif ($key eq 'INDENTS'){ + $filter_string = $val if main::is_int($val)} + elsif ($key eq 'LINES_MAX'){ + if ($val =~ /^-?\d+$/ && $val >= -1){ + if ($val == 0){ + $size{'max-lines'} = $size{'term-lines'};} + elsif ($val == -1){ + $size{'output-block'} = 1;} + else { + $size{'max-lines'} = $val;} + }} + elsif ($key eq 'MAX_WRAP' || $key eq 'WRAP_MAX' || $key eq 'INDENT_MIN'){ + $size{'max-wrap'} = $val if main::is_int($val)} # print "mc: key: $key val: $val\n"; # print Dumper (keys %size) . "\n"; } @@ -1525,7 +1533,9 @@ sub run_debugger { if ($debugger{'sys'} && main::count_dir_files('/sys')){ build_tree('sys'); # kernel crash, not sure what creates it, for ppc, as root - sys_traverse_data() if ($debugger{'sys'} && ($debugger{'sys-force'} || !$b_root || !$b_ppc)) ; + if ($debugger{'sys'} && ($debugger{'sys-force'} || !$b_root || !$risc{'ppc'})){ + sys_traverse_data(); + } } else { print "Skipping /sys data collection.\n"; @@ -1567,10 +1577,7 @@ sub create_debug_directory { $root_string = '-root'; } my $id = ($debugger{'id'}) ? '-' . $debugger{'id'}: ''; - if ($b_arm){$alt_string = '-ARM'} - elsif ($b_mips){$alt_string = '-MIPS'} - elsif ($b_ppc){$alt_string = '-PPC'} - elsif ($b_sparc){$alt_string = '-SPARC'} + $alt_string = '-' . uc($risc{'id'}) if %risc; $alt_string .= "-BSD-$bsd_type" if $bsd_type; $alt_string .= '-ANDROID' if $b_android; $alt_string .= '-CYGWIN' if $b_cygwin; # could be windows arm? @@ -1846,9 +1853,10 @@ sub display_data { 'clutter-backend' => $ENV{'CLUTTER_BACKEND'}, 'sdl-videodriver' => $ENV{'SDL_VIDEODRIVER'}, # program display values - 'size-cols-max' => $size{'max'}, + 'size-cols-max' => $size{'max-cols'}, 'size-indent' => $size{'indent'}, - 'size-wrap-width' => $size{'wrap-max'}, + 'size-lines-max' => $size{'max-lines'}, + 'size-wrap-width' => $size{'max-wrap'}, ); write_data(\%data,'display'); my @cmds = ( @@ -2011,6 +2019,7 @@ sub system_data { ['dmidecode',''], ['dmesg',''], ['gcc','--version'], + ['getconf','-a'], ['initctl','list'], ['ipmi-sensors','-V'], # version ['ipmi-sensors',''], @@ -2064,9 +2073,14 @@ sub system_data { ['vcgencmd','get_mem gpu'], ); run_commands(\@cmds,'system'); + my $glob = '/sys/devices/system/cpu/'; + $glob .= '{cpufreq,cpu*/topology,cpu*/cpufreq,cpu*/cache/index*,smt,'; + $glob .= 'vulnerabilities}/*'; + get_glob('sys','cpu',$glob); @files = main::globber('/dev/bus/usb/*/*'); copy_files(\@files, 'system'); } + sub system_files { print "Collecting system files data...\n"; my (%data,@files,@files2); @@ -2187,6 +2201,25 @@ sub run_commands { } } } +sub get_glob { + my ($type,$id,$glob) = @_; + my @files = main::globber($glob); + return if !@files; + my ($item,@result); + foreach (sort @files){ + next if -d $_; + if (-r $_) { + $item = main::reader($_,'strip',0); + } + else { + $item = main::message('root-required'); + } + $item = main::message('undefined') if ! defined $item; + push(@result,$_ . '::' . $item); + } + # print Data::Dumper::Dumper \@result; + main::writer("$data_dir/$type-data-$id-glob.txt",\@result); +} sub write_data { my ($data_ref, $type) = @_; my ($empty,$error,$fh,$good,$name,$undefined,$value); @@ -2394,7 +2427,7 @@ sub wanted { # block maybe: cfgroup\/ # picdec\/|, wait_for_fb_sleep/wake is an odroid thing caused hang # wakeup_count also fails for android, but works fine on regular systems - return if $b_arm && $File::Find::name =~ m!^/sys/power/(wait_for_fb_|wakeup_count$)!; + return if $risc{'arm'} && $File::Find::name =~ m!^/sys/power/(wait_for_fb_|wakeup_count$)!; # do not need . files or __ starting files return if $File::Find::name =~ m!/\.[a-z]!; # pp_num_states: amdgpu driver bug; android: wakeup_count @@ -3303,7 +3336,7 @@ sub item_data { 'rpm' => '?', }, 'sudo' => { - 'info' => '-Dx hddtemp-user; -o file-user', + 'info' => '-Dx hddtemp-user; -o file-user (try doas!)', 'info-bsd' => '-Dx hddtemp-user; -o file-user (alt for doas)', 'apt' => 'sudo', 'pacman' => 'sudo', @@ -3502,7 +3535,7 @@ sub get_pm { sub make_row { my ($start,$middle,$end) = @_; my ($dots,$line,$sep) = ('','',': '); - foreach (0 .. ($size{'max'} - 16 - length("$start$middle"))){ + foreach (0 .. ($size{'max-cols'} - 16 - length("$start$middle"))){ $dots .= '.'; } $line = "$start$sep$middle$dots $end"; @@ -3510,7 +3543,7 @@ sub make_row { } sub make_line { my $line = ''; - foreach (0 .. $size{'max'} - 2){ + foreach (0 .. $size{'max-cols'} - 2){ $line .= '-'; } return $line; @@ -3665,13 +3698,14 @@ sub is_hex { ## NOTE: for perl pre 5.012 length(undef) returns warning # receives string, returns boolean 1 if integer sub is_int { - return 1 if (defined $_[0] && length($_[0]) && length($_[0]) == ($_[0] =~ tr/0123456789//)); + return 1 if (defined $_[0] && length($_[0]) && + length($_[0]) == ($_[0] =~ tr/0123456789//)); } -# receives string, returns boolean 1 if numeric. tr/// is 4x faster than regex +# receives string, returns true/1 if >= 0 numeric. tr/// 4x faster than regex sub is_numeric { return 1 if (defined $_[0] && ($_[0] =~ tr/0123456789//) >= 1 && - length($_[0]) == ($_[0] =~ tr/0123456789.//) && ($_[0] =~ tr/.//) <= 1); + length($_[0]) == ($_[0] =~ tr/0123456789.//) && ($_[0] =~ tr/.//) <= 1); } # gets array ref, which may be undefined, plus join string @@ -4461,7 +4495,7 @@ sub get { 'B|battery' => sub { $show{'short'} = 0; $show{'battery'} = 1; - $show{'battery-forced'} = 1; }, + $show{'battery-forced'} = 1;}, 'c|color:i' => sub { my ($opt,$arg) = @_; if ($arg >= 0 && $arg < main::get_color_scheme('count')){ @@ -4475,14 +4509,14 @@ sub get { } }, 'C|cpu' => sub { $show{'short'} = 0; - $show{'cpu'} = 1; }, + $show{'cpu'} = 1;}, 'd|disk-full|optical' => sub { $show{'short'} = 0; $show{'disk'} = 1; - $show{'optical'} = 1; }, + $show{'optical'} = 1;}, 'D|disk' => sub { $show{'short'} = 0; - $show{'disk'} = 1; }, + $show{'disk'} = 1;}, 'E|bluetooth' => sub { $show{'short'} = 0; $show{'bluetooth'} = 1; @@ -4490,7 +4524,7 @@ sub get { 'f|flags|flag' => sub { $show{'short'} = 0; $show{'cpu'} = 1; - $show{'cpu-flag'} = 1; }, + $show{'cpu-flag'} = 1;}, 'F|full' => sub { $show{'short'} = 0; $show{'audio'} = 1; @@ -4508,13 +4542,13 @@ sub get { $show{'raid'} = 1; $show{'sensor'} = 1; $show{'swap'} = 1; - $show{'system'} = 1; }, + $show{'system'} = 1;}, 'G|graphics|graphic' => sub { $show{'short'} = 0; $show{'graphic'} = 1; - $show{'graphic-basic'} = 1; }, + $show{'graphic-basic'} = 1;}, 'h|help|?' => sub { - $show{'help'} = 1; }, + $show{'help'} = 1;}, 'i|ip' => sub { $show{'short'} = 0; $show{'ip'} = 1; @@ -4523,13 +4557,13 @@ sub get { $use{'downloader'} = 1 if ! main::check_program('dig');}, 'I|info' => sub { $show{'short'} = 0; - $show{'info'} = 1; }, + $show{'info'} = 1;}, 'j|swap|swaps' => sub { $show{'short'} = 0; $show{'swap'} = 1;}, 'J|usb' => sub { $show{'short'} = 0; - $show{'usb'} = 1; }, + $show{'usb'} = 1;}, 'l|labels|label' => sub { $show{'label'} = 1;}, 'limit:i' => sub { @@ -4542,10 +4576,10 @@ sub get { } }, 'L|logical|lvm' => sub { $show{'short'} = 0; - $show{'logical'} = 1; }, + $show{'logical'} = 1;}, 'm|memory' => sub { $show{'short'} = 0; - $show{'ram'} = 1; }, + $show{'ram'} = 1;}, 'memory-modules' => sub { $show{'short'} = 0; $show{'ram'} = 1; @@ -4556,24 +4590,24 @@ sub get { $show{'ram-short'} = 1;}, 'M|machine' => sub { $show{'short'} = 0; - $show{'machine'} = 1; }, + $show{'machine'} = 1;}, 'n|network-advanced' => sub { $show{'short'} = 0; $show{'network'} = 1; - $show{'network-advanced'} = 1; }, + $show{'network-advanced'} = 1;}, 'N|network' => sub { $show{'short'} = 0; - $show{'network'} = 1; }, + $show{'network'} = 1;}, 'o|unmounted' => sub { $show{'short'} = 0; - $show{'unmounted'} = 1; }, + $show{'unmounted'} = 1;}, 'p|partition-full|partitions-full' => sub { $show{'short'} = 0; $show{'partition'} = 0; - $show{'partition-full'} = 1; }, + $show{'partition-full'} = 1;}, 'P|partitions|partition' => sub { $show{'short'} = 0; - $show{'partition'} = 1; }, + $show{'partition'} = 1;}, 'partition-sort:s' => sub { my ($opt,$arg) = @_; if ($arg =~ /^(dev-base|fs|id|label|percent-used|size|uuid|used)$/){ @@ -4584,14 +4618,14 @@ sub get { } }, 'r|repos|repo' => sub { $show{'short'} = 0; - $show{'repo'} = 1; }, + $show{'repo'} = 1;}, 'R|raid' => sub { $show{'short'} = 0; $show{'raid'} = 1; - $show{'raid-forced'} = 1; }, + $show{'raid-forced'} = 1;}, 's|sensors|sensor' => sub { $show{'short'} = 0; - $show{'sensor'} = 1; }, + $show{'sensor'} = 1;}, 'sleep:s' => sub { my ($opt,$arg) = @_; $arg ||= 0; @@ -4603,10 +4637,10 @@ sub get { } }, 'slots|slot' => sub { $show{'short'} = 0; - $show{'slot'} = 1; }, + $show{'slot'} = 1;}, 'S|system' => sub { $show{'short'} = 0; - $show{'system'} = 1; }, + $show{'system'} = 1;}, 't|processes|process:s' => sub { my ($opt,$arg) = @_; $show{'short'} = 0; @@ -4773,19 +4807,42 @@ sub get { $arg = 80; } if ($arg =~ /\d/ && ($arg == 1 || $arg >= 80)){ - main::set_display_width($arg); + $size{'max-cols'} = $arg; } else { main::error_handler('bad-arg', $opt, $arg); - } }, + }}, + 'Y|height|less:i' => sub { + my ($opt, $arg) = @_; + main::error_handler('not-in-irc', '-Y/--height') if $b_irc; + if ($arg >= -3){ + if ($arg >= 0){ + $size{'max-lines'} = ($arg) ? $arg: $size{'term-lines'}; + } + elsif ($arg == -1) { + $use{'output-block'} = 1; + } + elsif ($arg == -2) { + $force{'colors'} = 1; + } + # unset conifiguration set max height + else { + $size{'max-lines'} = 0; + } + } + else { + main::error_handler('bad-arg', $opt, $arg); + }}, 'z|filter' => sub { - $use{'filter'} = 1; }, - 'filter-label' => sub { - $use{'filter-label'} = 1; }, - 'Z|filter-override' => sub { - $use{'filter-override'} = 1; }, - 'filter-uuid' => sub { - $use{'filter-uuid'} = 1; }, + $use{'filter'} = 1;}, + 'filter-label|zl' => sub { + $use{'filter-label'} = 1;}, + 'Z|filter-override|no-filter' => sub { + $use{'filter-override'} = 1;}, + 'filter-uuid|zu' => sub { + $use{'filter-uuid'} = 1;}, + 'filter-v|filter-vulnerabilities|zv' => sub { + $use{'filter-vulnerabilities'} = 1;}, ## Start non data options 'alt:i' => sub { my ($opt,$arg) = @_; @@ -4810,7 +4867,9 @@ sub get { main::error_handler('bad-arg', $opt, $arg); }}, 'arm' => sub { - $b_arm = 1 }, + undef %risc; + $risc{'id'} = 'arm'; + $risc{'arm'} = 1;}, 'bsd:s' => sub { my ($opt,$arg) = @_; if ($arg =~ /^(darwin|dragonfly|freebsd|openbsd|netbsd)$/i){ @@ -4864,17 +4923,17 @@ sub get { 'debug-no-exit' => sub { $debugger{'no-exit'} = 1 }, 'debug-no-proc' => sub { - $debugger{'no-proc'} = 1; }, + $debugger{'no-proc'} = 1;}, 'debug-no-sys' => sub { - $debugger{'sys'} = 0; }, + $debugger{'sys'} = 0;}, 'debug-proc' => sub { - $debugger{'proc'} = 1; }, + $debugger{'proc'} = 1;}, 'debug-proc-print' => sub { $debugger{'proc-print'} = 1;}, 'debug-sys-print' => sub { - $debugger{'sys-print'} = 1; }, + $debugger{'sys-print'} = 1;}, 'debug-test-1' => sub { - $debugger{'test-1'} = 1; }, + $debugger{'test-1'} = 1;}, 'debug-width|debug-y|debug-zy:i' => sub { my ($opt,$arg) = @_; $arg ||= 80; @@ -4885,7 +4944,7 @@ sub get { main::error_handler('bad-arg', $opt, $arg); } }, 'dig' => sub { - $force{'no-dig'} = 0; }, + $force{'no-dig'} = 0;}, 'display:s' => sub { my ($opt,$arg) = @_; if ($arg =~ /^:?([0-9\.]+)?$/){ @@ -4945,8 +5004,8 @@ sub get { 'force:s' => sub { my ($opt,$arg) = @_; if ($arg){ - my $wl = 'display|dmidecode|hddtemp|lsusb|man|meminfo|no-dig|'; - $wl .= 'no-doas|no-html-wan|no-sudo|pkg|usb-sys|vmstat|wmctrl'; + my $wl = 'colors|cpuinfo|display|dmidecode|hddtemp|lsusb|man|meminfo|'; + $wl .= 'no-dig|no-doas|no-html-wan|no-sudo|pkg|usb-sys|vmstat|wmctrl'; for (split(',',$arg)){ if ($_ =~ /\b($wl)\b/){ $force{lc($1)} = 1; @@ -4974,13 +5033,39 @@ sub get { $show{'host'} = 1; $show{'no-host'} = 0}, 'html-wan' => sub { - $force{'no-html-wan'} = 0; }, + $force{'no-html-wan'} = 0;}, + 'indent:i' => sub { + my ($opt,$arg) = @_; + if ($arg >= 11){ + $size{'indent'} = $arg; + } + else { + main::error_handler('bad-arg', $opt, $arg); + }}, + 'indents:i' => sub { + my ($opt,$arg) = @_; + if ($arg >= 0 && $arg < 11){ + $size{'indents'} = $arg; + } + else { + main::error_handler('bad-arg', $opt, $arg); + }}, 'irc' => sub { - $b_irc = 1; }, + $b_irc = 1;}, 'man' => sub { - $use{'yes-man'} = 1; }, + $use{'yes-man'} = 1;}, + 'max-wrap|wrap-max|indent-min:i' => sub { + my ($opt,$arg) = @_; + if ($arg >= 0){ + $size{'max-wrap'} = $arg; + } + else { + main::error_handler('bad-arg', $opt, $arg); + }}, 'mips' => sub { - $b_mips = 1 }, + undef %risc; + $risc{'id'} = 'mips'; + $risc{'mips'} = 1;}, 'output:s' => sub { my ($opt,$arg) = @_; if ($arg =~ /^(json|screen|xml)$/){ @@ -4990,20 +5075,20 @@ sub get { main::error_handler('bad-arg', $opt, $arg); }}, 'no-dig' => sub { - $force{'no-dig'} = 1; }, + $force{'no-dig'} = 1;}, 'no-doas' => sub { - $force{'no-doas'} = 1; }, + $force{'no-doas'} = 1;}, 'no-host|no-hostname' => sub { $show{'host'} = 0 ; $show{'no-host'} = 1}, 'no-html-wan' => sub { $force{'no-html-wan'}= 1;}, 'no-man' => sub { - $use{'no-man'} = 0; }, + $use{'no-man'} = 0;}, 'no-ssl' => sub { $dl{'no-ssl-opt'}=1 }, 'no-sudo' => sub { - $force{'no-sudo'} = 1; }, + $force{'no-sudo'} = 1;}, 'output-file:s' => sub { my ($opt,$arg) = @_; if ($arg){ @@ -5020,11 +5105,17 @@ sub get { 'pkg' => sub { $force{'pkg'} = 1 }, 'ppc' => sub { - $b_ppc = 1 }, + undef %risc; + $risc{'id'} = 'ppc'; + $risc{'ppc'} = 1;}, 'recommends' => sub { $show{'recommends'} = 1;}, + 'riscv' => sub { + undef %risc; + $risc{'id'} = 'riscv'; + $risc{'riscv'} = 1;}, 'sensors-default' => sub { - $use{'sensors-default'} = 1; }, + $use{'sensors-default'} = 1;}, 'sensors-exclude:s' => sub { my ($opt,$arg) = @_; if ($arg){ @@ -5042,11 +5133,13 @@ sub get { main::error_handler('bad-arg',$opt,$arg); }}, 'sparc' => sub { - $b_sparc = 1; }, + undef %risc; + $risc{'id'} = 'sparc'; + $risc{'sparc'} = 1;}, 'sys-debug' => sub { - $debugger{'sys-force'} = 1; }, + $debugger{'sys-force'} = 1;}, 'tty' => sub { # workaround for ansible running this - $b_irc = 0; }, + $b_irc = 0;}, 'U|update:s' => sub { # 1,2,3 OR http://myserver/path/inxi my ($opt,$arg) = @_; process_updater($opt,$arg);}, @@ -5065,14 +5158,6 @@ sub get { }}, 'wm' => sub { $force{'wmctrl'} = 1 }, - 'wrap-max|indent-min:i' => sub { - my ($opt,$arg) = @_; - if ($arg =~ /^\d+$/){ - $size{'wrap-max'} = $arg; - } - else { - main::error_handler('bad-arg', $opt, $arg); - }}, '<>' => sub { my ($opt) = @_; main::error_handler('unknown-option', "$opt", "");} @@ -5250,133 +5335,131 @@ sub show_options { my $color_scheme_count = get_color_scheme('count') - 1; my $partition_string='partition'; my $partition_string_u='Partition'; - my $flags = ($b_arm) ? 'features' : 'flags' ; + my $flags = (%risc || $bsd_type) ? 'features' : 'flags' ; if ($bsd_type){ $partition_string='slice'; $partition_string_u='Slice'; } # fit the line to the screen! - for my $i (0 .. (($size{'max'} / 2) - 2)){ + for my $i (0 .. (($size{'max-cols'} / 2) - 2)){ $line = $line . '- '; } push(@data, ['0', '', '', "$self_name supports the following options. For more detailed information, see man^$self_name. If you start $self_name with no arguments, - it will display a short system summary." ], - ['0', '', '', '' ], + it will display a short system summary."], + ['0', '', '', ''], ['0', '', '', "You can use these options alone or together, to show or add the item(s) you want to see: A, B, C, D, E, G, I, J, L, M, N, P, R, S, W, d, f, i, j, l, m, n, o, p, r, s, t, u, w, --slots. If you use them with -v [level], -b or -F, $self_name will add the requested - lines to the output." ], + lines to the output."], ['0', '', '', '' ], ['0', '', '', "Examples:^$self_name^-v4^-c6 OR $self_name^-bDc^6 OR - $self_name^-FzjJxy^80" ], + $self_name^-FzjJxy^80"], ['0', '', '', $line ], - ['0', '', '', "Output Control Options (see Extra Data Options to extend output):" ], - ['1', '-A', '--audio', "Audio/sound devices(s), driver, running sound servers." ], - ['1', '-b', '--basic', "Basic output, short form. Same as $self_name^-v^2." ], + ['0', '', '', "See Filter Options for output filtering, Output Control Options + for colors, sizing, output changes, Extra Data Options to extend Main output, + Additional Options and Advanced Options for less common situations."], + ['0', '', '', $line ], + ['0', '', '', "Main Feature Options:"], + ['1', '-A', '--audio', "Audio/sound devices(s), driver, running sound + servers."], + ['1', '-b', '--basic', "Basic output, short form. Same as $self_name^-v^2."], ['1', '-B', '--battery', "System battery info, including charge, condition - voltage (if critical), plus extra info (if battery present/detected)." ], - ['1', '-c', '--color', "Set color scheme (0-42). For piped or redirected output, - you must use an explicit color selector. Example:^$self_name^-c^11" ], - ['1', '', '', "Color selectors let you set the config file value for the - selection (NOTE: IRC and global only show safe color set)" ], - ['2', '94', '', "Console, out of X" ], - ['2', '95', '', "Terminal, running in X - like xTerm" ], - ['2', '96', '', "Gui IRC, running in X - like Xchat, Quassel, Konversation etc." ], - ['2', '97', '', "Console IRC running in X - like irssi in xTerm" ], - ['2', '98', '', "Console IRC not in X" ], - ['2', '99', '', "Global - Overrides/removes all settings. Setting specific - removes global." ], - ['1', '-C', '--cpu', "CPU output, including per CPU clock speed and max - CPU speed (if available)." ], + voltage (if critical), plus extra info (if battery present/detected)."], + ['1', '-C', '--cpu', "CPU output (if each item available): basic topology, + model, type (see man for types), cache, average CPU speed, min/max speeds, + per core clock speeds."], ['1', '-d', '--disk-full, --optical', "Optical drive data (and floppy disks, - if present). Triggers -D." ], + if present). Triggers -D."], ['1', '-D', '--disk', "Hard Disk info, including total storage and details for each disk. Disk total used percentage includes swap ${partition_string} - size(s)." ], - ['1', '-E', '--bluetooth', "Show bluetooth device data and report, if available. - Shows state, address, IDs, version info." ], + size(s)."], + ['1', '-E', '--bluetooth', "Show bluetooth device data and report, if + available. Shows state, address, IDs, version info."], ['1', '-f', '--flags', "All CPU $flags. Triggers -C. Not shown with -F to - avoid spamming." ], + avoid spamming."], ['1', '-F', '--full', "Full output. Includes all Upper Case line letters - (except -J, -W) plus --swap, -s and -n. Does not show extra verbose options such - as -d -f -i -J -l -m -o -p -r -t -u -x, unless specified." ], - ['1', '-G', '--graphics', "Graphics info (devices(s), drivers, display protocol - (if available), display server/Wayland compositor, resolution, renderer, - OpenGL version)." ], + (except -J, -W) plus --swap, -s and -n. Does not show extra verbose options + such as -d -f -i -J -l -m -o -p -r -t -u -x, unless specified."], + ['1', '-G', '--graphics', "Graphics info (devices(s), drivers, display + protocol (if available), display server/Wayland compositor, resolution, + renderer, OpenGL version)."], ['1', '-i', '--ip', "WAN IP address and local interfaces (requires ifconfig or ip network tool). Triggers -n. Not shown with -F for user security reasons. - You shouldn't paste your local/WAN IP." ], + You shouldn't paste your local/WAN IP."], ['1', '-I', '--info', "General info, including processes, uptime, memory, - IRC client or shell type, $self_name version." ], - ['1', '-j', '--swap', "Swap in use. Includes ${partition_string}s, zram, file." ], - ['1', '-J', '--usb', "Show USB data: Hubs and Devices." ], - ['1', '-l', '--label', "$partition_string_u labels. Use with -j, -o, -p, -P." ], + IRC client or shell type, $self_name version."], + ['1', '-j', '--swap', "Swap in use. Includes ${partition_string}s, zram, + file."], + ['1', '-J', '--usb', "Show USB data: Hubs and Devices."], + ['1', '-l', '--label', "$partition_string_u labels. Use with -j, -o, -p, -P."], ['1', '-L', '--logical', "Logical devices, LVM (VG, LV), - LUKS, Crypto, bcache, etc. Shows components/devices, sizes, etc." ], + LUKS, Crypto, bcache, etc. Shows components/devices, sizes, etc."], ['1', '-m', '--memory', "Memory (RAM) data. Requires root. Numbers of devices (slots) supported and individual memory devices (sticks of memory etc). For devices, shows device locator, size, speed, type (e.g. DDR3). - If neither -I nor -tm are selected, also shows RAM used/total." ], - ['1', '', '--memory-modules', "Memory (RAM) data. Exclude empty module slots." ], - ['1', '', '--memory-short', "Memory (RAM) data. Show only short Memory RAM report, - number of arrays, slots, modules, and RAM type." ], + If neither -I nor -tm are selected, also shows RAM used/total."], + ['1', '', '--memory-modules', "Memory (RAM) data. Exclude empty module slots."], + ['1', '', '--memory-short', "Memory (RAM) data. Show only short Memory RAM + report, number of arrays, slots, modules, and RAM type."], ['1', '-M', '--machine', "Machine data. Device type (desktop, server, laptop, VM etc.), motherboard, BIOS and, if present, system builder (e.g. Lenovo). Shows UEFI/BIOS/UEFI [Legacy]. Older systems/kernels without the required /sys - data can use dmidecode instead, run as root. Dmidecode can be forced with --dmidecode" ], - ['1', '-n', '--network-advanced', "Advanced Network device info. Triggers -N. Shows - interface, speed, MAC id, state, etc. " ], - ['1', '-N', '--network', "Network device(s), driver." ], + data can use dmidecode instead, run as root. Dmidecode can be forced with + --dmidecode"], + ['1', '-n', '--network-advanced', "Advanced Network device info. Triggers -N. + Shows interface, speed, MAC id, state, etc. "], + ['1', '-N', '--network', "Network device(s), driver."], ['1', '-o', '--unmounted', "Unmounted $partition_string info (includes UUID and Label if available). Shows file system type if you have lsblk installed (Linux) or, for BSD/GNU Linux, if 'file' installed and you are root or if - you have added to /etc/sudoers (sudo v. 1.7 or newer)(BSDs: see doas)." ], - ['1', '', '', "Example: ^<username>^ALL^=^NOPASSWD:^/usr/bin/file^" ], - ['1', '-p', '--partitions-full', "Full $partition_string information (-P plus all other - detected ${partition_string}s)." ], + you have added to /etc/sudoers (sudo v. 1.7 or newer)(or try doas)."], + ['1', '', '', "Example: ^<username>^ALL^=^NOPASSWD:^/usr/bin/file^"], + ['1', '-p', '--partitions-full', "Full $partition_string information (-P plus + all other detected ${partition_string}s)."], ['1', '-P', '--partitions', "Basic $partition_string info. Shows, if detected: / /boot /home /opt /tmp /usr /usr/home /var /var/log /var/tmp. Swap ${partition_string}s show if --swap is not used. Use -p to see all - mounted ${partition_string}s." ], + mounted ${partition_string}s."], ['1', '-r', '--repos', "Distro repository data. Supported repo types: APK, APT, CARDS, EOPKG, NIX, PACMAN, PACMAN-G2, PISI, PKG (BSDs), PORTAGE, PORTS - (BSDs), SCRATCHPKG, SLACKPKG, TCE, URPMQ, XBPS, YUM/ZYPP." ], - ['1', '-R', '--raid', "RAID data. Shows RAID devices, states, levels, array sizes, - and components. md-raid: If device is resyncing, also shows resync progress line." ], + (BSDs), SCRATCHPKG, SLACKPKG, TCE, URPMQ, XBPS, YUM/ZYPP."], + ['1', '-R', '--raid', "RAID data. Shows RAID devices, states, levels, array + sizes, and components. md-raid: If device is resyncing, also shows resync + progress line."], ['1', '-s', '--sensors', "Sensors output (if sensors installed/configured): mobo/CPU/GPU temp; detected fan speeds. GPU temp only for Fglrx/Nvidia drivers. - Nvidia shows screen number for > 1 screen. IPMI sensors if present." ], - ['1', '', '--slots', "PCI slots: type, speed, status. Requires root." ], + Nvidia shows screen number for > 1 screen. IPMI sensors if present."], + ['1', '', '--slots', "PCI slots: type, speed, status. Requires root."], ['1', '-S', '--system', "System info: host name, kernel, desktop environment - (if in X/Wayland), distro." ], + (if in X/Wayland), distro."], ['1', '-t', '--processes', "Processes. Requires extra options: c (CPU), m (memory), cm (CPU+memory). If followed by numbers 1-x, shows that number - of processes for each type (default: 5; if in IRC, max: 5). " ], + of processes for each type (default: 5; if in IRC, max: 5). "], ['1', '', '', "Make sure that there is no space between letters and - numbers (e.g.^-t^cm10)." ], - ['1', '-u', '--uuid', "$partition_string_u UUIDs. Use with -j, -o, -p, -P." ], + numbers (e.g.^-t^cm10)."], + ['1', '-u', '--uuid', "$partition_string_u UUIDs. Use with -j, -o, -p, -P."], ['1', '-v', '--verbosity', "Set $self_name verbosity level (0-8). - Should not be used with -b or -F. Example: $self_name^-v^4" ], - ['2', '0', '', "Same as: $self_name" ], - ['2', '1', '', "Basic verbose, -S + basic CPU + -G + basic Disk + -I." ], - ['2', '2', '', "Networking device (-N), Machine (-M), Battery (-B; if present), - and, if present, basic RAID (devices only; notes if inactive). - Same as $self_name^-b" ], + Should not be used with -b or -F. Example: $self_name^-v^4"], + ['2', '0', '', "Same as: $self_name"], + ['2', '1', '', "Basic verbose, -S + basic CPU + -G + basic Disk + -I."], + ['2', '2', '', "Networking device (-N), Machine (-M), Battery (-B; if + present), and, if present, basic RAID (devices only; notes if inactive). Same + as $self_name^-b"], ['2', '3', '', "Advanced CPU (-C), battery (-B), network (-n); - triggers -x. " ], + triggers -x. "], ['2', '4', '', "$partition_string_u size/used data (-P) for - (if present) /, /home, /var/, /boot. Shows full disk data (-D). " ], + (if present) /, /home, /var/, /boot. Shows full disk data (-D). "], ['2', '5', '', "Audio device (-A), sensors (-s), memory/RAM (-m), bluetooth (if present), $partition_string label^(-l), full swap (-j), - UUID^(-u), short form of optical drives, RAID data (if present)." ], + UUID^(-u), short form of optical drives, RAID data (if present)."], ['2', '6', '', "Full $partition_string (-p), unmounted $partition_string (-o), optical drive (-d), USB (-J), - full RAID; triggers -xx." ], + full RAID; triggers -xx."], ['2', '7', '', "Network IP data (-i), bluetooth, logical (-L), - RAID forced; triggers -xxx."], + RAID forced, full CPU $flags; triggers -xxx."], ['2', '8', '', "Everything available, including repos (-r), processes (-tcm), PCI slots (--slots); triggers admin (-a)."], ); @@ -5391,316 +5474,364 @@ sub show_options { want the weather somewhere other than the machine running $self_name. Use only ASCII characters, replace spaces in city/state/country names with '+'. Example:^$self_name^-W^[new+york,ny^london,gb^madrid,es]"], - ['1', '', '--weather-source', "[1-9] Change weather data source. 1-4 generally - active, 5-9 check. See man."], + ['1', '', '--weather-source', "[1-9] Change weather data source. 1-4 + generally active, 5-9 check. See man."], ['1', '', '--weather-unit', "Set weather units to metric (m), imperial (i), metric/imperial (mi), or imperial/metric (im)."], ); } push(@data, - ['1', '-y', '--width', "Output line width max (integer >= 80). Overrides IRC/Terminal - settings or actual widths. If no integer give, defaults to 80. -1 removes line lengths. - 1 switches output to 1 key/value pair per line. Example:^inxi^-y^130" ], - ['1', '-z', '--filter', "Adds security filters for IP/MAC addresses, serial numbers, - location (-w), user home directory name, host name. Default on for IRC clients." ], - ['1', '', '--filter-label', "Filters out ${partition_string} labels in -j, - -o, -p, -P, -Sa." ], - ['1', '-Z', '--filter-override', "Override for output filters. Useful for - debugging networking issues in IRC, for example." ], - ['1', '', '--filter-uuid', "Filters out ${partition_string} UUIDs in -j, - -o, -p, -P, -Sa." ], - ['0', '', '', "$line" ], - ['0', '', '', "Extra Data Options:" ], + [0, '', '', "$line"], + ['0', '', '', "Filter Options:"], + ['1', '', '--host', "Turn on hostname for -S. Overrides -z."], + ['1', '', '--no-host', "Turn off hostname for -S. Useful if showing output + from servers etc. Activated by -z as well."], + ['1', '-z', '--filter', "Adds security filters for IP/MAC addresses, serial + numbers, location (-w), user home directory name, host name. Default on for + IRC clients."], + ['1', '', '--zl,--filter-label', "Filters out ${partition_string} labels in + -j, -o, -p, -P, -Sa."], + ['1', '', '--zu,--filter-uuid', "Filters out ${partition_string} UUIDs in -j, + -o, -p, -P, -Sa."], + ['1', '', '--zv,--filter-vulnerabilities', "Filters out Vulnerabilities + report in -Ca."], + ['1', '-Z', '--no-filter', "Disable output filters. Useful for debugging + networking issues in IRC, or you needed to use --tty, for example."], + [0, '', '', "$line"], + ['0', '', '', "Output Control Options:"], + ['1', '-c', '--color', "Set color scheme (0-42). For piped or redirected + output, you must use an explicit color selector. Example:^$self_name^-c^11"], + ['1', '', '', "Color selectors let you set the config file value for the + selection (NOTE: IRC and global only show safe color set)"], + ['2', '94', '', "Console, out of X"], + ['2', '95', '', "Terminal, running in X - like xTerm"], + ['2', '96', '', "Gui IRC, running in X - like Xchat, Quassel, Konversation + etc."], + ['2', '97', '', "Console IRC running in X - like irssi in xTerm"], + ['2', '98', '', "Console IRC not in X"], + ['2', '99', '', "Global - Overrides/removes all settings. Setting specific + removes global."], + ['1', '', '--indent', "[11-20] Change default wide mode primary indentation + width."], + ['1', '', '--indents', "[0-10] Change wrapped mode primary indentation width, + and secondary / -y1 indent widths."], + ['1', '', '--limit', "[-1; 1-x] Set max output limit of IP addresses for -i + (default 10; -1 removes limit)."], + ['1', '', '--max-wrap,--wrap-max', "[70-xxx] Set maximum width where + $self_name autowraps line starters. Current: $size{'max-wrap'}"], + ['1', '', '--output', "[json|screen|xml] Change data output type. Requires + --output-file if not screen."], + ['1', '', '--output-file', "[Full filepath|print] Output file to be used for + --output."], + ['1', '', '--partition-sort', "[dev-base|fs|id|label|percent-used|size|uuid|used] + Change sort order of ${partition_string} output. See man page for specifics."], + ['1', '-y', '--width', "[empty|-1|1|80-xxx] Output line width max. Overrides + IRC/Terminal settings or actual widths. If no integer give, defaults to 80. + -1 removes line lengths. 1 switches output to 1 key/value pair per line. + Example:^inxi^-y^130"], + ['1', '-Y', '--height', "[empty|-3-xxx] Output height control. Similar to + 'less' command except colors preserved, defaults to console/terminal height. + -1 shows 1 primary Item: at a time; -2 retains color on redirect/piping (to + less -R); -3 removes configuration value; 0 or -Y sets to detected terminal + height. Greater than 0 shows x lines at a time."], + ['0', '', '', "$line"], + ['0', '', '', "Extra Data Options:"], ['1', '-a', '--admin', "Adds advanced sys admin data (only works with verbose or line output, not short form); check man page for explanations!; - also sets --extra=3:" ], + also sets --extra=3:"], ['2', '-A', '', "If available: list of alternate kernel modules/drivers - for device(s)." ], + for device(s)."], ['2', '-C', '', "If available: CPU socket type, base/boost speeds - (dmidecode+root/sudo/doas[BSDs] required); CPU vulnerabilities (bugs); - family, model-id, stepping - format: hex (decimal) if greater - than 9, otherwise hex; microcode - format: hex." ], - ['2', '-d,-D', '', "If available: logical and physical block sizes; drive family; - maj:min, USB drive specifics; SMART report." ], + (dmidecode+root/sudo/doas required); Full topology line, with cores, threads, + threads per core, granular cache data, smt status; CPU vulnerabilities (bugs); + family, model-id, stepping - format: hex (decimal) if greater than 9; + microcode format: hex."], + ['2', '-d,-D', '', "If available: logical and physical block sizes; drive + family; maj:min, USB drive specifics; SMART report."], ['2', '-E', '', "If available: in Report:, adds Info: line: acl-mtu, - sco-mtu, link-policy, link-mode, service-classes." ], + sco-mtu, link-policy, link-mode, service-classes."], ['2', '-G', '', "If available: Xorg Display ID, Screens total, default Screen, current Screen; per X Screen: resolution, dpi, size, diagonal; per Monitor: resolution; hz; dpi; size; diagonal; list of alternate kernel modules/drivers - for device(s)." ], + for device(s)."], ['2', '-I', '', "As well as per package manager counts, also adds total number of lib files found for each package manager if not -r; adds init - service tool." ], + service tool."], ['2', '-j,-p,-P', '', "For swap (if available): swappiness and vfs cache - pressure, and if values are default or not." ], + pressure, and if values are default or not."], ['2', '-L', '', "LV, Crypto, devices, components: add maj:min; show - full device/components report (speed, mapped names)." ], + full device/components report (speed, mapped names)."], ['2', '-n,-N', '', "If available: list of alternate kernel modules/drivers - for device(s)." ], - ['2', '-o', '', "If available: maj:min of device." ], + for device(s)."], + ['2', '-o', '', "If available: maj:min of device."], ['2', '-p,-P', '', "If available: raw size of ${partition_string}s, maj:min, - percent available for user, block size of file system (root required)." ], - ['2', '-r', '', "Packages, see -Ia." ], - ['2', '-R', '', "mdraid: device maj:min; per component: size, maj:min, state." ], - ['2', '-S', '', "If available: kernel boot parameters." ], + percent available for user, block size of file system (root required)."], + ['2', '-r', '', "Packages, see -Ia."], + ['2', '-R', '', "mdraid: device maj:min; per component: size, maj:min, state."], + ['2', '-S', '', "If available: kernel boot parameters."], ['0', '', '', ''], ['1', '-x', '--extra', "Adds the following extra data (only works with - verbose or line output, not short form):" ], + verbose or line output, not short form):"], ['2', '-A', '', "Specific vendor/product information (if relevant); PCI/USB ID of device; Version/port(s)/driver version (if available); - non-running sound servers." ], + non-running sound servers."], ['2', '-B', '', "Current/minimum voltage, vendor/model, status (if available); - attached devices (e.g. wireless mouse, keyboard, if present)." ], - ['2', '-C', '', "CPU $flags (short list, use -f to see full list); - CPU boost (turbo) enabled/disabled, if present; - Bogomips on CPU; CPU microarchitecture + revision (if found, or - unless --admin, then shows as 'stepping')." ], + attached devices (e.g. wireless mouse, keyboard, if present)."], + ['2', '-C', '', "L1/L3 cache (if most Linux, or if root and dmidecode + installed); smt if disabled, CPU $flags (short list, use -f to see full list); + Highest core speed (if > 1 core); CPU boost (turbo) enabled/disabled, if + present; Bogomips on CPU; CPU microarchitecture + revision (if found, or + unless --admin, then shows as 'stepping')."], ['2', '-d', '', "Extra optical drive features data; adds rev version to - optical drive." ], + optical drive."], ['2', '-D', '', "HDD temp with disk data. Kernels >= 5.6: enable module drivetemp if not enabled. Older systems require hddtemp, run as as superuser, or as user if you have added hddtemp to /etc/sudoers - (sudo v. 1.7 or newer)(BSDs see doas). - Example:^<username>^ALL^=^NOPASSWD:^/usr/sbin/hddtemp" ], + (sudo v. 1.7 or newer)(or try doas). + Example:^<username>^ALL^=^NOPASSWD:^/usr/sbin/hddtemp"], ['2', '-E', '', "PCI/USB Bus ID of device, driver version, - LMP version." ], + LMP version."], ['2', '-G', '', "Specific vendor/product information (if relevant); PCI/USB ID of device; Direct rendering status (in X); Screen - number GPU is running on (Nvidia only)." ], + number GPU is running on (Nvidia only)."], ['2', '-i', '', "For IPv6, show additional scope addresses: Global, Site, - Temporary, Unknown. See --limit for large counts of IP addresses." ], + Temporary, Unknown. See --limit for large counts of IP addresses."], ['2', '-I', '', "Default system GCC. With -xx, also shows other installed GCC versions. If running in shell, not in IRC client, shows shell version number, if detected. Init/RC type and runlevel (if available). Total - count of all packages discovered in system and not -r." ], - ['2', '-j', '', "Add mapped: name if partition mapped." ], - ['2', '-J', '', "For Device: driver." ], - ['2', '-L', '', "For VG > LV, and other Devices, dm:" ], - ['2', '-m,--memory-modules', '', "Max memory module size (if available), device type." ], + count of all packages discovered in system and not -r."], + ['2', '-j', '', "Add mapped: name if partition mapped."], + ['2', '-J', '', "For Device: driver."], + ['2', '-L', '', "For VG > LV, and other Devices, dm:"], + ['2', '-m,--memory-modules', '', "Max memory module size (if available), + device type."], ['2', '-N', '', "Specific vendor/product information (if relevant); - PCI/USB ID of device; Version/port(s)/driver version (if available)." ], - ['2', '-o,-p,-P', '', "Add mapped: name if partition mapped." ], - ['2', '-r', '', "Packages, see -Ix." ], + PCI/USB ID of device; Version/port(s)/driver version (if available)."], + ['2', '-o,-p,-P', '', "Add mapped: name if partition mapped."], + ['2', '-r', '', "Packages, see -Ix."], ['2', '-R', '', "md-raid: second RAID Info line with extra data: blocks, chunk size, bitmap (if present). Resync line, shows blocks - synced/total blocks. Hardware RAID driver version, bus-ID." ], - ['2', '-s', '', "Basic voltages (ipmi, lm-sensors if present): 12v, 5v, 3.3v, vbat." ], + synced/total blocks. Hardware RAID driver version, bus-ID."], + ['2', '-s', '', "Basic voltages (ipmi, lm-sensors if present): 12v, 5v, 3.3v, + vbat."], ['2', '-S', '', "Kernel gcc version; system base of distro (if relevant - and detected)" ], + and detected)"], ['2', '-t', '', "Adds memory use output to CPU (-xt c), and CPU use to - memory (-xt m)." ], + memory (-xt m)."], ); if ($use{'weather'}){ push(@data, ['2', '-w,-W', '', "Wind speed and direction, humidity, pressure, - and time zone, if available." ]); + and time zone, if available."]); } push(@data, ['0', '', '', ''], ['1', '-xx', '--extra 2', "Show extra, extra data (only works with verbose - or line output, not short form):" ], - ['2', '-A', '', "Chip vendor:product ID for each audio device." ], - ['2', '-B', '', "Serial number." ], - ['2', '-C', '', "L1/L3 cache (if root and dmidecode installed)." ], + or line output, not short form):"], + ['2', '-A', '', "Chip vendor:product ID for each audio device."], + ['2', '-B', '', "Serial number."], ['2', '-D', '', "Disk transfer speed; NVMe lanes; Disk serial number; LVM - volume group free space (if available); disk duid (some BSDs)." ], - ['2', '-E', '', "Chip vendor:product ID, LMP subversion." ], + volume group free space (if available); disk duid (some BSDs)."], + ['2', '-E', '', "Chip vendor:product ID, LMP subversion."], ['2', '-G', '', "Chip vendor:product ID for each video device; OpenGL compatibility version, if free drivers and available; Xorg compositor; alternate Xorg drivers (if available). Alternate means driver is on automatic - driver check list of Xorg for the device vendor, but is not installed on system; - Xorg dpi." ], + driver check list of Xorg for the device vendor, but is not installed on + system; Xorg dpi."], ['2', '-I', '', "Other detected installed gcc versions (if present). System default runlevel. Adds parent program (or pty/tty) for shell info if not in IRC. Adds Init version number, RC (if found). Adds per package manager - installed package counts if not -r." ], - ['2', '-j,-p,-P', '', "Swap priority." ], - ['2', '-J', '', "Vendor:chip-ID." ], + installed package counts if not -r."], + ['2', '-j,-p,-P', '', "Swap priority."], + ['2', '-J', '', "Vendor:chip-ID."], ['2', '-L', '', "Show internal LVM volumes, like raid image/meta volumes; for LVM RAID, adds RAID report line (if not -R); show all components > - devices, number of 'c' or 'p' indicate depth of device." ], - ['2', '-m,--memory-modules', '', "Manufacturer, part number; single/double bank (if found)." ], - ['2', '-M', '', "Chassis info, BIOS ROM size (dmidecode only), if available." ], - ['2', '-N', '', "Chip vendor:product ID." ], - ['2', '-r', '', "Packages, see -Ixx." ], + devices, number of 'c' or 'p' indicate depth of device."], + ['2', '-m,--memory-modules', '', "Manufacturer, part number; single/double + bank (if found)."], + ['2', '-M', '', "Chassis info, BIOS ROM size (dmidecode only), if available."], + ['2', '-N', '', "Chip vendor:product ID."], + ['2', '-r', '', "Packages, see -Ixx."], ['2', '-R', '', "md-raid: Superblock (if present), algorithm. If resync, - shows progress bar. Hardware RAID Chip vendor:product ID." ], - ['2', '-s', '', "DIMM/SOC voltages (ipmi only)." ], + shows progress bar. Hardware RAID Chip vendor:product ID."], + ['2', '-s', '', "DIMM/SOC voltages (ipmi only)."], ['2', '-S', '', "Display manager (dm) in desktop output (e.g. kdm, gdm3, lightdm); active window manager if detected; desktop toolkit, - if available (Xfce/KDE/Trinity only)." ], - ['2', '--slots', '', "Slot length." ], + if available (Xfce/KDE/Trinity only)."], + ['2', '--slots', '', "Slot length."], ); if ($use{'weather'}){ push(@data, ['2', '-w,-W', '', "Snow, rain, precipitation, (last observed hour), - cloud cover, wind chill, dew point, heat index, if available." ] + cloud cover, wind chill, dew point, heat index, if available."] ); } push(@data, ['0', '', '', ''], ['1', '-xxx', '--extra 3', "Show extra, extra, extra data (only works - with verbose or line output, not short form):" ], - ['2', '-A', '', "Serial number, class ID." ], - ['2', '-B', '', "Chemistry, cycles, location (if available)." ], - ['2', '-C', '', "CPU voltage, external clock speed (if root and dmidecode installed)." ], - ['2', '-D', '', "Firmware rev. if available; partition scheme, in some cases; disk - type, rotation rpm (if available)." ], - ['2', '-E', '', "Serial number, class ID, HCI version and revision." ], - ['2', '-G', '', "Serial number, class ID." ], - ['2', '-I', '', "For 'Shell:' adds ([doas|su|sudo|login]) to shell name if present; - adds default shell+version if different; for 'running in:' adds (SSH) if SSH session; - adds wakeups: (from suspend) to Uptime." ], - ['2', '-J', '', "If present: Devices: serial number, interface count; USB speed; max power." ], - ['2', '-m,--memory-modules', '', "Width of memory bus, data and total (if present and greater - than data); Detail for Type, if present; module voltage, if available; serial - number." ], - ['2', '-N', '', "Serial number, class ID." ], + with verbose or line output, not short form):"], + ['2', '-A', '', "Serial number, class ID."], + ['2', '-B', '', "Chemistry, cycles, location (if available)."], + ['2', '-C', '', "CPU voltage, external clock speed (if root and dmidecode + installed); smt status, if available."], + ['2', '-D', '', "Firmware rev. if available; partition scheme, in some cases; + disk type, rotation rpm (if available)."], + ['2', '-E', '', "Serial number, class ID, HCI version and revision."], + ['2', '-G', '', "Serial number, class ID."], + ['2', '-I', '', "For 'Shell:' adds ([doas|su|sudo|login]) to shell name if + present; adds default shell+version if different; for 'running in:' adds (SSH) + if SSH session; adds wakeups: (from suspend) to Uptime."], + ['2', '-J', '', "If present: Devices: serial number, interface count; USB + speed; max power."], + ['2', '-m,--memory-modules', '', "Width of memory bus, data and total (if + present and greater than data); Detail for Type, if present; module voltage, + if available; serial number."], + ['2', '-N', '', "Serial number, class ID."], ['2', '-R', '', "zfs-raid: portion allocated (used) by RAID devices/arrays. - md-raid: system md-raid support types (kernel support, read ahead, RAID events). - Hardware RAID rev, ports, specific vendor/product information." ], - ['2', '-S', '', "Panel/tray/bar/dock info in desktop output, if in X (like lxpanel, - xfce4-panel, mate-panel); (if available) dm version number, window manager - version number, virtual terminal number."], + md-raid: system md-raid support types (kernel support, read ahead, RAID + events). Hardware RAID rev, ports, specific vendor/product information."], + ['2', '-S', '', "Panel/tray/bar/dock info in desktop output, if in X (like + lxpanel, xfce4-panel, mate-panel); (if available) dm version number, window + manager version number, virtual terminal number."], ); if ($use{'weather'}){ push(@data, ['2', '-w,-W', '', "Location (uses -z/irc filter), weather observation - time, altitude, sunrise/sunset, if available." ] + time, altitude, sunrise/sunset, if available."] ); } push(@data, - [0, '', '', "$line" ], - [0, '', '', "Additional Options:" ], - ['1', '-h', '--help', "This help menu." ], - ['1', '', '--recommends', "Checks $self_name application dependencies + recommends, - and directories, then shows what package(s) you need to install to add support - for that feature." ], + [0, '', '', "$line"], + [0, '', '', "Additional Options:"], + ['1', '-h', '--help', "This help menu."], + ['1', '', '--recommends', "Checks $self_name application dependencies + + recommends, and directories, then shows what package(s) you need to install + to add support for that feature."], ); if ($use{'update'}){ push(@data, - ['1', '-U', '--update', "Auto-update $self_name. Will also install/update man - page. Note: if you installed as root, you must be root to update, otherwise - user is fine. Man page installs require root. No arguments downloads from - main $self_name git repo." ], - ['1', '', '', "Use alternate sources for updating $self_name" ], - ['2', '1', '', "Get the git branch one version." ], - ['2', '2', '', "Get the git branch two version." ], - ['3', '3', '', "Get the dev server (smxi.org) version." ], + ['1', '-U', '--update', "Auto-update $self_name. Will also install/update + man page. Note: if you installed as root, you must be root to update, + otherwise user is fine. Man page installs require root. No arguments + downloads from main $self_name git repo."], + ['1', '', '', "Use alternate sources for updating $self_name"], + ['2', '1', '', "Get the git branch one version."], + ['2', '2', '', "Get the git branch two version."], + ['3', '3', '', "Get the dev server (smxi.org) version."], ['2', '<http>', '', "Get a version of $self_name from your own server. - Use the full download path, e.g.^$self_name^-U^https://myserver.com/inxi" ], + Use the full download path, e.g.^$self_name^-U^https://myserver.com/inxi"], ); } push(@data, - ['1', '-V', '--version', "Prints $self_name version info then exits." ], - ['0', '', '', "$line" ], - ['0', '', '', "Advanced Options:" ], - ['1', '', '--alt', "Trigger for various advanced options:" ], - ['2', '40', '', "Bypass Perl as a downloader option." ], - ['2', '41', '', "Bypass Curl as a downloader option." ], - ['2', '42', '', "Bypass Fetch as a downloader option." ], - ['2', '43', '', "Bypass Wget as a downloader option." ], + ['1', '-V', '--version', "Prints $self_name version info then exits."], + ['0', '', '', "$line"], + ['0', '', '', "Advanced Options:"], + ['1', '', '--alt', "Trigger for various advanced options:"], + ['2', '40', '', "Bypass Perl as a downloader option."], + ['2', '41', '', "Bypass Curl as a downloader option."], + ['2', '42', '', "Bypass Fetch as a downloader option."], + ['2', '43', '', "Bypass Wget as a downloader option."], ['2', '44', '', "Bypass Curl, Fetch, and Wget as downloader options. Forces - Perl if HTTP::Tiny present." ], - ['1', '', '--bt-tool', "[bt-adapter|hciconfig|rfkill] Force use of given tool for - bluetooth report." ], - ['1', '', '--dig', "Overrides configuration item NO_DIG (resets to default)." ], - ['1', '', '--display', "[:[0-9]] Try to get display data out of X (default: display 0)." ], - ['1', '', '--dmidecode', "Force use of dmidecode data instead of /sys where relevant - (e.g. -M, -B)." ], - ['1', '', '--downloader', "Force $self_name to use [curl|fetch|perl|wget] for downloads." ], - ['1', '', '--force', "[dmidecode|hddtemp|lsusb|meminfo|usb-sys|vmstat|wmctl]. 1 or more - in comma separated list. Force use of item(s). - See --hddtemp, --dmidecode, --wm, --usb-tool, --usb-sys." ], - ['1', '', '--hddtemp', "Force use of hddtemp for disk temps." ], - ['1', '', '--host', "Turn on hostname for -S." ], - ['1', '', '--html-wan', "Overrides configuration item NO_HTML_WAN (resets to default)." ], - ['1', '', '--limit', "[-1; 1-x] Set max output limit of IP addresses for -i - (default 10; -1 removes limit)." ], + Perl if HTTP::Tiny present."], + ['1', '', '--bt-tool', "[bt-adapter|hciconfig|rfkill] Force use of given tool + for bluetooth report."], + ['1', '', '--dig', "Overrides configuration item NO_DIG (resets to default)."], + ['1', '', '--display', "[:[0-9]] Try to get display data out of X (default: + display 0)."], + ['1', '', '--dmidecode', "Force use of dmidecode data instead of /sys where + relevant + (e.g. -M, -B)."], + ['1', '', '--downloader', "Force $self_name to use [curl|fetch|perl|wget] for + downloads."], + ['1', '', '--force', "[dmidecode|hddtemp|lsusb|meminfo|usb-sys|vmstat|wmctrl]. + 1 or more in comma separated list. Force use of item(s). + See --hddtemp, --dmidecode, --wm, --usb-tool, --usb-sys."], + ['1', '', '--hddtemp', "Force use of hddtemp for disk temps."], + ['1', '', '--html-wan', "Overrides configuration item NO_HTML_WAN (resets to + default)."], ); if ($use{'update'}){ push(@data, - ['1', '', '--man', "Install correct man version for dev branch (-U 3) or pinxi using -U." ], + ['1', '', '--man', "Install correct man version for dev branch (-U 3) or + pinxi using -U."], ); } push(@data, - ['1', '', '--no-dig', "Skip dig for WAN IP checks, use downloader program." ], - ['1', '', '--no-doas', "Skip internal program use of doas features (not related - to starting $self_name with doas)." ], - ['1', '', '--no-host', "Turn off hostname for -S. Useful if showing output from servers etc. - -z triggers --no-host." ], - ['1', '', '--no-html-wan', "Skip HTML IP sources for WAN IP checks, use dig only, - or nothing if --no-dig." ], + ['1', '', '--no-dig', "Skip dig for WAN IP checks, use downloader program."], + ['1', '', '--no-doas', "Skip internal program use of doas features (not + related to starting $self_name with doas)."], + ['1', '', '--no-html-wan', "Skip HTML IP sources for WAN IP checks, use dig + only, or nothing if --no-dig."], ); if ($use{'update'}){ push(@data, - ['1', '', '--no-man', "Disable man install for all -U update actions." ], + ['1', '', '--no-man', "Disable man install for all -U update actions."], ); } push(@data, ['1', '', '--no-ssl', "Skip SSL certificate checks for all downloader actions - (Wget/Fetch/Curl/Perl-HTTP::Tiny)." ], - ['1', '', '--no-sudo', "Skip internal program use of sudo features (not related - to starting $self_name with sudo)." ], - ['1', '', '--output', "[json|screen|xml] Change data output type. Requires --output-file - if not screen." ], - ['1', '', '--output-file', "[Full filepath|print] Output file to be used for --output." ], - ['1', '', '--partition-sort', "[dev-base|fs|id|label|percent-used|size|uuid|used] - Change sort order of ${partition_string} output. See man page for specifics." ], - ['1', '', '--pkg', "Force use of disabled package manager counts for packages feature. - RPM disabled by default due to possible massive rpm package query times." ], - ['1', '', '--sensors-default', "Removes configuration item SENSORS_USE and SENSORS_EXCLUDE. - Same as default behavior." ], - ['1', '', '--sensors-exclude', "[sensor[s] name, comma separated] Exclude supplied sensor - array[s] for -s output (lm-sensors, Linux only)." ], - ['1', '', '--sensors-use', "[sensor[s] name, comma separated] Use only supplied sensor - array[s] for -s output (lm-sensors, Linux only)." ], + (Wget/Fetch/Curl/Perl-HTTP::Tiny)."], + ['1', '', '--no-sudo', "Skip internal program use of sudo features (not + related to starting $self_name with sudo)."], + ['1', '', '--pkg', "Force use of disabled package manager counts for packages + feature. RPM disabled by default due to possible massive rpm package query + times."], + ['1', '', '--sensors-default', "Removes configuration item SENSORS_USE and + SENSORS_EXCLUDE. Same as default behavior."], + ['1', '', '--sensors-exclude', "[sensor[s] name, comma separated] Exclude + supplied sensor array[s] for -s output (lm-sensors, Linux only)."], + ['1', '', '--sensors-use', "[sensor[s] name, comma separated] Use only + supplied sensor array[s] for -s output (lm-sensors, Linux only)."], ['1', '', '--sleep', "[0-x.x] Change CPU sleep time, in seconds, for -C (default:^$cpu_sleep). Allows system to catch up and show a more accurate CPU - use. Example:^$self_name^-Cxxx^--sleep^0.15" ], - ['1', '', '--tty', "Forces irc flag to false. Generally useful if $self_name is running - inside of another tool like Chef or MOTD and returns corrupted color codes. Please see - man page or file an issue if you need to use this flag. Must use -y [width] option if - you want a specific output width. Always put this option first in an option list."], - ['1', '', '--usb-sys', "Force USB data to use only /sys as data source (Linux only)." ], + use. Example:^$self_name^-Cxxx^--sleep^0.15"], + ['1', '', '--tty', "Forces irc flag to false. Generally useful if $self_name + is running inside of another tool like Chef or MOTD and returns corrupted + color codes. Please see man page or file an issue if you need to use this + flag. Must use -y [width] option if you want a specific output width. Always + put this option first in an option list. See -Z for disabling output filters + as well."], + ['1', '', '--usb-sys', "Force USB data to use only /sys as data source (Linux + only)."], ['1', '', '--usb-tool', "Force USB data to use lsusb as data source [default] - (Linux only)." ], + (Linux only)."], ['1', '', '--wan-ip-url', "[URL] Skips dig, uses supplied URL for WAN IP (-i). URL output must end in the IP address. See man. - Example:^$self_name^-i^--wan-ip-url^https://yoursite.com/ip.php" ], - ['1', '', '--wm', "Force wm: to use wmctrl as data source. Default uses ps." ], - ['1', '', '--wrap-max', "Set maximum width where $self_name autowraps line starters - (previously --indent-min). Current: $size{'wrap-max'}" ], + Example:^$self_name^-i^--wan-ip-url^https://yoursite.com/ip.php"], + ['1', '', '--wm', "Force wm: to use wmctrl as data source. Default uses ps."], ['0', '', '', $line ], - ['0', '', '', "Debugging Options:" ], - ['1', '', '--dbg', "Specific debuggers, change often. Only 1 is constant:" ], - ['2', '1', '', "Show downloader output. Turns off quiet mode." ], - ['1', '', '--debug', "Triggers debugging modes." ], - ['2', '1-3', '', "On screen debugger output." ], - ['2', '10', '', "Basic logging." ], - ['2', '11', '', "Full file/system info logging." ], - ['1', '', ,'', "The following create a tar.gz file of system data, plus $self_name - output. To automatically upload debugger data tar.gz file - to ftp.smxi.org: $self_name^--debug^21" ], - ['2', '20', '', "Full system data collection: /sys; xorg conf and log data, xrandr, - xprop, xdpyinfo, glxinfo etc.; data from dev, disks, - ${partition_string}s, etc." ], + ['0', '', '', "Debugging Options:"], + ['1', '', '--dbg', "[1-xx] Specific debuggers, change often. See man page."], + ['2', '1', '', "Show downloader output. Turns off quiet mode."], + ['1', '', '--debug', "[1-3|10|11|20-22] Triggers debugging modes."], + ['2', '1-3', '', "On screen debugger output."], + ['2', '10', '', "Basic logging."], + ['2', '11', '', "Full file/system info logging."], + ['1', '', ,'', "The following create a tar.gz file of system data, plus + $self_name output. To automatically upload debugger data tar.gz file to + ftp.smxi.org: $self_name^--debug^21"], + ['2', '20', '', "Full system data collection: /sys; xorg conf and log data, + xrandr, xprop, xdpyinfo, glxinfo etc.; data from dev, disks, + ${partition_string}s, etc."], ['2', '21', '', "Upload debugger dataset to $self_name debugger server - automatically, removes debugger data directory, leaves tar.gz debugger file." ], + automatically, removes debugger data directory, leaves tar.gz debugger file."], ['2', '22', '', "Upload debugger dataset to $self_name debugger server - automatically, removes debugger data directory and debugger tar.gz file." ], - # ['1', '', '--debug-filter', "Add -z flag to debugger $self_name optiions." ], - ['1', '', '--debug-proc', "Force debugger parsing of /proc as sudo/doas/root." ], - ['1', '', '--debug-proc-print', "To locate file that /proc debugger hangs on." ], - ['1', '', '--debug-no-exit', "Skip exit on error to allow completion." ], - ['1', '', '--debug-no-proc', "Skip /proc debugging in case of a hang." ], - ['1', '', '--debug-no-sys', "Skip /sys debugging in case of a hang." ], - ['1', '', '--debug-sys', "Force PowerPC debugger parsing of /sys as sudo/doas/root." ], - ['1', '', '--debug-sys-print', "To locate file that /sys debugger hangs on." ], - ['1', '', '--ftp', "Use with --debugger 21 to trigger an alternate FTP server for upload. - Format:^[ftp.xx.xx/yy]. Must include a remote directory to upload to. - Example:^$self_name^--debug^21^--ftp^ftp.myserver.com/incoming" ], - ['0', '', '', "$line" ], + automatically, removes debugger data directory and debugger tar.gz file."], + # ['1', '', '--debug-filter', "Add -z flag to debugger $self_name optiions."], + ['1', '', '--debug-id', "[short-string] Add given string to debugger file + name. Helps identify source of debugger dataset. Use with --debug 20-22."], + ['1', '', '--debug-proc', "Force debugger parsing of /proc as sudo/doas/root."], + ['1', '', '--debug-proc-print', "To locate file that /proc debugger hangs on."], + ['1', '', '--debug-no-exit', "Skip exit on error to allow completion."], + ['1', '', '--debug-no-proc', "Skip /proc debugging in case of a hang."], + ['1', '', '--debug-no-sys', "Skip /sys debugging in case of a hang."], + ['1', '', '--debug-sys', "Force PowerPC debugger parsing of /sys as + sudo/doas/root."], + ['1', '', '--debug-sys-print', "To locate file that /sys debugger hangs on."], + ['1', '', '--ftp', "Use with --debugger 21 to trigger an alternate FTP server + for upload. Format:^[ftp.xx.xx/yy]. Must include a remote directory to upload + to. Example:^$self_name^--debug^21^--ftp^ftp.myserver.com/incoming"], + ['0', '', '', "$line"], ); print_basic(\@data); exit 0; # shell true @@ -5782,7 +5913,7 @@ sub set { eval $start if $b_log; main::set_ps_aux() if !$loaded{'ps-aux'}; if (!$b_irc){ - # we'll run get_shell_data for -I, but only then + # we'll run ShellData::set() for -I, but only then } else { $use{'filter'} = 1; @@ -5953,6 +6084,7 @@ sub get_client_version { $client{'name-print'} = $client{'name'}; } $b_irc = 0; + $use{'filter'} = 0; } else { $client{'name-print'} = 'Unknown Client: ' . $client{'name'}; @@ -6081,7 +6213,6 @@ sub check_modern_konvi { eval $end if $b_log; return $b_modern_konvi; } - sub set_konvi_data { eval $start if $b_log; my $config_tool = ''; @@ -6124,39 +6255,25 @@ sub set_konvi_data { ######################################################################## #### ------------------------------------------------------------------- -#### FILTERS AND TOOLS +#### CLEANERS, FILTERS, AND TOOLS #### ------------------------------------------------------------------- -sub apply_filter { - my ($string) = @_; - if ($string){ - $string = ($use{'filter'}) ? $filter_string : $string; - } - else { - $string = 'N/A'; - } - return $string; -} - -# note, let the print logic handle N/A cases -sub apply_partition_filter { - my ($source,$string,$type) = @_; - return $string if !$string || $string eq 'N/A'; - if ($source eq 'system'){ - my $test = ($type eq 'label') ? '=LABEL=': '=UUID='; - $string =~ s/$test[^\s]+/$test$filter_string/g; - } - else { - $string = $filter_string; - } - return $string; +sub clean { + my ($item) = @_; + return $item if !$item;# handle cases where it was 0 or '' + # note: |nee trips engineering, but I don't know why nee was filtered + $item =~ s/chipset|company|components|computing|computer|corporation|communications|electronics|electrical|electric|gmbh|group|incorporation|industrial|international|\bnee\b|no\sstring|revision|semiconductor|software|technologies|technology|ltd\.|<ltd>|\bltd\b|inc\.|<inc>|\binc\b|intl\.|co\.|<co>|corp\.|<corp>|\(tm\)|\(r\)|®|\(rev ..\)|\'|\"|\sinc\s*$|\?//gi; + $item =~ s/,|\*/ /g; + $item =~ s/^\s+|\s+$//g; + $item =~ s/\s\s+/ /g; + return $item; } -sub arm_cleaner { +sub clean_arm { my ($item) = @_; $item =~ s/(\([^\(]*Device Tree[^\)]*\))//gi; - $item =~ s/\s\s+/ /g; $item =~ s/^\s+|\s+$//g; + $item =~ s/\s\s+/ /g; return $item; } @@ -6172,49 +6289,122 @@ sub clean_characters { return $data; } -sub cleaner { - my ($item) = @_; - return $item if !$item;# handle cases where it was 0 or '' - # note: |nee trips engineering, but I don't know why nee was filtered - $item =~ s/chipset|company|components|computing|computer|corporation|communications|electronics|electrical|electric|gmbh|group|incorporation|industrial|international|\bnee\b|no\sstring|revision|semiconductor|software|technologies|technology|ltd\.|<ltd>|\bltd\b|inc\.|<inc>|\binc\b|intl\.|co\.|<co>|corp\.|<corp>|\(tm\)|\(r\)|®|\(rev ..\)|\'|\"|\sinc\s*$|\?//gi; - $item =~ s/,|\*/ /g; - $item =~ s/\s\s+/ /g; - $item =~ s/^\s+|\s+$//g; - return $item; -} - -sub disk_cleaner { +sub clean_disk { my ($item) = @_; return $item if !$item; # <?unknown>?| $item =~ s/vendor.*|product.*|O\.?E\.?M\.?//gi; - $item =~ s/\s\s+/ /g; $item =~ s/^\s+|\s+$//g; + $item =~ s/\s\s+/ /g; return $item; } -sub dmi_cleaner { +sub clean_dmi { my ($string) = @_; - my $cleaner = '^Base Board .*|^Chassis .*|empty|Undefined.*|.*O\.E\.M\..*|.*OEM.*|^Not .*'; - $cleaner .= '|^System .*|.*unknow.*|.*N\/A.*|none|^To be filled.*|^0x[0]+$'; - $cleaner .= '|\[Empty\]|<Bad Index>|<OUT OF SPEC>|Default string|^\.\.$|Manufacturer.*'; - $cleaner .= '|AssetTagNum|Manufacturer| Or Motherboard|PartNum.*|\bOther\b.*|SerNum'; - $string =~ s/$cleaner//i; - $string =~ s/^\s+|\bbios\b|\bacpi\b|\s+$//gi; + $string = clean_unset($string,'AssetTagNum|^Base Board .*|^Chassis .*|' . + 'Manufacturer.*| Or Motherboard|\bOther\b.*|PartNum.*|SerNum|' . + '^System .*|^0x[0]+$'); + $string =~ s/\bbios\b|\bacpi\b//gi; $string =~ s/http:\/\/www.abit.com.tw\//Abit/i; + $string =~ s/^[\s'"]+|[\s'"]+$//g; $string =~ s/\s\s+/ /g; - $string =~ s/^\s+|\s+$//g; $string = remove_duplicates($string) if $string; return $string; } -sub general_cleaner { +sub clean_pci { + my ($string,$type) = @_; + # print "st1 $type:$string\n"; + my $filter = 'and\ssubsidiaries|compatible\scontroller|'; + $filter .= '\b(device|controller|connection|multimedia)\b|\([^)]+\)'; + # \[[^\]]+\]$| not trimming off ending [...] initial type filters removes end + $filter = '\[[^\]]+\]$|' . $filter if $type eq 'pci'; + $string =~ s/($filter)//ig; + $string =~ s/^[\s'"]+|[\s'"]+$//g; + $string =~ s/\s\s+/ /g; + # print "st2 $type:$string\n"; + $string = remove_duplicates($string) if $string; + return $string; +} + +sub clean_pci_subsystem { my ($string) = @_; - my $cleaner = '\b(defauult string|empty|none|undefined.*|unknown|unspecified)\b'; - $string =~ s/$cleaner//i; + # we only need filters for features that might use vendor, -AGN + my $filter = 'and\ssubsidiaries|adapter|(hd\s)?audio|definition|desktop|ethernet|'; + $filter .= 'gigabit|graphics|hdmi(\/[\S]+)?|high|integrated|motherboard|network|onboard|'; + $filter .= 'raid|pci\s?express'; + $string =~ s/\b($filter)\b//ig; + $string =~ s/^[\s'"]+|[\s'"]+$//g; + $string =~ s/\s\s+/ /g; return $string; } +# Use sparingly, but when we need regex type stuff +# stripped out for reliable string compares, it's better. +# sometimes the pattern comes from unknown strings +# which can contain regex characters, get rid of those +sub clean_regex { + my ($string) = @_; + return if !$string; + $string =~ s/(\{|\}|\(|\)|\[|\]|\|)/ /g; + $string =~ s/^\s+|\s+$//g; + $string =~ s/\s\s+/ /g; + return $string; +} + +# $extra optional, if you want to add custom filter to defaults +sub clean_unset { + my ($string,$extra) = @_; + my $cleaner = '^(\.)+$|Bad Index|default string|\[?empty\]?|\bnone\b|N\/A|^not |'; + $cleaner .= 'not set|OUT OF SPEC|To be filled|O\.?E\.?M|undefine|unknow|unspecif'; + $cleaner .= '|' . $extra if $extra; + $string =~ s/.*($cleaner).*//i; + return $string; +} + +sub filter { + my ($string) = @_; + if ($string){ + if ($use{'filter'} && $string ne message('root-required')){ + $string = $filter_string; + } + } + else { + $string = 'N/A'; + } + return $string; +} + +# note, let the print logic handle N/A cases +sub filter_partition { + my ($source,$string,$type) = @_; + return $string if !$string || $string eq 'N/A'; + if ($source eq 'system'){ + my $test = ($type eq 'label') ? '=LABEL=': '=UUID='; + $string =~ s/$test[^\s]+/$test$filter_string/g; + } + else { + $string = $filter_string; + } + return $string; +} + +sub filter_pci_long { + my ($string) = @_; + if ($string =~ /\[AMD(\/ATI)?\]/){ + $string =~ s/Advanced\sMicro\sDevices\s\[AMD(\/ATI)?\]/AMD/; + } + return $string; +} + +# args: list of values, return the first one that is defined +sub get_defined { + for (@_){ + return $_ if defined $_; + } + return; # don't return undef explicitly, only implicitly! +} + # args: $1 - vendor id; $2 - product id # returns print ready vendor:chip id string, or na variants sub get_chip_id { @@ -6290,75 +6480,11 @@ sub increment_starters { return $result; } -sub pci_cleaner { - my ($string,$type) = @_; - # print "st1 $type:$string\n"; - my $filter = 'and\ssubsidiaries|compatible\scontroller|'; - $filter .= '\b(device|controller|connection|multimedia)\b|\([^)]+\)'; - # \[[^\]]+\]$| not trimming off ending [...] initial type filters removes end - $filter = '\[[^\]]+\]$|' . $filter if $type eq 'pci'; - $string =~ s/($filter)//ig; - $string =~ s/\s\s+/ /g; - $string =~ s/^\s+|\s+$//g; - # print "st2 $type:$string\n"; - $string = remove_duplicates($string) if $string; - return $string; -} - -sub pci_cleaner_subsystem { - my ($string) = @_; - # we only need filters for features that might use vendor, -AGN - my $filter = 'and\ssubsidiaries|adapter|(hd\s)?audio|definition|desktop|ethernet|'; - $filter .= 'gigabit|graphics|hdmi(\/[\S]+)?|high|integrated|motherboard|network|onboard|'; - $filter .= 'raid|pci\s?express'; - $string =~ s/\b($filter)\b//ig; - $string =~ s/\s\s+/ /g; - $string =~ s/^\s+|\s+$//g; - return $string; -} - -sub pci_long_filter { - my ($string) = @_; - if ($string =~ /\[AMD(\/ATI)?\]/){ - $string =~ s/Advanced\sMicro\sDevices\s\[AMD(\/ATI)?\]/AMD/; - } - return $string; -} - -# Use sparingly, but when we need regex type stuff -# stripped out for reliable string compares, it's better. -# sometimes the pattern comes from unknown strings -# which can contain regex characters, get rid of those -sub regex_cleaner { - my ($string) = @_; - return if !$string; - $string =~ s/(\{|\}|\(|\)|\[|\]|\|)/ /g; - $string =~ s/\s\s+/ /g; - $string =~ s/^\s+|\s+$//g; - return $string; -} - -sub remove_duplicates { - my ($string) = @_; - return if !$string; - my $holder = ''; - my (@temp); - foreach (split(/\s+/, $string)){ - if ($holder ne $_){ - push(@temp, $_); - } - $holder = $_; - } - $string = join(' ', @temp); - return $string; -} - -sub row_defaults { +sub message { my ($type,$id) = @_; $id ||= ''; my %unfound = ( 'arm-cpu-f' => 'Use -f option to see features', - 'arm-pci' => 'No ARM data found for this feature.', 'battery-data' => 'No system battery data found. Is one present?', 'battery-data-bsd' => 'No battery data found. Try with --dmidecode', 'battery-data-sys' => 'No /sys data found.', @@ -6367,6 +6493,7 @@ sub row_defaults { 'cpu-bugs-null' => 'No CPU vulnerability/bugs data available.', 'cpu-model-null' => 'Model N/A', 'cpu-speeds' => 'No per core speed data found.', + 'cpu-speeds-bsd' => 'No OS support for core speeds.', 'darwin-feature' => 'Feature not supported iu Darwin/OSX.', 'disk-data' => 'No disk data found.', 'disk-data-bsd' => 'No disk data found.', @@ -6394,11 +6521,12 @@ sub row_defaults { 'machine-data-bsd' => 'No machine data: Is dmidecode installed? Try -M --dmidecode.', 'machine-data-dmidecode' => 'No machine data: try newer kernel. Is dmidecode installed? Try -M --dmidecode.', 'machine-data-force-dmidecode' => 'No machine data: try newer kernel. Is dmidecode installed? Try -M --dmidecode.', - 'mips-pci' => 'No MIPS data found for this feature.', 'note-check' => 'check', 'note-est' => 'est.', 'optical-data' => 'No optical or floppy data found.', 'optical-data-bsd' => 'No optical or floppy data found.', + 'output-control' => "-:: 'Enter' to continue to next block. Any key + 'Enter' to exit:", + 'output-control-exit' => 'Exiting output. Have a nice day.', 'output-limit' => "Output throttled. IPs: $id; Limit: $limit; Override: --limit [1-x;-1 all]", 'package-data' => 'No packages detected. Unsupported package manager?', 'partition-data' => 'No partition data found.', @@ -6416,6 +6544,7 @@ sub row_defaults { 'recommends' => 'see --recommends', 'repo-data', "No repo data detected. Does $self_name support your package manager?", 'repo-data-bsd', "No repo data detected. Does $self_name support $id?", + 'risc-pci' => 'No ' . uc($id) . ' data found for this feature.', 'root-feature' => 'Feature requires superuser permissions.', 'root-item-incomplete' => "Full $id report requires superuser permissions.", 'root-required' => '<superuser required>', @@ -6441,10 +6570,13 @@ sub row_defaults { 'tool-unknown-error' => "Unknown $id error. Unable to generate data.", 'tools-missing' => "This feature requires one of these tools: $id", 'tools-missing-bsd' => "This feature requires one of these tools: $id", + 'undefined' => '<undefined>', 'unmounted-data' => 'No unmounted partitions found.', 'unmounted-data-bsd' => "Unmounted partition feature unsupported in $id.", 'unmounted-file' => 'No /proc/partitions file found.', + 'unsupported' => '<unsupported>', 'usb-data' => 'No USB data found. Server?', + 'unknown-cpu-topology' => 'ERR-103', 'unknown-desktop-version' => 'ERR-101', 'unknown-dev' => 'ERR-102', 'unknown-shell' => 'ERR-100', @@ -6454,6 +6586,34 @@ sub row_defaults { return $unfound{$type}; } +# string of range types (2-5; 3 4; 3,4,2-12) to generate single regex string for +sub regex_range { + return if ! defined $_[0]; + my @processed; + foreach my $item (split(/[,\s]+/,$_[0])){ + if ($item =~ /(\d+)-(\d+)/){ + $item = join('|',($1..$2)); + } + push(@processed,$item); + } + return join('|',@processed); +} + +sub remove_duplicates { + my ($string) = @_; + return if !$string; + my $holder = ''; + my (@temp); + foreach (split(/\s+/, $string)){ + if ($holder ne $_){ + push(@temp, $_); + } + $holder = $_; + } + $string = join(' ', @temp); + return $string; +} + # convert string passed to KB, based on GB/MB/TB id # NOTE: K 1024 KB 1000 KiB 1024 # The logic will turn false MB to M for this tool @@ -6593,6 +6753,18 @@ sub key { return sprintf("%03d#%s#%s#%s", $_[0],$_[1],$_[2],$_[3]); } +sub output_control { + print message('output-control'); + chomp(my $response = <STDIN>); + if (!$response){ + $size{'lines'} = 1; + } + else { + print message('output-control-exit'), "\n"; + exit 0; + } +} + sub print_basic { my ($data) = @_; my $indent = 18; @@ -6603,11 +6775,10 @@ sub print_basic { my $indent2 = 8; my $length = @$data; my ($start,$i,$j,$line); - - if ($size{'max'} > 110){ + if ($size{'max-cols'} > 110){ $indent_static = 22; } - elsif ($size{'max'} < 90){ + elsif ($size{'max-cols'} < 90){ $indent_static = 15; } # print $length . "\n"; @@ -6640,7 +6811,7 @@ sub print_basic { $start = ''; # print "1-print.\n"; } - if (($indent + length($data->[$i][3])) < $size{'max'}){ + if (($indent + length($data->[$i][3])) < $size{'max-cols'}){ $data->[$i][3] =~ s/\^/ /g; $line = sprintf("%-${indent}s%s\n", "$start", $data->[$i][3]); print_line($line); @@ -6653,12 +6824,12 @@ sub print_basic { # then splits like awk, on one or more white spaces. foreach my $word (split(' ', $data->[$i][3])){ # print "$word\n"; - if (($indent + length($holder) + length($word)) < $size{'max'}){ + if (($indent + length($holder) + length($word)) < $size{'max-cols'}){ $word =~ s/\^/ /g; $holder .= $word . $sep; # print "3-hold.\n"; } - # elsif (($indent + length($holder) + length($word)) >= $size{'max'}){ + # elsif (($indent + length($holder) + length($word)) >= $size{'max-cols'}){ else { $line = sprintf("%-${indent}s%s\n", "$start", $holder); print_line($line); @@ -6682,26 +6853,31 @@ sub print_basic { # hash key to force sorts. sub print_data { my ($data) = @_; - my ($array,$counter,$length,$split_count) = (0,0,0,0); + my ($counter,$length,$split_count) = (0,0,0); my ($hash_id,$holder,$start,$start2,$start_holder) = ('','','','',''); my $indent = $size{'indent'}; - my (@temp,@working,@values,%ids,%row); - my ($holder2,$key,$line,$val2,$val3); + my (%ids); + my ($b_container,$b_ni2,$holder2,$key,$line,$val2,$val3); # these 2 sets are single logic items - my $b_single = ($size{'max'} == 1) ? 1: 0; - my ($b_container,$indent_use,$indentx) = (0,0,0); - # $size{'max'} = 88; + my $b_single = ($size{'max-cols'} == 1) ? 1: 0; + my ($b_row1,$indent_2,$indent_use,$indentx) = (1,0,0,0); + # $size{'max-cols'} = 88; # NOTE: indent < 11 would break the output badly in some cases - if ($size{'max'} < $size{'wrap-max'} || $size{'indent'} < 11){ - $indent = 2; + if ($size{'max-cols'} < $size{'max-wrap'} || $size{'indent'} < 11){ + $indent = $size{'indents'}; } - # foreach my $key1 (sort { (split('#', $a))[0] <=> (split('#', $b))[0] } keys %$data){ foreach my $key1 (sort { substr($a,0,3) <=> substr($b,0,3) } keys %$data){ - # foreach my $key1 (sort { $a cmp $b } keys %$data){ $key = (split('#', $key1))[3]; + $b_row1 = 1; if ($key ne 'SHORT'){ $start = sprintf("$colors{'c1'}%-${indent}s$colors{'cn'}","$key$sep{'s1'}"); + if ($use{'output-block'}){ + output_control() if $use{'output-block'} > 1; + $use{'output-block'}++; + } $start_holder = $key; + $indent_2 = $indent + $size{'indents'}; + $b_ni2 = ($start_holder eq 'Info') ? 1 : 0; if ($indent < 10){ $line = "$start\n"; print_line($line); @@ -6713,7 +6889,6 @@ sub print_data { $indent = 0; } next if ref($data->{$key1}) ne 'ARRAY'; - # @working = @{$data->{$key1}}; # Line starters that will be -x incremented always # It's a tiny bit faster manually resetting rather than using for loop %ids = ( @@ -6734,13 +6909,16 @@ sub print_data { 'variant' => 1, # arm > 1 cpu type ); foreach my $val1 (@{$data->{$key1}}){ - $indent_use = $length = $indent; if (ref($val1) eq 'HASH'){ - #%row = %$val1; - ($counter,$split_count) = (0,0); - # foreach my $key2 (sor ({ (split('#', $a))[0] <=> (split('#', $b))[0] } keys %$val1){ - foreach my $key2 (sort { substr($a,0,3) <=> substr($b,0,3) } keys %$val1){ - # foreach my $key2 (sort { $a cmp $b } keys %$val1){ + if (!$b_single){ + $indent_use = $length = ($b_row1) ? $indent : $indent_2; + } + ($counter,$b_row1,$split_count) = (0,1,0); + foreach my $key2 (sort {substr($a,0,3) <=> substr($b,0,3)} keys %$val1){ + if (!$b_single){ + $indent_use = ($b_row1 || $b_ni2) ? $indent: $indent_2; + } + # print "m-1: r1: $b_row1 iu: $indent_use\n"; ($hash_id,$b_container,$indentx,$key) = (split('#', $key2)); if ($start_holder eq 'Graphics' && $key eq 'Screen'){ $ids{'Monitor'} = 1; @@ -6765,39 +6943,52 @@ sub print_data { if (!$b_single && $val2 || $val2 eq '0'){ $val2 .= " "; } - # see: Use of implicit split to @_ is deprecated. Only get this warning - # in Perl 5.08 oddly enough. - @temp = split(/\s+/, $val2); + # see: Use of implicit split to @_ is deprecated. Only get this + # warning in Perl 5.08 oddly enough. ie, no: scalar (split(...)); + my @temp = split(/\s+/, $val2); $split_count = scalar @temp; - if (!$b_single && (length("$key$sep{'s2'} $val2") + $length) < $size{'max'}){ - # print "one\n"; + if (!$b_single && + (length("$key$sep{'s2'} $val2") + $length) < $size{'max-cols'}){ + # print "h-1: r1: $b_row1 iu: $indent_use\n"; $length += length("$key$sep{'s2'} $val2"); $holder .= "$colors{'c1'}$key$sep{'s2'}$colors{'c2'} $val2"; } - # handle case where the opening key/value pair is > max, and where - # there are a lot of terms, like cpu flags, raid types supported. Raid - # can have the last row have a lot of devices, or many raid types - elsif (!$b_single && (length("$key$sep{'s2'} $val2") + $indent) > $size{'max'} && - !defined $ids{$key} && $split_count > 2){ - # print "two\n"; - @values = split(/\s+/, $val2); + # handle case where the key/value pair is > max, and where there are + # a lot of terms, like cpu flags, raid types supported. Raid can have + # the last row have a lot of devices, or many raid types + elsif (!$b_single && + (length("$key$sep{'s2'} $val2") + $indent_use) > $size{'max-cols'} && + !defined $ids{$key} && $split_count > 2){ + # print "m-2 r1: $b_row1 iu: $indent_use\n"; + my @values = split(/\s+/, $val2); $val3 = shift @values; - # $length += length("$key$sep{'s2'} $val3 ") + $indent; $start2 = "$colors{'c1'}$key$sep{'s2'}$colors{'c2'} $val3 "; $holder2 = ''; + # case where not first item in line, but when key+first word added, + # is wider than max width. + if ($holder && + ($length + length("$key$sep{'s2'} $val3")) > $size{'max-cols'}){ + # print "p-1a r1: $b_row1 iu: $indent_use\n"; + $holder =~ s/\s+$//; + $line = sprintf("%-${indent_use}s%s$colors{'cn'}\n","$start","$holder"); + print_line($line); + $b_row1 = 0; + $start = ''; + $holder = ''; + $length = $indent_use; + } $length += length("$key$sep{'s2'} $val3 "); # print scalar @values,"\n"; foreach (@values){ # my $l = (length("$_ ") + $length); # print "$l\n"; - if ((length("$_ ") + $length) < $size{'max'}){ - # print "three.1\n"; + $indent_use = ($b_row1) ? $indent : $indent_2; + if ((length("$_ ") + $length) < $size{'max-cols'}){ + # print "h-2: r1: $b_row1 iu: $indent_use\n"; # print "a\n"; if ($start2){ $holder2 .= "$start2$_ "; $start2 = ''; - #$length += $length2; - #$length2 = 0; } else { $holder2 .= "$_ "; @@ -6805,7 +6996,7 @@ sub print_data { $length += length("$_ "); } else { - # print "three.2\n"; + # print "p-1b: r1: $b_row1 iu: $indent_use\n"; if ($start2){ $holder2 = "$start2$holder2"; } @@ -6814,57 +7005,63 @@ sub print_data { } # print "xx:$holder"; $holder2 =~ s/\s+$//; - $line = sprintf("%-${indent}s%s$colors{'cn'}\n","$start","$holder$holder2"); + $line = sprintf("%-${indent_use}s%s$colors{'cn'}\n","$start","$holder$holder2"); print_line($line); + $b_row1 = 0; $holder = ''; $holder2 = "$_ "; # print "h2: $holder2\n"; - $length = length($holder2) + $indent; + $length = length($holder2) + $indent_use; $start2 = ''; $start = ''; - #$length2 = 0; } } if ($holder2 !~ /^\s*$/){ - # print "four\n"; + # print "p-2: r1: $b_row1 iu: $indent_use\n"; $holder2 =~ s/\s+$//; $holder2 = "$colors{'c2'}$holder2"; - $line = sprintf("%-${indent}s%s$colors{'cn'}\n","$start","$holder$holder2"); + $line = sprintf("%-${indent_use}s%s$colors{'cn'}\n","$start","$holder$holder2"); print_line($line); + $b_row1 = 0; $holder = ''; $holder2 = ''; - $length = $indent; + $length = $indent_use; $start2 = ''; $start = ''; - #$length2 = 0; } } # NOTE: only these and the last fallback are used for b_single output else { - # print "H: $counter " . scalar %$val1 . " $indent3 $indent2\n"; if ($holder){ - # print "five\n"; + # print "p-3: r1: $b_row1 iu: $indent_use\n"; $holder =~ s/\s+$//; $line = sprintf("%-${indent_use}s%s$colors{'cn'}\n",$start,"$holder"); $length = length("$key$sep{'s2'} $val2") + $indent_use; print_line($line); + $b_row1 = 0; $start = ''; } else { - # print "six\n"; + # print "h-3a: r1: $b_row1 iu: $indent_use\n"; $length = $indent_use; - #$holder = ''; + } + if ($b_single){ + $indent_use = ($indent * $indentx); + } + else { + $indent_use = ($b_row1 || $b_ni2) ? $indent: $indent_2; } $holder = "$colors{'c1'}$key$sep{'s2'}$colors{'c2'} $val2"; + # print "h-3b: r1: $b_row1 iu: $indent_use\n"; } $counter++; - $indent_use = ($indent * $indentx) if $b_single; } if ($holder !~ /^\s*$/){ - # print "seven\n"; + # print "p-4: r1: $b_row1 iu: $indent_use\n"; $holder =~ s/\s+$//; $line = sprintf("%-${indent_use}s%s$colors{'cn'}\n",$start,"$start2$holder"); print_line($line); + $b_row1 = 0; $holder = ''; $length = 0; $start = ''; @@ -6872,11 +7069,19 @@ sub print_data { } # only for repos currently elsif (ref($val1) eq 'ARRAY'){ - # print "eight\n"; - $array=0; + # print "p-5: r1: $b_row1 iu: $indent_use\n"; + my $array=0; + $indent_use = $indent_2; foreach my $item (@$val1){ $array++; - $indent_use = ($b_single) ? $indent + 2: $indent; + if ($size{'max-lines'}){ + my $l1 = length("$array$sep{'s2'} $item") + $indent_use; + if ($l1 > $size{'term-cols'}){ + my $l2 = length("$array$sep{'s2'} ") + $indent_use + 6; + # print "$l1 $size{'term-cols'} $l2 $array $indent_use\n"; + $item = substr($item,0,$size{'term-cols'} - $l2) . '[...]'; + } + } $line = "$colors{'c1'}$array$sep{'s2'} $colors{'c2'}$item$colors{'cn'}"; $line = sprintf("%-${indent_use}s%s\n","","$line"); print_line($line); @@ -6907,7 +7112,19 @@ sub print_line { system('qdbus', 'org.kde.konversation', '/irc', 'say', $client{'dserver'}, $client{'dtarget'}, $line); } else { + # print "tl: $size{'term-lines'} ml: $size{'max-lines'} l:$size{'lines'}\n"; + if ($size{'max-lines'}){ + # -y1 + -Y can result in start of output scrolling off screen if terminal + # wrapped lines happen. + if ((($size{'max-lines'} >= $size{'term-lines'}) && + $size{'max-lines'} == $size{'lines'}) || + ($size{'max-lines'} < $size{'term-lines'} && + $size{'max-lines'} + 1 == $size{'lines'})){ + output_control(); + } + } print $line; + $size{'lines'}++ if $size{'max-lines'}; } } @@ -6927,17 +7144,16 @@ sub get { eval $start if $b_log; my (@rows); my $num = 0; - if (($b_arm || $b_mips) && !$use{'soc-audio'} && !$use{'pci-tool'}){ - my $type = ($b_arm) ? 'arm' : 'mips'; + if (%risc && !$use{'soc-audio'} && !$use{'pci-tool'}){ my $key = 'Message'; push(@rows,{ - main::key($num++,0,1,$key) => main::row_defaults($type . '-pci',''), + main::key($num++,0,1,$key) => main::message('risc-pci',$risc{'id'}), },); } else { push(@rows,device_output()); } - if (((($b_arm || $b_mips) && !$use{'soc-audio'} && !$use{'pci-tool'}) || !@rows) && + if (((%risc && !$use{'soc-audio'} && !$use{'pci-tool'}) || !@rows) && (my $file = $system_files{'asound-cards'})){ push(@rows,asound_output($file)); } @@ -6949,7 +7165,7 @@ sub get { $type = 'pci-card-data-root'; } push(@rows,{ - main::key($num++,0,1,$key) => main::row_defaults($type,''), + main::key($num++,0,1,$key) => main::message($type,''), },); } push(@rows,sound_server_output()); @@ -6968,10 +7184,10 @@ sub device_output { my $driver = $row->[9]; $driver ||= 'N/A'; my $device = $row->[4]; - $device = ($device) ? main::pci_cleaner($device,'output') : 'N/A'; + $device = ($device) ? main::clean_pci($device,'output') : 'N/A'; # have seen absurdly verbose card descriptions, with non related data etc - if (length($device) > 85 || $size{'max'} < 110){ - $device = main::pci_long_filter($device); + if (length($device) > 85 || $size{'max-cols'} < 110){ + $device = main::filter_pci_long($device); } push(@rows, { main::key($num++,1,1,'Device') => $device, @@ -7035,7 +7251,7 @@ sub asound_output { if ($extra > 0){ my $version = main::get_module_version($driver); $rows[$j]->{main::key($num++,0,3,'v')} = $version if $version; - $rows[$j]->{main::key($num++,0,2,'message')} = main::row_defaults('pci-advanced-data',''); + $rows[$j]->{main::key($num++,0,2,'message')} = main::message('pci-advanced-data',''); } } } @@ -7054,7 +7270,7 @@ sub usb_output { $num = 1; # make sure to reset, or second device trips last flag ($path_id,$product) = ('',''); - $product = main::cleaner($row->[13]) if $row->[13]; + $product = main::clean($row->[13]) if $row->[13]; $path_id = $row->[2] if $row->[2]; $product ||= 'N/A'; $row->[15] ||= 'N/A'; @@ -7074,7 +7290,7 @@ sub usb_output { $rows[$j]->{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]"; } if ($extra > 2 && $row->[16]){ - $rows[$j]->{main::key($num++,0,2,'serial')} = main::apply_filter($row->[16]); + $rows[$j]->{main::key($num++,0,2,'serial')} = main::filter($row->[16]); } $j = scalar @rows; } @@ -7188,7 +7404,7 @@ sub get { if (!%battery){ if ($show{'battery-forced'}){ $key1 = 'Message'; - $val1 = main::row_defaults('battery-data',''); + $val1 = main::message('battery-data',''); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } } @@ -7202,7 +7418,7 @@ sub get { if (!%battery){ if ($show{'battery-forced'}){ $key1 = 'Message'; - $val1 = main::row_defaults('battery-data-bsd',''); + $val1 = main::message('battery-data-bsd',''); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } } @@ -7215,7 +7431,7 @@ sub get { if (!%battery){ if ($show{'battery-forced'}){ $key1 = 'Message'; - $val1 = main::row_defaults('battery-data',''); + $val1 = main::message('battery-data',''); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } } @@ -7226,7 +7442,7 @@ sub get { else { if ($show{'battery-forced'}){ $key1 = 'Message'; - $val1 = (!$bsd_type) ? main::row_defaults('battery-data-sys'): main::row_defaults('battery-data-bsd'); + $val1 = (!$bsd_type) ? main::message('battery-data-sys'): main::message('battery-data-bsd'); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } } @@ -7271,7 +7487,8 @@ sub battery_output { # we need to handle cases where charge or energy full is 0 if (defined $battery->{$key}{'energy_now'} && $battery->{$key}{'energy_now'} ne ''){ $charge = "$battery->{$key}{'energy_now'} Wh"; - if ($battery->{$key}{'energy_full'} && main::is_numeric($battery->{$key}{'energy_full'})){ + if ($battery->{$key}{'energy_full'} && + main::is_numeric($battery->{$key}{'energy_full'})){ my $percent = sprintf("%.1f", $battery->{$key}{'energy_now'}/$battery->{$key}{'energy_full'}*100); $charge .= ' (' . $percent . '%)'; } @@ -7285,7 +7502,8 @@ sub battery_output { } if ($battery->{$key}{'energy_full'} || $battery->{$key}{'energy_full_design'}){ $battery->{$key}{'energy_full_design'} ||= 'N/A'; - $battery->{$key}{'energy_full'}= (defined $battery->{$key}{'energy_full'} && $battery->{$key}{'energy_full'} ne '') ? $battery->{$key}{'energy_full'} : 'N/A'; + $battery->{$key}{'energy_full'} = (defined $battery->{$key}{'energy_full'} && + $battery->{$key}{'energy_full'} ne '') ? $battery->{$key}{'energy_full'} : 'N/A'; $condition = "$battery->{$key}{'energy_full'}/$battery->{$key}{'energy_full_design'} Wh"; if ($battery->{$key}{'of_orig'}){ $condition .= " ($battery->{$key}{'of_orig'}%)"; @@ -7298,7 +7516,8 @@ sub battery_output { main::key($num++,0,2,'charge') => $charge, main::key($num++,0,2,'condition') => $condition, },); - if ($extra > 0 || ($battery->{$key}{'voltage_now'} && $battery->{$key}{'voltage_min_design'} && + if ($extra > 0 || ($battery->{$key}{'voltage_now'} && + $battery->{$key}{'voltage_min_design'} && ($battery->{$key}{'voltage_now'} - $battery->{$key}{'voltage_min_design'}) < 0.5)){ $battery->{$key}{'voltage_now'} ||= 'N/A'; $rows[$j]->{main::key($num++,1,2,'volts')} = $battery->{$key}{'voltage_now'}; @@ -7328,7 +7547,7 @@ sub battery_output { $rows[$j]->{main::key($num++,0,2,'type')} = $chemistry; } if ($extra > 1){ - $serial = main::apply_filter($battery->{$key}{'serial_number'}); + $serial = main::filter($battery->{$key}{'serial_number'}); $rows[$j]->{main::key($num++,0,2,'serial')} = $serial; } $status = ($battery->{$key}{'status'}) ? $battery->{$key}{'status'}: 'N/A'; @@ -7358,14 +7577,15 @@ sub battery_output { if ($upower_data{'percent'}){ $charge = $upower_data{'percent'}; } - elsif ($battery->{$key}{'capacity_level'} && lc($battery->{$key}{'capacity_level'}) ne 'unknown'){ + elsif ($battery->{$key}{'capacity_level'} && + lc($battery->{$key}{'capacity_level'}) ne 'unknown'){ $charge = $battery->{$key}{'capacity_level'}; } else { $charge = 'N/A'; } $model = $battery->{$key}{'model_name'} if $battery->{$key}{'model_name'}; - $status = ($battery->{$key}{'status'} && lc($battery->{$key}{'status'}) ne 'unknown') ? $battery->{$key}{'status'}: 'N/A' ; + $status = ($battery->{$key}{'status'}) ? $battery->{$key}{'staus'}: 'N/A' ; $vendor = $battery->{$key}{'manufacturer'} if $battery->{$key}{'manufacturer'}; if ($vendor || $model){ if ($vendor && $model){ @@ -7383,7 +7603,7 @@ sub battery_output { main::key($num++,0,2,'model') => $model, },); if ($extra > 1){ - $serial = main::apply_filter($battery->{$key}{'serial_number'}); + $serial = main::filter($battery->{$key}{'serial_number'}); $rows[$j]->{main::key($num++,0,2,'serial')} = $serial; } $rows[$j]->{main::key($num++,0,2,'charge')} = $charge; @@ -7409,7 +7629,8 @@ sub battery_data_sys { my @items = qw(alarm capacity capacity_level charge_full charge_full_design charge_now constant_charge_current constant_charge_current_max cycle_count energy_full energy_full_design energy_now location manufacturer model_name - power_now present scope serial_number status technology type voltage_min_design voltage_now); + power_now present scope serial_number status technology type voltage_min_design + voltage_now); foreach $item (@batteries){ $b_ma = 0; $id = $item; @@ -7457,14 +7678,19 @@ sub battery_data_sys { $b_ma = 1; } elsif ($file eq 'manufacturer'){ - $value = main::dmi_cleaner($value); + $value = main::clean_dmi($value); } elsif ($file eq 'model_name'){ - $value = main::dmi_cleaner($value); + $value = main::clean_dmi($value); + } + # Valid values: Unknown,Charging,Discharging,Not charging,Full + # don't use clean_unset because Not charging is a valid value. + elsif ($file eq 'status'){ + $value =~ s/unknown//i; } } elsif ($b_root && -e $path && ! -r $path){ - $value = main::row_defaults('root-required'); + $value = main::message('root-required'); } $battery{$id}->{$file} = $value; # print "$battery{$id}->{$file}\n"; @@ -7557,11 +7783,19 @@ sub battery_data_sysctl { elsif (/raw[^:]+:[0-9\.]+\s+\((battery) ([^\)]+)\)/){ $battery{$id}->{'status'} = $2; } - elsif (/^acpi[\S]+:at [^:]+:\s*$id\s+model\s+(.*?)\s*serial\s+([\S]*?)\s*type\s+(.*?)\s*oem\s+(.*)/i){ - $battery{$id}->{'model_name'} = main::dmi_cleaner($1); - $battery{$id}->{'serial_number'} = $2; - $battery{$id}->{'technology'} = $3; - $battery{$id}->{'manufacturer'} = main::dmi_cleaner($4); + elsif (/^acpi[\S]+:at [^:]+:\s*$id\s+/i){ + if (/\s+model\s+(.*?)\s*/){ + $battery{$id}->{'model_name'} = main::clean_dmi($1); + } + if (/\s*serial\s+([\S]*?)\s*/){ + $battery{$id}->{'serial_number'} = main::clean_unset($1,'^(0x)0+$'); + } + if (/\s*type\s+(.*?)\s*/){ + $battery{$id}->{'technology'} = $1; + } + if (/\s*oem\s+(.*)/){ + $battery{$id}->{'manufacturer'} = main::clean_dmi($1); + } } } # then do the condition/charge percent math @@ -7617,11 +7851,16 @@ sub battery_data_dmi { foreach my $item (@$row[3 .. $#$row]){ my @value = split(/:\s+/, $item); next if !$value[0]; - if ($value[0] eq 'Location'){$battery{$id}->{'location'} = $value[1] } - elsif ($value[0] eq 'Manufacturer'){$battery{$id}->{'manufacturer'} = main::dmi_cleaner($value[1]) } - elsif ($value[0] =~ /Chemistry/){$battery{$id}->{'technology'} = $value[1] } - elsif ($value[0] =~ /Serial Number/){$battery{$id}->{'serial_number'} = $value[1] } - elsif ($value[0] =~ /^Name/){$battery{$id}->{'model_name'} = main::dmi_cleaner($value[1]) } + if ($value[0] eq 'Location'){ + $battery{$id}->{'location'} = $value[1]} + elsif ($value[0] eq 'Manufacturer'){ + $battery{$id}->{'manufacturer'} = main::clean_dmi($value[1])} + elsif ($value[0] =~ /Chemistry/){ + $battery{$id}->{'technology'} = $value[1]} + elsif ($value[0] =~ /Serial Number/){ + $battery{$id}->{'serial_number'} = $value[1]} + elsif ($value[0] =~ /^Name/){ + $battery{$id}->{'model_name'} = main::clean_dmi($value[1])} elsif ($value[0] eq 'Design Capacity'){ $value[1] =~ s/\s*mwh$//i; $battery{$id}->{'energy_full_design'} = sprintf("%.1f", $value[1]/1000); @@ -7693,13 +7932,12 @@ sub get { my $num = 0; $b_bluetooth = 1 if @ps_cmd && (grep {m|/bluetoothd\b|} @ps_cmd); # note: rapi 4 has pci bus - if (($b_arm || $b_mips) && !$use{'soc-bluetooth'} && !$use{'pci-tool'}){ + if (%risc && !$use{'soc-bluetooth'} && !$use{'pci-tool'}){ # do nothing, but keep the test conditions to force - # the non arm case to always run - # my $type = ($b_arm) ? 'arm' : 'mips'; + # the non risc case to always run # my $key = 'Message'; # push(@rows,{ - # main::key($num++,0,1,$key) => main::row_defaults($type . '-pci',''), + # main::key($num++,0,1,$key) => main::message('risc-pci',$risc{'id'}), # },); } else { @@ -7710,7 +7948,7 @@ sub get { if ($show{'bluetooth-forced'}){ my $key = 'Message'; push(@rows,{ - main::key($num++,0,1,$key) => main::row_defaults('bluetooth-data'), + main::key($num++,0,1,$key) => main::message('bluetooth-data'), },); } } @@ -7733,10 +7971,10 @@ sub device_output { $j = scalar @rows; my $driver = ($row->[9]) ? $row->[9] : 'N/A'; my $device = $row->[4]; - $device = ($device) ? main::pci_cleaner($device,'output') : 'N/A'; + $device = ($device) ? main::clean_pci($device,'output') : 'N/A'; # have seen absurdly verbose card descriptions, with non related data etc - if (length($device) > 85 || $size{'max'} < 110){ - $device = main::pci_long_filter($device); + if (length($device) > 85 || $size{'max-cols'} < 110){ + $device = main::filter_pci_long($device); } push(@rows, { main::key($num++,1,1,'Device') => $device, @@ -7790,7 +8028,7 @@ sub usb_output { $j = scalar @rows; # makre sure to reset, or second device trips last flag ($path_id,$product) = ('',''); - $product = main::cleaner($row->[13]) if $row->[13]; + $product = main::clean($row->[13]) if $row->[13]; $product ||= 'N/A'; $row->[15] ||= 'N/A'; $path_id = $row->[2] if $row->[2]; @@ -7814,7 +8052,7 @@ sub usb_output { $rows[$j]->{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]"; } if ($extra > 2 && $row->[16]){ - $rows[$j]->{main::key($num++,0,2,'serial')} = main::apply_filter($row->[16]); + $rows[$j]->{main::key($num++,0,2,'serial')} = main::filter($row->[16]); } push(@rows,advanced_output('usb',$path_id)) if $path_id; } @@ -7898,10 +8136,10 @@ sub advanced_output { } } if (!$hci{$item}->{'address'} && $tool eq 'rfkill'){ - $address = main::row_defaults('recommends'); + $address = main::message('recommends'); } else { - $address = main::apply_filter($hci{$item}->{'address'}); + $address = main::filter($hci{$item}->{'address'}); } $rows[$j]->{main::key($num++,0,$l,'address')} = $address; # lmp/hci version only hciconfig sadly @@ -7964,10 +8202,10 @@ sub advanced_output { my $value = ''; if ($alerts{'hciconfig'}->{'action'} eq 'platform' || $alerts{'bt-adapter'}->{'action'} eq 'platform'){ - $value = main::row_defaults('tool-missing-os','bluetooth'); + $value = main::message('tool-missing-os','bluetooth'); } else { - $value = main::row_defaults('tools-missing','hciconfig/bt-adapter'); + $value = main::message('tools-missing','hciconfig/bt-adapter'); } push(@rows,{ main::key($num++,0,1,$key) => $value, @@ -8019,7 +8257,7 @@ sub bt_tool_data { } } if (!@data && !$b_bluetooth){ - $hci{'alert'} = main::row_defaults('bluetooth-down'); + $hci{'alert'} = main::message('bluetooth-down'); } print Data::Dumper::Dumper \%hci if $dbg[27]; main::log_data('dump','%hci', \%hci) if $b_log; @@ -8071,7 +8309,7 @@ sub hciconfig_data { $hci{$id}->{'link-mode'} = lc($1); } elsif (/^Service Classes?:\s+(.+)/){ - $hci{$id}->{'service-classes'} = main::general_cleaner(lc($1)); + $hci{$id}->{'service-classes'} = main::clean_unset(lc($1)); } } print Data::Dumper::Dumper \%hci if $dbg[27]; @@ -8138,14 +8376,14 @@ sub bluetooth_version { ## CpuItem { package CpuItem; - +my ($type); sub get { eval $start if $b_log; - my ($type) = @_; + ($type) = @_; my (@rows); if ($type eq 'short' || $type eq 'basic'){ # note, for short form, just return the raw data, not the processed output - @rows = short_data($type); + @rows = short_data(); if ($type eq 'basic'){ @rows = short_output(\@rows); } @@ -8156,28 +8394,24 @@ sub get { eval $end if $b_log; return @rows; } + +## OUTPUT HANDLERS ## sub full_output { eval $start if $b_log; my $num = 0; - my ($b_flags,$b_speeds,$core_speeds_value,$flag_key,@flags,%cpu,@rows); + my ($b_speeds,$core_speeds_value,$cpu); + my (@rows); my $sleep = $cpu_sleep * 1000000; if (my $file = $system_files{'proc-cpuinfo'}){ - # bsd sleep is set before sysctl runs, same idea - if ($b_hires){ - eval 'Time::HiRes::usleep($sleep)'; - } - else { - select(undef, undef, undef, $cpu_sleep); - } - %cpu = cpuinfo_data($file,'full'); + $cpu = cpuinfo_data($file); } elsif ($bsd_type){ my ($key1,$val1) = ('',''); if ($alerts{'sysctl'}){ if ($alerts{'sysctl'}->{'action'} eq 'use'){ # $key1 = 'Status'; -# $val1 = main::row_defaults('dev'); - %cpu = sysctl_data('full'); +# $val1 = main::message('dev'); + $cpu = sysctl_data(); } else { $key1 = ucfirst($alerts{'sysctl'}->{'action'}); @@ -8187,18 +8421,17 @@ sub full_output { } } } - my %properties = cpu_properties(\%cpu); - my $type = ($properties{'cpu-type'}) ? $properties{'cpu-type'}: ''; - my @processors = @{$cpu{'processors'}}; - my @speeds = cpu_speeds(\@processors); + my $properties = cpu_properties($cpu); + my $type = ($properties->{'cpu-type'}) ? $properties->{'cpu-type'}: ''; my $j = scalar @rows; - $cpu{'model_name'} ||= 'N/A'; + $j = scalar @rows; + $cpu->{'model_name'} ||= 'N/A'; push(@rows, { - main::key($num++,1,1,'Info') => $properties{'cpu-layout'}, - main::key($num++,0,2,'model') => $cpu{'model_name'}, + main::key($num++,1,1,'Info') => $properties->{'topology-string'}, + main::key($num++,0,2,'model') => $cpu->{'model_name'}, },); - if ($cpu{'system-cpus'}){ - my %system_cpus = %{$cpu{'system-cpus'}}; + if ($cpu->{'system-cpus'}){ + my %system_cpus = %{$cpu->{'system-cpus'}}; my $i = 1; my $counter = (%system_cpus && scalar keys %system_cpus > 1) ? '-' : ''; foreach my $key (keys %system_cpus){ @@ -8206,160 +8439,229 @@ sub full_output { $rows[$j]->{main::key($num++,0,2,'variant'.$counter)} = $key; } } - if ($b_admin && $properties{'socket'}){ - if ($properties{'upgrade'}){ - $rows[$j]->{main::key($num++,1,2,'socket')} = $properties{'socket'} . ' (' . $properties{'upgrade'} . ')'; - $rows[$j]->{main::key($num++,0,3,'note')} = main::row_defaults('note-check'); + if ($b_admin && $properties->{'socket'}){ + if ($properties->{'upgrade'}){ + $rows[$j]->{main::key($num++,1,2,'socket')} = $properties->{'socket'} . ' (' . $properties->{'upgrade'} . ')'; + $rows[$j]->{main::key($num++,0,3,'note')} = main::message('note-check'); } else { - $rows[$j]->{main::key($num++,0,2,'socket')} = $properties{'socket'}; + $rows[$j]->{main::key($num++,0,2,'socket')} = $properties->{'socket'}; } } - $properties{'bits-sys'} ||= 'N/A'; - $rows[$j]->{main::key($num++,0,2,'bits')} = $properties{'bits-sys'}; + $properties->{'bits-sys'} ||= 'N/A'; + $rows[$j]->{main::key($num++,0,2,'bits')} = $properties->{'bits-sys'}; if ($type){ $rows[$j]->{main::key($num++,0,2,'type')} = $type; + if (!$properties->{'topology-full'} && $cpu->{'smt'} && ($extra > 2 || + ($extra > 0 && $cpu->{'smt'} eq 'disabled'))){ + $rows[$j]->{main::key($num++,0,2,'smt')} = $cpu->{'smt'}; + } } if ($extra > 0){ - $cpu{'arch'} ||= 'N/A'; - $rows[$j]->{main::key($num++,1,2,'arch')} = $cpu{'arch'}; - if ($cpu{'arch-note'}){ - $rows[$j]->{main::key($num++,0,3,'note')} = $cpu{'arch-note'}; + $cpu->{'arch'} ||= 'N/A'; + $rows[$j]->{main::key($num++,1,2,'arch')} = $cpu->{'arch'}; + if ($cpu->{'arch-note'}){ + $rows[$j]->{main::key($num++,0,3,'note')} = $cpu->{'arch-note'}; } # ntoe: had if arch, but stepping can be defined where arch failed, stepping can be 0 - if (!$b_admin && defined $cpu{'stepping'}){ - $rows[$j]->{main::key($num++,0,2,'rev')} = $cpu{'stepping'}; + if (!$b_admin && (defined $cpu->{'stepping'} || defined $cpu->{'revision'})){ + my $rev = main::get_defined($cpu->{'stepping'},$cpu->{'revision'}); + $rows[$j]->{main::key($num++,0,2,'rev')} = $rev; } } if ($b_admin){ - $rows[$j]->{main::key($num++,0,2,'family')} = hex_and_decimal($cpu{'family'}); - $rows[$j]->{main::key($num++,0,2,'model-id')} = hex_and_decimal($cpu{'model_id'}); - $rows[$j]->{main::key($num++,0,2,'stepping')} = hex_and_decimal($cpu{'stepping'}); - if (!$b_arm && !$b_mips && !$b_ppc && $cpu{'type'} ne 'elbrus'){ - $cpu{'microcode'} ||= 'N/A'; - $rows[$j]->{main::key($num++,0,2,'microcode')} = $cpu{'microcode'}; + $rows[$j]->{main::key($num++,0,2,'family')} = hex_and_decimal($cpu->{'family'}); + $rows[$j]->{main::key($num++,0,2,'model-id')} = hex_and_decimal($cpu->{'model-id'}); + if (defined $cpu->{'stepping'}){ + $rows[$j]->{main::key($num++,0,2,'stepping')} = hex_and_decimal($cpu->{'stepping'}); } - } - if (($extra > 1 && ($properties{'l1-cache'} || $properties{'l3-cache'})) || - ((!$b_arm && !$b_mips && !$b_ppc) || $properties{'l2-cache'})){ - $rows[$j]->{main::key($num++,1,2,'cache')} = ''; - if ($extra > 1 && $properties{'l1-cache'}){ - $rows[$j]->{main::key($num++,0,3,'L1')} = main::get_size($properties{'l1-cache'},'string'); - } - # the arm + l2 will never be true since arm cpus don't have l2 cache - $properties{'l2-cache'} = ($properties{'l2-cache'}) ? main::get_size($properties{'l2-cache'},'string') : 'N/A'; - $rows[$j]->{main::key($num++,0,3,'L2')} = $properties{'l2-cache'}; - if ($extra > 1 && $properties{'l3-cache'}){ - $rows[$j]->{main::key($num++,0,3,'L3')} = main::get_size($properties{'l3-cache'},'string'); + elsif (defined $cpu->{'revision'}){ + $rows[$j]->{main::key($num++,0,2,'rev')} = $cpu->{'revision'}; } - if ($properties{'cache-check'}){ - $rows[$j]->{main::key($num++,0,3,'note')} = $properties{'cache-check'}; + + if (!%risc && $cpu->{'type'} ne 'elbrus'){ + $cpu->{'microcode'} = ($cpu->{'microcode'}) ? '0x' . $cpu->{'microcode'} : 'N/A'; + $rows[$j]->{main::key($num++,0,2,'microcode')} = $cpu->{'microcode'}; } } - if ($extra > 0 && !$show{'cpu-flag'}){ + # note, risc cpus are using l1, L2, L3 more often, but if risc and no L2, skip + if ($properties->{'topology-string'} && (($extra > 1 && + ($properties->{'l1-cache'} || $properties->{'l3-cache'})) || + (!%risc || $properties->{'l2-cache'}) || $properties->{'cache'})){ + full_output_caches($j,$properties,\$num,\@rows); + } + # all tests already done to load this, admin, etc + if ($properties->{'topology-full'}){ $j = scalar @rows; - @flags = split(/\s+/, $cpu{'flags'}) if $cpu{'flags'}; - $flag_key = ($b_arm || $bsd_type) ? 'features': 'flags'; - my $flag = 'N/A'; - if (@flags){ - # failure to read dmesg.boot: dmesg.boot permissions; then short -Cx list flags - @flags = grep {/^(dmesg.boot|permissions|avx[2-9]?|lm|nx|pae|pni|(sss|ss)e([2-9])?([a-z])?(_[0-9])?|svm|vmx)$/} @flags; - @flags = map {s/pni/sse3/; $_} @flags; - @flags = sort @flags; - $flag = join(' ', @flags) if @flags; - } - if ($b_arm && $flag eq 'N/A'){ - $flag = main::row_defaults('arm-cpu-f'); - } push(@rows, { - main::key($num++,0,2,$flag_key) => $flag, - }); - $b_flags = 1; - } - if ($extra > 0 && !$bsd_type){ - my $bogomips = (main::is_numeric($cpu{'bogomips'})) ? int($cpu{'bogomips'}) : 'N/A'; - $rows[$j]->{main::key($num++,0,2,'bogomips')} = $bogomips; + main::key($num++,1,1,'Topology') => '', + },); + my ($id,$var) = (2,''); + if (scalar @{$properties->{'topology-full'}} > 1){ + $var = 'variant'; + $id = 3; + } + foreach my $topo (@{$properties->{'topology-full'}}){ + if ($var){ + $rows[$j]->{main::key($num++,1,2,'variant')} = ''; + } + my $x = ($size{'max-cols'} == 1 || $output_type ne 'screen') ? '' : 'x'; + $rows[$j]->{main::key($num++,0,$id,'cpus')} = $topo->{'cpus'} . $x; + $rows[$j]->{main::key($num++,1,$id+1,'cores')} = $topo->{'cores'}; + if ($topo->{'cores-mt'} && $topo->{'cores-st'}){ + $rows[$j]->{main::key($num++,1,$id+2,'mt')} = $topo->{'cores-mt'}; + $rows[$j]->{main::key($num++,0,$id+3,'tpc')} = $topo->{'tpc'}; + $rows[$j]->{main::key($num++,0,$id+2,'st')} = $topo->{'cores-st'}; + } + if ($topo->{'cores-mt'}){ + $rows[$j]->{main::key($num++,0,$id+2,'tpc')} = $topo->{'tpc'}; + } + if ($topo->{'max'} || $topo->{'min'}){ + my ($freq,$key) = ('',''); + if ($topo->{'max'} && $topo->{'min'}){ + $key = 'min/max'; + $freq = $topo->{'min'} . '/' . $topo->{'max'}; + } + elsif ($topo->{'max'}){ + $key = 'max'; + $freq = $topo->{'max'}; + } + else { + $key = 'min'; + $freq = $topo->{'min'}; + } + $rows[$j]->{main::key($num++,0,$id+1,$key)} = $freq; + } + if ($topo->{'threads'}){ + $rows[$j]->{main::key($num++,0,$id+1,'threads')} = $topo->{'threads'}; + } + if ($topo->{'dies'}){ + $rows[$j]->{main::key($num++,0,$id+1,'dies')} = $topo->{'dies'}; + } + } + $cpu->{'smt'} ||= 'N/A'; + $rows[$j]->{main::key($num++,0,2,'smt')} = $cpu->{'smt'}; + full_output_caches($j,$properties,\$num,\@rows); } $j = scalar @rows; - my $core_key = (scalar @speeds > 1) ? 'Core speeds (MHz)' : 'Core speed (MHz)'; - my $speed_key = ($properties{'speed-key'}) ? $properties{'speed-key'}: 'Speed'; - my $min_max = ($properties{'min-max'}) ? $properties{'min-max'}: 'N/A'; - my $min_max_key = ($properties{'min-max-key'}) ? $properties{'min-max-key'}: 'min/max'; - my $speed = (defined $properties{'speed'}) ? $properties{'speed'}: 'N/A'; - # aren't able to get per core speeds in bsds yet - if (@speeds){ - if (grep {$_ ne '0'} @speeds){ + my $speeds = $cpu->{'processors'}; + my $core_key = (defined $speeds && scalar @{$speeds} > 1) ? 'cores' : 'core'; + my $speed_key = ($properties->{'speed-key'}) ? $properties->{'speed-key'}: 'Speed'; + my $min_max = ($properties->{'min-max'}) ? $properties->{'min-max'}: 'N/A'; + my $min_max_key = ($properties->{'min-max-key'}) ? $properties->{'min-max-key'}: 'min/max'; + my $speed = ''; + if (!$properties->{'avg-speed-key'}){ + $speed = (defined $properties->{'speed'}) ? $properties->{'speed'}: 'N/A'; + } + # Aren't able to get per core speeds in BSDs. Why don't they support this? + if (defined $speeds && @$speeds){ + # only if defined and not 0 + if (grep {$_} @{$speeds}){ $core_speeds_value = ''; $b_speeds = 1; } else { - $core_speeds_value = main::row_defaults('cpu-speeds'); + my $id = ($bsd_type) ? 'cpu-speeds-bsd' : 'cpu-speeds'; + $core_speeds_value = main::message($id); } } else { - $core_speeds_value = 'N/A'; + $core_speeds_value = main::message('cpu-speeds'); } $j = scalar @rows; push(@rows, { main::key($num++,1,1,$speed_key) => $speed, - main::key($num++,0,2,$min_max_key) => $min_max, }); - if ($b_admin && $properties{'dmi-speed'} && $properties{'dmi-max-speed'}){ - $rows[$j]->{main::key($num++,0,2,'base/boost')} = $properties{'dmi-speed'} . '/' . $properties{'dmi-max-speed'}; + if ($properties->{'avg-speed-key'}){ + $rows[$j]->{main::key($num++,0,2,$properties->{'avg-speed-key'})} = $properties->{'speed'}; + if ($extra > 0 && $properties->{'high-speed-key'}){ + $rows[$j]->{main::key($num++,0,2,$properties->{'high-speed-key'})} = $cpu->{'high-freq'}; + } } - if ($extra > 0){ - my $boost = get_boost_status(); - $rows[$j]->{main::key($num++,0,2,'boost')} = $boost if $boost; + $rows[$j]->{main::key($num++,0,2,$min_max_key)} = $min_max; + if ($extra > 0 && defined $cpu->{'boost'}){ + $rows[$j]->{main::key($num++,0,2,'boost')} = $cpu->{'boost'}; + } + if ($b_admin && $properties->{'dmi-speed'} && $properties->{'dmi-max-speed'}){ + $rows[$j]->{main::key($num++,0,2,'base/boost')} = $properties->{'dmi-speed'} . '/' . $properties->{'dmi-max-speed'}; + } + if ($b_admin && ($cpu->{'governor'} || $cpu->{'scaling-driver'})){ + $rows[$j]->{main::key($num++,1,2,'scaling')} = ''; + $cpu->{'driver'} ||= 'N/A'; + $rows[$j]->{main::key($num++,0,3,'driver')} = $cpu->{'scaling-driver'}; + $cpu->{'governor'} ||= 'N/A'; + $rows[$j]->{main::key($num++,0,3,'governor')} = $cpu->{'governor'}; } if ($extra > 2){ - if ($properties{'volts'}){ - $rows[$j]->{main::key($num++,0,2,'volts')} = $properties{'volts'} . ' V'; + if ($properties->{'volts'}){ + $rows[$j]->{main::key($num++,0,2,'volts')} = $properties->{'volts'} . ' V'; } - if ($properties{'ext-clock'}){ - $rows[$j]->{main::key($num++,0,2,'ext-clock')} = $properties{'ext-clock'}; + if ($properties->{'ext-clock'}){ + $rows[$j]->{main::key($num++,0,2,'ext-clock')} = $properties->{'ext-clock'}; } } $rows[$j]->{main::key($num++,1,2,$core_key)} = $core_speeds_value; my $i = 1; # if say 96 0 speed cores, no need to print all those 0s if ($b_speeds){ - foreach (@speeds){ + foreach (@{$speeds}){ $rows[$j]->{main::key($num++,0,3,$i++)} = $_; } } - if ($show{'cpu-flag'} && !$b_flags){ - $flag_key = ($b_arm || $bsd_type) ? 'Features': 'Flags'; - @flags = split(/\s+/, $cpu{'flags'}) if $cpu{'flags'}; + if ($extra > 0 && !$bsd_type){ + my $bogomips = ($cpu->{'bogomips'} && + main::is_numeric($cpu->{'bogomips'})) ? int($cpu->{'bogomips'}) : 'N/A'; + $rows[$j]->{main::key($num++,0,2,'bogomips')} = $bogomips; + } + if (($extra > 0 && !$show{'cpu-flag'}) || $show{'cpu-flag'}){ + my @flags = ($cpu->{'flags'}) ? split(/\s+/, $cpu->{'flags'}) : (); + my $flag_key = (%risc || $bsd_type) ? 'Features': 'Flags'; my $flag = 'N/A'; + if (!$show{'cpu-flag'}){ + if (@flags){ + # failure to read dmesg.boot: dmesg.boot permissions; then short -Cx list flags + @flags = grep {/^(dmesg.boot|permissions|avx[2-9]?|ht|lm|nx|pae|pni|(sss|ss)e([2-9])?([a-z])?(_[0-9])?|svm|vmx)$/} @flags; + @flags = map {s/pni/sse3/; $_} @flags if @flags; + @flags = sort @flags; + } + # only ARM has Features, never seen them for MIPS/PPC/SPARC/RISCV, but check + if ($risc{'arm'} && $flag eq 'N/A'){ + $flag = main::message('arm-cpu-f'); + } + } if (@flags){ @flags = sort @flags; - $flag = join(' ', @flags) if @flags; + $flag = join(' ', @flags); } push(@rows, { main::key($num++,0,1,$flag_key) => $flag, },); } if ($b_admin){ - my @bugs = cpu_bugs_sys(); my $value = ''; - if (!@bugs){ - if ($cpu{'bugs'}){ - my @proc_bugs = split(/\s+/, $cpu{'bugs'}); + if (!defined $cpu->{'bugs-hash'}){ + if ($cpu->{'bugs-string'}){ + my @proc_bugs = split(/\s+/, $cpu->{'bugs-string'}); @proc_bugs = sort @proc_bugs; $value = join(' ', @proc_bugs); } else { - $value = main::row_defaults('cpu-bugs-null'); + $value = main::message('cpu-bugs-null'); } } + if ($use{'filter-vulnerabilities'} && + (defined $cpu->{'bugs-hash'} || $cpu->{'bugs-string'})){ + $value = $filter_string; + undef $cpu->{'bugs-hash'}; + } push(@rows, { main::key($num++,1,1,'Vulnerabilities') => $value, },); - if (@bugs){ - $j = $#rows; - foreach my $bug (@bugs){ - $rows[$j]->{main::key($num++,1,2,'Type')} = $bug->[0]; - $rows[$j]->{main::key($num++,0,3,$bug->[1])} = $bug->[2]; + if (defined $cpu->{'bugs-hash'}){ + $j = scalar @rows; + foreach my $key (sort keys %{$cpu->{'bugs-hash'}}){ + $rows[$j]->{main::key($num++,1,2,'Type')} = $key; + $rows[$j]->{main::key($num++,0,3,$cpu->{'bugs-hash'}->{$key}[0])} = $cpu->{'bugs-hash'}->{$key}[1]; $j++; } } @@ -8367,55 +8669,96 @@ sub full_output { eval $end if $b_log; return @rows; } +# $num, $rows passed by reference +sub full_output_caches { + eval $start if $b_log; + my ($j,$properties,$num,$rows) = @_; + my $value = ''; + if (!$properties->{'l1-cache'} && !$properties->{'l2-cache'} && + !$properties->{'l3-cache'}){ + $value = ($properties->{'cache'}) ? $properties->{'cache'} : 'N/A'; + } + $$rows[$j]->{main::key($$num++,1,2,'cache')} = $value; + if ($extra > 0 && $properties->{'l1-cache'}){ + $$rows[$j]->{main::key($$num++,2,3,'L1')} = $properties->{'l1-cache'}; + if ($b_admin && ($properties->{'l1d-desc'} || $properties->{'l1i-desc'})){ + my $desc = ''; + if ($properties->{'l1d-desc'}){ + $desc .= 'd-' . $properties->{'l1d-desc'}; + } + if ($properties->{'l1i-desc'}){ + $desc .= '; ' if $desc; + $desc .= 'i-' . $properties->{'l1i-desc'}; + } + $$rows[$j]->{main::key($$num++,0,4,'desc')} = $desc; + } + } + # $$rows[$j]->{main::key($$num++,1,$l,$key)} = $support; + if (!$value){ + $properties->{'l2-cache'} = ($properties->{'l2-cache'}) ? $properties->{'l2-cache'} : 'N/A'; + $$rows[$j]->{main::key($$num++,1,3,'L2')} = $properties->{'l2-cache'}; + if ($b_admin && $properties->{'l2-desc'}){ + $$rows[$j]->{main::key($$num++,0,4,'desc')} = $properties->{'l2-desc'}; + } + } + if ($extra > 0 && $properties->{'l3-cache'}){ + $$rows[$j]->{main::key($$num++,1,3,'L3')} = $properties->{'l3-cache'}; + if ($b_admin && $properties->{'l3-desc'}){ + $$rows[$j]->{main::key($$num++,0,4,'desc')} = $properties->{'l3-desc'}; + } + } + if ($properties->{'cache-check'}){ + $$rows[$j]->{main::key($$num++,0,3,'note')} = $properties->{'cache-check'}; + } + eval $end if $b_log; +} sub short_output { eval $start if $b_log; my ($cpu) = @_; my @data; my $num = 0; - $cpu->[1] ||= main::row_defaults('cpu-model-null'); + $cpu->[1] ||= main::message('cpu-model-null'); $cpu->[2] ||= 'N/A'; @data = ({ main::key($num++,1,1,'Info') => $cpu->[0] . ' ' . $cpu->[1] . ' [' . $cpu->[2] . ']', #main::key($num++,0,2,'type') => $cpu->[2], },); if ($extra > 0){ - $data[0]->{main::key($num++,1,2,'arch')} = $cpu->[7]; - if ($cpu->[8]){ - $data[0]->{main::key($num++,0,3,'note')} = $cpu->[8]; + $data[0]->{main::key($num++,1,2,'arch')} = $cpu->[8]; + if ($cpu->[9]){ + $data[0]->{main::key($num++,0,3,'note')} = $cpu->[9]; } } - $data[0]->{main::key($num++,0,2,$cpu->[3])} = $cpu->[4]; + my $value = ($cpu->[7]) ? '' : $cpu->[4]; + $data[0]->{main::key($num++,1,2,$cpu->[3])} = $value; + if ($cpu->[7]){ + $data[0]->{main::key($num++,0,3,$cpu->[7])} = $cpu->[4]; + } if ($cpu->[6]){ - $data[0]->{main::key($num++,0,2,$cpu->[5])} = $cpu->[6]; + $data[0]->{main::key($num++,0,3,$cpu->[5])} = $cpu->[6]; } eval $end if $b_log; return @data; } + +## SHORT OUTPUT DATA ## sub short_data { eval $start if $b_log; - my ($type) = @_; my $num = 0; - my (%cpu,@data,%speeds); + my ($cpu,@data,%speeds); my $sys = '/sys/devices/system/cpu/cpufreq/policy0'; # NOTE: : Permission denied, ie, this is not always readable # /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq if (my $file = $system_files{'proc-cpuinfo'}){ - my $sleep = $cpu_sleep * 1000000; - if ($b_hires){ - eval 'Time::HiRes::usleep($sleep)'; - } - else { - select(undef, undef, undef, $cpu_sleep); - } - %cpu = cpuinfo_data($file,$type); + $cpu = cpuinfo_data($file); } elsif ($bsd_type){ my ($key1,$val1) = ('',''); if ($alerts{'sysctl'}){ if ($alerts{'sysctl'}->{'action'} eq 'use'){ # $key1 = 'Status'; -# $val1 = main::row_defaults('dev'); - %cpu = sysctl_data($type); +# $val1 = main::message('dev'); + $cpu = sysctl_data($type); } else { $key1 = ucfirst($alerts{'sysctl'}->{'action'}); @@ -8426,52 +8769,310 @@ sub short_data { } } # $cpu{'cur-freq'} = $cpu[0]->{'core-id'}[0]{'speed'}; - @data = prep_short_data(\%cpu); + @data = prep_short_data($cpu); eval $end if $b_log; return @data; } - sub prep_short_data { eval $start if $b_log; my ($cpu_data) = @_; - my %properties = cpu_properties($cpu_data); + my $properties = cpu_properties($cpu_data); my ($cpu,$speed_key,$speed,$type) = ('','speed',0,''); $cpu = $cpu_data->{'model_name'} if $cpu_data->{'model_name'}; - $type = $properties{'cpu-type'} if $properties{'cpu-type'}; - $speed_key = $properties{'speed-key'} if $properties{'speed-key'}; - $speed = $properties{'speed'} if $properties{'speed'}; + $type = $properties->{'cpu-type'} if $properties->{'cpu-type'}; + $speed_key = $properties->{'speed-key'} if $properties->{'speed-key'}; + $speed = $properties->{'speed'} if $properties->{'speed'}; my @result = ( - $properties{'cpu-layout'}, + $properties->{'topology-string'}, $cpu, $type, $speed_key, $speed, - $properties{'min-max-key'}, - $properties{'min-max'}, + $properties->{'min-max-key'}, + $properties->{'min-max'}, + $properties->{'avg-speed-key'}, ); if ($extra > 0){ $cpu_data->{'arch'} ||= 'N/A'; - $result[7] = $cpu_data->{'arch'}; - $result[8] = $cpu_data->{'arch-note'}; + $result[8] = $cpu_data->{'arch'}; + $result[9] = $cpu_data->{'arch-note'}; } eval $end if $b_log; return @result; } +## PRIMARY DATA GENERATORS ## sub cpuinfo_data { eval $start if $b_log; - my ($file,$type)= @_; - my ($arch,@ids,@line,$b_first,$b_proc_int,$note,$starter); + my ($file)= @_; + my ($arch,$note,$temp); # has to be set above fake cpu section my %cpu = set_cpu_data(); + # sleep is also set in front of sysctl_data for BSDs, same idea + my $sleep = $cpu_sleep * 1000000; + if ($b_hires){ + eval 'Time::HiRes::usleep($sleep)'; + } + else { + select(undef, undef, undef, $cpu_sleep); + } + # Run this logic first to make sure we get the speeds as raw as possible. + # Not in function to avoid unnecessary cpu use, we have slept right before. + # ARM and legacy systems etc do not always have cpufreq. + # note that there can be a definite cost to reading scaling_cur_freq, which + # must be generated on the fly based on some time snippet sample. + if (-e '/sys/devices/system/cpu/'){ + my $glob = '/sys/devices/system/cpu/cpu*/cpufreq/{affected_cpus,'; + # reading cpuinfo WAY faster than scaling, but root only + if (-r '/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq'){ + $glob .= 'cpuinfo_cur_freq}'; + } + else { + $glob .= 'scaling_cur_freq}'; + } + my ($error,$file,$key,%working,%freq,@value); + foreach (main::globber($glob)){ + next if ! -r $_; + undef $error; + # $fh always non null, even on error + open(my $fh, '<', $_) or $error = $!; + if (!$error){ + m%/sys/devices/system/cpu/cpu(\d+)/cpufreq/(affected_cpus|(cpuinfo|scaling)_cur_freq)%; + $key = $1; + $file = $2; + chomp(@value = <$fh>); + close $fh; + if ($file eq 'affected_cpus'){ + # chomp seems to turn undefined into '', not sure why + $working{$key}->[0] = $value[0] if $value[0] ne ''; + } + else { + $working{$key}->[1] = clean_speed($value[0],'khz'); + } + } + } + if (%working){ + foreach (keys %working){ + $freq{sprintf("%04d",$_)} = $working{$_}->[1] if defined $working{$_}->[0]; + } + $cpu{'sys-freq'} = \%freq if %freq; + } + } + cpuinfo_data_grabber($file) if !$loaded{'cpuinfo'}; $cpu{'type'} = cpu_vendor($cpu_arch) if $cpu_arch =~ /e2k/; # already set to lower + my ($core_count,$proc_count,$speed) = (0,0,0); + my ($b_block_1) = (1); + # need to prime for arm cpus, which do not have physical/core ids usually + # level 0 is phys id, level 1 is die id, level 2 is core id + # note, there con be a lot of processors, 32 core HT would have 64, for example. + foreach my $block (@cpuinfo){ + # get the repeated data for CPUs, after assign the dynamic per core data + next if !$block; + if ($b_block_1){ + $b_block_1 = 0; + if (!$cpu{'type'} && $block->{'vendor_id'}){ + $cpu{'type'} = cpu_vendor($block->{'vendor_id'}); + } + # PPC can use 'cpu', MIPS 'cpu model' + $temp = main::get_defined($block->{'model name'},$block->{'cpu'}, + $block->{'cpu model'}); + if ($temp){ + $cpu{'model_name'} = $temp; + $cpu{'model_name'} = main::clean($cpu{'model_name'}); + $cpu{'model_name'} = clean_cpu($cpu{'model_name'}); + if ($risc{'arm'} || $cpu{'model_name'} =~ /ARM|AArch/i){ + $cpu{'type'} = 'arm'; + if ($cpu{'model_name'} =~ /(.*)\srev\s([\S]+)\s(\(([\S]+)\))?/){ + $cpu{'model_name'} = $1; + $cpu{'stepping'} = $2; + if ($4){ + $cpu{'arch'} = $4; + if ($cpu{'model_name'} !~ /\Q$cpu{'arch'}\E/i){ + $cpu{'model_name'} .= ' ' . $cpu{'arch'}; + } + } + # print "p0:\n"; + } + } + elsif ($risc{'mips'} || $cpu{'model_name'} =~ /mips/i){ + $cpu{'type'} = 'mips'; + } + } + $temp = main::get_defined($block->{'architecture'}, + $block->{'cpu family'},$block->{'cpu architecture'}); + if ($temp){ + if ($temp =~ /^\d+$/){ + # translate integers to hex + $cpu{'family'} = uc(sprintf("%x",$temp)); + } + elsif ($risc{'arm'}){ + $cpu{'arch'} = $temp; + } + } + # note: stepping and ARM cpu revision are integers + $temp = main::get_defined($block->{'stepping'},$block->{'cpu revision'}); + # can be 0, but can be 'unknown' + if (defined $temp){ + if ($temp =~ /^\d+$/){ + $cpu{'stepping'} = uc(sprintf("%x",$temp)); + } + } + # PPC revision is a string + elsif (defined $block->{'revision'}){ + $cpu{'revision'} = $block->{'revision'}; + } + # this is hex so uc for cpu arch id. raspi 4 has Model rather than Hardware + if (defined $block->{'model'}){ + # can be 0, but can be 'unknown' + if ($temp =~ /^\d+$/){ + $cpu{'model-id'} = uc(sprintf("%x",$block->{'model'})); + } + } + if ($block->{'cpu variant'}){ + $cpu{'model-id'} = uc($block->{'cpu variant'}); + $cpu{'model-id'} =~ s/^0X//; + } + # this is per cpu, not total if > 1 pys cpus + if (!$cpu{'cores'} && $block->{'cpu cores'}){ + $cpu{'cores'} = $block->{'cpu cores'}; + } + ## this is only for -C full cpu output + if ($type eq 'full'){ + # note: in cases where only cache is there, don't guess, it can be L1, + # L2, or L3, but never all of them added togehter, so give up. + if ($block->{'cache size'} && + $block->{'cache size'} =~ /(\d+\s*[KMG])i?B?$/){ + $cpu{'cache'} = main::translate_size($1); + } + if ($block->{'l1 cache size'} && + $block->{'l1 cache size'} =~ /(\d+\s*[KMG])i?B?$/){ + $cpu{'l1-cache'} = main::translate_size($1); + } + if ($block->{'l2 cache size'} && + $block->{'l2 cache size'} =~ /(\d+\s*[KMG])i?B?$/){ + $cpu{'l2-cache'} = main::translate_size($1); + } + if ($block->{'l3 cache size'} && + $block->{'l3 cache size'} =~ /(\d+\s*[KMG])i?B?$/){ + $cpu{'l3-cache'} = main::translate_size($1); + } + if ($cpu{'type'} eq 'elbrus'){ + # note: cache0 is L1i and cache1 L1d. cp_caches_fallback handles + if (!$cpu{'l1i-cache'} && $block->{'cache0'} && + $block->{'cache0'} =~ /size\s*=\s*(\d+)K\s/){ + $cpu{'l1i-cache'} = $1; + } + if (!$cpu{'l1d-cache'} && $block->{'cache1'} && + $block->{'cache1'} =~ /size\s*=\s*(\d+)K\s/){ + $cpu{'l1d-cache'} = $1; + } + if (!$cpu{'l2-cache'} && $block->{'cache2'} && + $block->{'cache2'} =~ /size\s*=\s*(\d+)(K|M)\s/){ + $cpu{'l2-cache'} = ($2 eq 'M') ? ($1*1024) : $1; + } + if (!$cpu{'l3-cache'} && $block->{'cache3'} && + $block->{'cache3'} =~ /size\s*=\s*(\d+)(K|M)\s/){ + $cpu{'l3-cache'} = ($2 eq 'M') ? ($1*1024) : $1; + } + } + $temp = main::get_defined($block->{'flags'} || $block->{'features'}); + if ($temp){ + $cpu{'flags'} = $temp; + } + if ($b_admin){ + # note: not used unless maybe /sys data missing? + if ($block->{'bugs'}){ + $cpu{'bugs-string'} = $block->{'bugs'}; + } + # unlike family and model id, microcode appears to be hex already + if ($block->{'microcode'}){ + if ($block->{'microcode'} =~ /0x/){ + $cpu{'microcode'} = uc($block->{'microcode'}); + $cpu{'microcode'} =~ s/^0X//; + } + else { + $cpu{'microcode'} = uc(sprintf("%x",$block->{'microcode'})); + } + } + } + } + } + ## Start incrementers + $temp = main::get_defined($block->{'cpu mhz'},$block->{'clock'}); + if ($temp){ + $speed = clean_speed($temp); + push(@{$cpu{'processors'}},$speed); + } + # new arm shows bad bogomip value, so don't use it, however, ancient + # cpus, intel 486, can have super low bogomips, like 33.17 + if ($extra > 0 && $block->{'bogomips'} && ((%risc && + $block->{'bogomips'} > 50) || !%risc)){ + $cpu{'bogomips'} += $block->{'bogomips'}; + } + # just to get core counts for ARM/MIPS/PPC systems + if (defined $block->{'processor'} && !$temp){ + if ($block->{'processor'} =~ /^\d+$/){ + push(@{$cpu{'processors'}},0); + } + } + # note: for alder lake, could vary, depending on if e or p core but we + # only care aobut the highest value for crude logic here + if ($block->{'siblings'} && + (!$cpu{'siblings'} || $block->{'siblings'} > $cpu{'siblings'})){ + $cpu{'siblings'} = $block->{'siblings'}; + } + # Ignoring trying to catch dies with $block->{'physical id'}, + # that's too buggy for cpuinfo + if (defined $block->{'core id'}){ + # https://www.pcworld.com/article/3214635/components-processors/ryzen-threadripper-review-we-test-amds-monster-cpu.html + my $phys = (defined $block->{'physical id'}) ? $block->{'physical id'}: 0; + my $die_id = 0; + if (!grep {$_ eq $block->{'core id'}} @{$cpu{'ids'}->[$phys][$die_id]}){ + push(@{$cpu{'ids'}->[$phys][$die_id]},$block->{'core id'}); + } + } + } + undef @cpuinfo; # we're done with it, dump it + undef %cpuinfo_machine; + if (%risc){ + if (!$cpu{'type'}){ + $cpu{'type'} = $risc{'id'}; + } + if (!$bsd_type){ + my $system_cpus = system_cpu_name(); + $cpu{'system-cpus'} = $system_cpus if %$system_cpus; + } + } + main::log_data('dump','%cpu',\%cpu) if $b_log; + print Data::Dumper::Dumper \%cpu if $dbg[8]; + eval $end if $b_log; + return \%cpu; +} +sub cpuinfo_data_grabber { + eval $start if $b_log; + my ($file) = @_; + $loaded{'cpuinfo'} = 1; # use --arm flag when testing arm cpus, and --fake-cpu to trigger fake data if ($fake{'cpu'}){ + ## CPU sys/cpuinfo pairs: + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/android-pocom3-fake-cpuinfo.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/arm-pine64-cpuinfo-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/arm-riscyslack2-cpuinfo-1.txt"; + $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/ppc-stuntkidz~cpuinfo.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/riscv-unmatched-2021~cpuinfo-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~cpuinfo-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-cpuinfo-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-cpuinfo.txt"; + ## ARM/MIPS # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/arm/arm-4-core-pinebook-1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/arm/armv6-single-core-1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/arm/armv7-dual-core-1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/arm/armv7-new-format-model-name-single-core.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/arm/arm-2-die-96-core-rk01.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/arm/arm-shevaplug-1.2ghz.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/mips/mips-mainusg-cpuinfo.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/ppc/ppc-debian-ppc64-cpuinfo.txt"; + ## x86 # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/amd/16-core-32-mt-ryzen.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/amd/2-16-core-epyc-abucodonosor.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/amd/2-core-probook-antix.txt"; @@ -8479,6 +9080,7 @@ sub cpuinfo_data { # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/amd/4-core-althlon-mjro.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/amd/4-core-apu-vc-box.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/amd/4-core-a10-5800k-1.txt"; + $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/intel/1-core-486-fourtysixandtwo.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/intel/2-core-ht-atom-bruh.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/intel/core-2-i3.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/intel/8-core-i7-damentz64.txt"; @@ -8488,8 +9090,7 @@ sub cpuinfo_data { # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/intel/2-1-core-xeon-vm-vs2017.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/intel/4-1-core-xeon-vps-frodo1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/intel/4-6-core-xeon-no-mt-lathander.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/mips/mips-mainusg-cpuinfo.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/ppc/ppc-debian-ppc64-cpuinfo.txt"; + ## Elbrus # $cpu{'type'} = 'elbrus'; # uncomment to test elbrus # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/elbrus/elbrus-2c3/cpuinfo.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/elbrus/1xE1C-8.txt"; @@ -8501,274 +9102,340 @@ sub cpuinfo_data { # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/elbrus/4xE2CDSP-4.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/elbrus/cpuinfo.e8c2.txt"; } - my @cpuinfo = main::reader($file); - my %speeds = set_cpu_speeds_sys(); - my @phys_cpus = (0);# start with 1 always - my ($core_count,$die_holder,$die_id,$phys_id,$proc_count,$speed) = (0,0,0,0,0,0,0); - my ($phys_holder) = (undef); - # need to prime for arm cpus, which do not have physical/core ids usually - # level 0 is phys id, level 1 is die id, level 2 is core id - # note, there con be a lot of processors, 32 core HT would have 64, for example. - foreach (@cpuinfo){ - next if /^\s*$/; - @line = split(/\s*:\s*/, $_, 2); - next if !$line[0]; - $starter = $line[0]; # preserve case for one specific ARM issue - $line[0] = lc($line[0]); - if ($b_arm && !$b_first && $starter eq 'Processor' && $line[1] !~ /^\d+$/){ - # print "l1:$line[1]\n"; - $cpu{'model_name'} = main::cleaner($line[1]); - $cpu{'model_name'} = cpu_cleaner($cpu{'model_name'}); - $cpu{'type'} = 'arm'; - # Processor : AArch64 Processor rev 4 (aarch64) - # Processor : Feroceon 88FR131 rev 1 (v5l) - if ($cpu{'model_name'} && $cpu{'model_name'} =~ /(.*)\srev\s([\S]+)\s(\(([\S]+)\))?/){ - $cpu{'model_name'} = $1; - $cpu{'stepping'} = $2; - if ($4){ - $cpu{'arch'} = $4; - $cpu{'model_name'} .= ' ' . $cpu{'arch'} if $cpu{'model_name'} !~ /$cpu{'arch'}/i; - } - $cpu{'processors'}->[$proc_count] = 0; - $b_proc_int = 0; - $b_first = 1; - # print "p0:\n"; - } - } - elsif ($line[0] eq 'processor'){ - # this protects against double processor lines, one int, one string - if ($line[1] =~ /^\d+$/){ - $b_proc_int = 1; - $b_first = 1; - $cpu{'processors'}->[$proc_count] = 0; - $proc_count++; - # print "p1: $proc_count\n"; - } - else { - if (!$b_proc_int){ - $cpu{'processors'}->[$proc_count] = 0; - $proc_count++; - # print "p2a: $proc_count\n"; - } - if (!$b_first){ - # note: alternate: - # Processor : AArch64 Processor rev 4 (aarch64) - # but no model name type - if ($b_arm || $line[1] =~ /ARM|AArch/i){ - $b_arm = 1; - $cpu{'type'} = 'arm'; - } - $cpu{'model_name'} = main::cleaner($line[1]); - $cpu{'model_name'} = cpu_cleaner($cpu{'model'}); - # print "p2b:\n"; - } - $b_first = 1; - } - } - elsif (!$cpu{'family'} && - ($line[0] eq 'architecture' || $line[0] eq 'cpu family' || - $line[0] eq 'cpu architecture')){ - if ($line[1] =~ /^\d+$/){ - # translate integers to hex - $cpu{'family'} = uc(sprintf("%x", $line[1])); - } - elsif ($b_arm){ - $cpu{'arch'} = $line[1]; - } - } - elsif (!defined $cpu{'stepping'} && ($line[0] eq 'stepping' || - $line[0] eq 'cpu revision')){ - $cpu{'stepping'} = uc(sprintf("%x", $line[1])); - } - # ppc - elsif (!defined $cpu{'stepping'} && $line[0] eq 'revision'){ - $cpu{'stepping'} = $line[1]; - } - # this is hex so uc for cpu arch id. raspi 4 has Model rather than Hard - elsif (!$cpu{'model_id'} && (!$b_ppc && !$b_arm && $line[0] eq 'model')){ - $cpu{'model_id'} = uc(sprintf("%x", $line[1])); - } - elsif (!$cpu{'model_id'} && $line[0] eq 'cpu variant'){ - $cpu{'model_id'} = uc($line[1]); - $cpu{'model_id'} =~ s/^0X//; - } - # cpu can show in arm - elsif (!$cpu{'model_name'} && ($line[0] eq 'model name' || - $line[0] eq 'cpu' || $line[0] eq 'cpu model')){ - $cpu{'model_name'} = main::cleaner($line[1]); - $cpu{'model_name'} = cpu_cleaner($cpu{'model_name'}); - if ($b_arm || $line[1] =~ /ARM|AArch/i){ - $b_arm = 1; - $cpu{'type'} = 'arm'; - if ($cpu{'model_name'} && - $cpu{'model_name'} =~ /(.*)\srev\s([\S]+)\s(\(([\S]+)\))?/){ - $cpu{'model_name'} = $1; - $cpu{'stepping'} = $2; - if ($4){ - $cpu{'arch'} = $4; - $cpu{'model_name'} .= ' ' . $cpu{'arch'} if $cpu{'model_name'} !~ /$cpu{'arch'}/i; - } - #$cpu{'processors'}->[$proc_count] = 0; - } - } - elsif ($b_mips || $line[1] =~ /mips/i){ - $b_mips = 1; - $cpu{'type'} = 'mips'; - } - } - elsif ($line[0] eq 'cpu mhz' || $line[0] eq 'clock'){ - $speed = speed_cleaner($line[1]); - $cpu{'processors'}->[$proc_count-1] = $speed; - #$ids[$phys_id]->[$die_id] = [$speed]; - } - elsif (!$cpu{'siblings'} && $line[0] eq 'siblings'){ - $cpu{'siblings'} = $line[1]; + my @raw = main::reader($file); + @raw = map {$_ =~ s/^\s*$/~~~/;$_;} @raw; + push(@raw,'~~~') if @raw; + my ($b_processor,$key,$value); + my ($i) = (0); + my @key_tests = ('firmware','hardware','mmu','model','motherboard', + 'platform','system type','timebase'); + foreach my $row (@raw){ + ($key,$value) = split(/\s*:\s*/,$row,2); + next if !defined $key; + # ARM: 'Hardware' can appear in processor block; system type (mips) + # ARM: CPU revision; machine: Revision/PPC: revision (CPU implied) + # orangepi3 has Hardware/Processor embedded in processor block + if (%risc && ((grep {lc($key) eq $_} @key_tests) || + (!$risc{'ppc'} && lc($key) eq 'revision'))){ + $b_processor = 0; } - elsif (!$cpu{'cores'} && $line[0] eq 'cpu cores'){ - $cpu{'cores'} = $line[1]; + else { + $b_processor = 1; } - # increment by 1 for every new physical id we see. These are in almost all cases - # separate cpus, not separate dies within a single cpu body. - elsif ($line[0] eq 'physical id'){ - if (!defined $phys_holder || $phys_holder != $line[1]){ - # only increment if not in array counter - push(@phys_cpus, $line[1]) if ! grep {/$line[1]/} @phys_cpus; - $phys_holder = $line[1]; - # print "pid: $line[1] ph: $phys_holder did: $die_id\n"; - $die_id = 0; - #$die_holder = 0; + if ($b_processor){ + if ($key eq '~~~'){ + $i++; + next; } + # A small handful of ARM devices use Processor instead of 'model name' + # Processor : AArch64 Processor rev 4 (aarch64) + # Processor : Feroceon 88FR131 rev 1 (v5l) + $key = ($key eq 'Processor') ? 'model name' : lc($key); + $cpuinfo[$i]->{$key} = $value; } - elsif ($line[0] eq 'core id'){ - # print "ph: $phys_holder did: $die_id l1: $line[1] s: $speed\n"; - # https://www.pcworld.com/article/3214635/components-processors/ryzen-threadripper-review-we-test-amds-monster-cpu.html - if ($line[1] > 0){ - $die_holder = $line[1]; - $core_count++; - } - # NOTE: this logic won't work for die detections, unforutnately. - # ARM uses a different /sys based method, and ryzen relies on math on the cores - # in process_data - elsif ($line[1] == 0 && $die_holder > 0){ - $die_holder = $line[1]; - $core_count = 0; - $die_id++ if ($cpu{'type'} ne 'intel' && $cpu{'type'} ne 'amd'); - } - $phys_holder = 0 if ! defined $phys_holder; - $ids[$phys_holder]->[$die_id][$line[1]] = $speed; - # print "ph: $phys_holder did: $die_id l1: $line[1] s: $speed\n"; - } - if (!$cpu{'type'} && $line[0] eq 'vendor_id'){ - $cpu{'type'} = cpu_vendor($line[1]); + else { + next if $cpuinfo_machine{lc($key)}; + $cpuinfo_machine{lc($key)} = $value; } - ## this is only for -C full cpu output - if ($type eq 'full'){ - if (!$cpu{'l2-cache'} && ($line[0] eq 'cache size' || $line[0] eq 'l2 cache size')){ - if ($line[1] =~ /(\d+\s*[KMG])i?B?$/){ - $cpu{'l2-cache'} = main::translate_size($1); + } + if ($b_log){ + main::log_data('dump','@cpuinfo',\@cpuinfo); + main::log_data('dump','%cpuinfo_machine',\%cpuinfo_machine); + } + if ($dbg[41]){ + print Data::Dumper::Dumper \@cpuinfo; + print Data::Dumper::Dumper \%cpuinfo_machine; + } + eval $end if $b_log; +} +sub cpu_sys_data { + eval $start if $b_log; + my $sys_freq = $_[0]; + my (%cpu_sys); + my $working = sys_data_grabber(); + return \%cpu_sys if !%{$working}; + $cpu_sys{'data'} = $working->{'data'} if $working->{'data'}; + my ($core_id,$fake_core_id,$phys_id,) = (0,0,-1); + my (%cache_ids,@freq_max,@freq_min); + foreach my $key (sort keys %{$working->{'cpus'}}){ + ($core_id,$phys_id) = (0,0); + my $cpu_id = $key + 0; + my $speed; + my $cpu = $working->{'cpus'}{$key}; + if (defined $cpu->{'topology'}{'physical_package_id'}){ + $phys_id = sprintf("%04d",$cpu->{'topology'}{'physical_package_id'}); + } + if (defined $cpu->{'topology'}{'core_id'}){ + # id is not consistent, seen 5 digit id + $core_id = sprintf("%08d",$cpu->{'topology'}{'core_id'}); + if ($fake{'cpu'}){ + if (defined $cpu->{'cpufreq'}{'scaling_cur_freq'} && + $cpu->{'cpufreq'}{'affected_cpus'} && + $cpu->{'cpufreq'}{'affected_cpus'} ne 'UNDEFINED'){ + $speed = clean_speed($cpu->{'cpufreq'}{'scaling_cur_freq'},'khz'); } } - elsif (!$cpu{'l1-cache'} && $line[0] eq 'l1 cache size'){ - if ($line[1] =~ /(\d+\s*[KMG])i?B?$/){ - $cpu{'l1-cache'} = main::translate_size($1); - } + elsif (defined $sys_freq && defined $sys_freq->{$key}){ + $speed = $sys_freq->{$key}; } - elsif (!$cpu{'l3-cache'} && $line[0] eq 'l3 cache size'){ - if ($line[1] =~ /(\d+\s*[KMG])i?B?$/){ - $cpu{'l3-cache'} = main::translate_size($1); - } + if (defined $speed){ + push(@{$cpu_sys{'cpus'}->{$phys_id}{'cores'}{$core_id}},$speed); + push(@{$cpu_sys{'data'}->{'speeds'}{'all'}},$speed); } - if ($cpu{'type'} eq 'elbrus'){ - # note: cache0 is L1i and cache1 L1d, but add both for L1 - if (!$cpu{'l0-cache'} && $line[0] eq 'cache0'){ - if ($line[1] =~ /size\s*=\s*(\d+)K\s/){ - $cpu{'l0-cache'} = $1; - } - } - elsif (!$cpu{'l1-cache'} && $line[0] eq 'cache1'){ - if ($line[1] =~ /size\s*=\s*(\d+)K\s/){ - $cpu{'l1-cache'} = $1; - $cpu{'l1-cache'} += $cpu{'l0-cache'} if $cpu{'l0-cache'}; - } - } - elsif (!$cpu{'l2-cache'} && $line[0] eq 'cache2'){ - if ($line[1] =~ /size\s*=\s*(\d+)(K|M)\s/){ - $cpu{'l2-cache'} = ($2 eq 'M') ? ($1*1024) : $1; - } - } - elsif (!$cpu{'l3-cache'} && $line[0] eq 'cache3'){ - if ($line[1] =~ /size\s*=\s*(\d+)(K|M)\s/){ - $cpu{'l3-cache'} = ($2 eq 'M') ? ($1*1024) : $1; + else { + push(@{$cpu_sys{'data'}->{'speeds'}{'all'}},0); + # seen cases, riscv, where core id, phys id, are all -1 + my $id = ($core_id != -1) ? $core_id: $fake_core_id++; + push(@{$cpu_sys{'cpus'}->{$phys_id}{'cores'}{$id}},0); + } + # Only use if topology core-id exists, some virtualized cpus can list + # frequency data for the non available cores, but those do not show + # topology data. + # For max / min, we want to prep for the day 1 pys cpu has > 1 min/max freq + if (defined $cpu->{'cpufreq'}{'cpuinfo_max_freq'}){ + $cpu->{'cpufreq'}{'cpuinfo_max_freq'} = clean_speed($cpu->{'cpufreq'}{'cpuinfo_max_freq'},'khz'); + if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_max_freq'}} @freq_max){ + push(@freq_max,$cpu->{'cpufreq'}{'cpuinfo_max_freq'}); + } + if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_max_freq'}} @{$cpu_sys{'cpus'}->{$phys_id}{'max-freq'}}){ + push(@{$cpu_sys{'cpus'}->{$phys_id}{'max-freq'}},$cpu->{'cpufreq'}{'cpuinfo_max_freq'}); + } + } + if (defined $cpu->{'cpufreq'}{'cpuinfo_min_freq'}){ + $cpu->{'cpufreq'}{'cpuinfo_min_freq'} = clean_speed($cpu->{'cpufreq'}{'cpuinfo_min_freq'},'khz'); + if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_min_freq'}} @freq_min){ + push(@freq_min,$cpu->{'cpufreq'}{'cpuinfo_min_freq'}); + } + if (!grep {$_ eq $cpu->{'cpufreq'}{'cpuinfo_min_freq'}} @{$cpu_sys{'cpus'}->{$phys_id}{'min-freq'}}){ + push(@{$cpu_sys{'cpus'}->{$phys_id}{'min-freq'}},$cpu->{'cpufreq'}{'cpuinfo_min_freq'}); + } + } + if (defined $cpu->{'cpufreq'}{'scaling_governor'}){ + if (!grep {$_ eq $cpu->{'cpufreq'}{'scaling_governor'}} @{$cpu_sys{'cpus'}->{$phys_id}{'governor'}}){ + push(@{$cpu_sys{'cpus'}->{$phys_id}{'governor'}},$cpu->{'cpufreq'}{'scaling_governor'}); + } + } + if (defined $cpu->{'cpufreq'}{'scaling_driver'}){ + $cpu_sys{'cpus'}->{$phys_id}{'scaling-driver'} = $cpu->{'cpufreq'}{'scaling_driver'}; + } + } + if (!defined $cpu_sys{'data'}->{'cpufreq-boost'} && defined $cpu->{'cpufreq'}{'cpb'}){ + $cpu_sys{'data'}->{'cpufreq-boost'} = $cpu->{'cpufreq'}{'cpb'}; + } + if (defined $cpu->{'topology'}{'core_cpus_list'}){ + $cpu->{'topology'}{'thread_siblings_list'} = $cpu->{'topology'}{'core_cpus_list'}; + } + if (defined $cpu->{'cache'} && keys %{$cpu->{'cache'}} > 0){ + foreach my $key2 (sort keys %{$cpu->{'cache'}}){ + my $cache = $cpu->{'cache'}{$key2}; + my $type = ($cache->{'type'} =~ /^([DI])/i) ? lc($1): ''; + my $level = 'l' . $cache->{'level'} . $type; + # Very old systems, 2.6.xx do not have shared_cpu_list + if (!defined $cache->{'shared_cpu_list'} && defined $cache->{'shared_cpu_map'}){ + $cache->{'shared_cpu_list'} = $cache->{'shared_cpu_map'}; + } + # print Data::Dumper::Dumper $cache; + if (defined $cache->{'shared_cpu_list'}){ + # not needed, the cpu is always in the range + # my $range = main::regex_range($cache->{'shared_cpu_list'}); + my $size = main::translate_size($cache->{'size'}); + # print "cpuid: $cpu_id phys-core: $phys_id-$core_id level: $level range: $range shared: $cache->{'shared_cpu_list'}\n"; + if (!(grep {$_ eq $cache->{'shared_cpu_list'}} @{$cache_ids{$phys_id}->{$level}})){ + push(@{$cache_ids{$phys_id}->{$level}},$cache->{'shared_cpu_list'}); + push(@{$cpu_sys{'cpus'}->{$phys_id}{'caches'}{$level}},$size); } } } - if (!$cpu{'flags'} && ($line[0] eq 'flags' || $line[0] eq 'features')){ - $cpu{'flags'} = $line[1]; - } - if ($extra > 0 && $line[0] eq 'bogomips'){ - # new arm shows bad bogomip value, so don't use it - $cpu{'bogomips'} += $line[1] if $line[1] > 50; - } } - if ($b_admin){ - # note: not used unless maybe /sys data missing? - if (!$cpu{'bugs'} && $line[0] eq 'bugs'){ - $cpu{'bugs'} = $line[1]; - } - # unlike family and model id, microcode appears to be hex already - if (!$cpu{'microcode'} && $line[0] eq 'microcode'){ - if ($line[1] =~ /0x/){ - $cpu{'microcode'} = uc($line[1]); - $cpu{'microcode'} =~ s/^0X//; - } - else { - $cpu{'microcode'} = uc(sprintf("%x", $line[1])); - } + # die_id is relatively new, core_siblings_list has been around longer + if (defined $cpu->{'topology'}{'die_id'} || + defined $cpu->{'topology'}{'core_siblings_list'}){ + my $die = $cpu->{'topology'}{'die_id'}; + $die = $cpu->{'topology'}{'core_siblings_list'} if !defined $die; + if (!grep {$_ eq $die} @{$cpu_sys{'cpus'}->{$phys_id}{'dies'}}){ + push(@{$cpu_sys{'cpus'}->{$phys_id}{'dies'}},$die); } } } - $cpu{'phys'} = scalar @phys_cpus; - $cpu{'dies'} = $die_id++; # count starts at 0, all cpus have 1 die at least - if ($b_arm || $b_mips){ - if ($cpu{'dies'} <= 1){ - my $arm_dies = cpu_dies_sys(); - # case were 4 core arm returned 4 sibling lists, obviously wrong - $cpu{'dies'} = $arm_dies if $arm_dies && $proc_count != $arm_dies; + if (defined $cpu_sys{'data'}->{'cpufreq-boost'} && + $cpu_sys{'data'}->{'cpufreq-boost'} =~ /^[01]$/){ + if ($cpu_sys{'data'}->{'cpufreq-boost'}){ + $cpu_sys{'data'}->{'cpufreq-boost'} = 'enabled'; } - $cpu{'type'} = ($b_arm) ? 'arm' : 'mips' if !$cpu{'type'}; - if (!$bsd_type){ - my %system_cpus = system_cpu_name(); - $cpu{'system-cpus'} = \%system_cpus if %system_cpus; + else { + $cpu_sys{'data'}->{'cpufreq-boost'} = 'disabled'; } } - $cpu{'ids'} = (\@ids); - if ($extra > 0 && !$cpu{'arch'} && $type ne 'short'){ - ($cpu{'arch'},$cpu{'arch-note'}) = cpu_arch($cpu{'type'},$cpu{'family'},$cpu{'model_id'},$cpu{'stepping'}); - # cpu_arch comes from set_os() - $cpu{'arch'} = $cpu_arch if (!$cpu{'arch'} && $cpu_arch && ($b_mips || $b_arm || $b_ppc)); - # print "$cpu{'type'},$cpu{'family'},$cpu{'model_id'},$cpu{'arch'}\n"; + # cpuinfo_max_freq:["2000000"] cpuinfo_max_freq:["1500000"] + # cpuinfo_min_freq:["200000"] + if (@freq_max){ + $cpu_sys{'data'}->{'speeds'}{'max-freq'} = join(':',@freq_max); + } + if (@freq_min){ + $cpu_sys{'data'}->{'speeds'}{'min-freq'} = join(':',@freq_min); } - if (!$speeds{'cur-freq'}){ - $cpu{'cur-freq'} = $cpu{'processors'}->[0]; - $speeds{'min-freq'} = 0; - $speeds{'max-freq'} = 0; + if ((scalar @freq_max < 2 && scalar @freq_min < 2) && + (defined $cpu_sys{'data'}->{'speeds'}{'min-freq'} && + defined $cpu_sys{'data'}->{'speeds'}{'max-freq'}) && + ($cpu_sys{'data'}->{'speeds'}{'min-freq'} > $cpu_sys{'data'}->{'speeds'}{'max-freq'} || + $cpu_sys{'data'}->{'speeds'}{'min-freq'} == $cpu_sys{'data'}->{'speeds'}{'max-freq'})){ + $cpu_sys{'data'}->{'speeds'}{'min-freq'} = 0; } + main::log_data('dump','%cpu_sys',\%cpu_sys) if $b_log; + print Data::Dumper::Dumper \%cpu_sys if $dbg[8]; + eval $end if $b_log; + return \%cpu_sys; +} +sub sys_data_grabber { + eval $start if $b_log; + my (@files); + # this data has to match the data in cpuinfo grabber fake cpu, and remember + # to use --arm flag if arm tests + if ($fake{'cpu'}){ + my $file; + ## CPU sys/cpuinfo pairs: + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/android-pocom3-fake-sys.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/arm-pine64-sys-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/arm-riscyslack2-sys-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/ppc-stuntkidz~sys.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/riscv-unmatched-2021~sys-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~sys-1.txt"; + $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-sys-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-sys.txt"; + @files = main::reader($file); + } + # There's a massive time hit reading full globbed set of files, so grab and + # read only what we need. else { - $cpu{'cur-freq'} = $speeds{'cur-freq'}; - $cpu{'min-freq'} = $speeds{'min-freq'}; - $cpu{'max-freq'} = $speeds{'max-freq'}; + my $glob = '/sys/devices/system/cpu/{'; + if ($dbg[43]){ + $glob .= 'cpufreq,cpu*/topology,cpu*/cpufreq,cpu*/cache/index*,smt,vulnerabilities}/*'; + } + else { + $glob .= 'cpu*/topology/{core_cpus_list,core_id,core_siblings_list,die_id,'; + $glob .= 'physical_package_id,thread_siblings_list}'; + $glob .= ',cpufreq/{boost,ondemand}'; + $glob .= ',cpu*/cpufreq/{cpb,cpuinfo_max_freq,cpuinfo_min_freq'; + $glob .= ($type eq 'full' && $b_admin) ? ',scaling_driver,scaling_governor}':'}'; + if ($type eq 'full'){ + $glob .= ',cpu*/cache/index*/{level,shared_cpu_list,shared_cpu_map,size,type}'; + } + $glob .= ',smt/{active,control}'; + if ($b_admin){ + $glob .= ',vulnerabilities/*'; + } + $glob .= '}'; + } + @files = main::globber($glob); } - main::log_data('dump','%cpu',\%cpu) if $b_log; - print Data::Dumper::Dumper \%cpu if $dbg[8]; + main::log_data('dump','@files',\@files) if $b_log; + print Data::Dumper::Dumper \@files if $dbg[40]; + my ($b_bug,$b_cache,$b_freq,$b_topo,$b_main,%working); + my ($main_id,$main_key,$holder,$id,$item,$key) = ('','','','','',''); + # need to return hash reference on failure or old systems complain + return \%working if !@files; + foreach (sort @files){ + if ($fake{'cpu'}){ + ($_,$item) = split(/::/,$_,2); + } + else { + next if -d $_ || ! -e $_; + undef $item; + } + $key = $_; + $key =~ m|/([^/]+)/([^/]+)$|; + my ($key_1,$key_2) = ($1,$2); + if (m|/cpu(\d+)/|){ + if (!$holder || $1 ne $holder){ + $id = sprintf("%04d",$1); + $holder = $1; + } + $b_bug = 0; + $b_cache = 0; + $b_freq = 0; + $b_main = 0; + $b_topo = 0; + if ($key_1 eq 'cpufreq'){ + $b_freq = 1; + $main_key = $key_2; + $key = $key_1; + } + elsif ($key_1 eq 'topology'){ + $b_topo = 1; + $main_key = $key_2; + $key = $key_1; + } + elsif ($key_1 =~ /^index(\d+)$/){ + $b_cache = 1; + $main_key = $key_2; + $main_id = sprintf("%02d",$1); + $key = 'cache'; + } + } + elsif ($key_1 eq 'vulnerabilities'){ + $id = $key_1; + $key = $key_2; + $b_bug = 1; + $b_cache = 0; + $b_main = 0; + $b_freq = 0; + $b_topo = 0; + $main_key = ''; + $main_id = ''; + } + else { + $id = $key_1 . '-' . $key_2; + $b_bug = 0; + $b_cache = 0; + $b_main = 1; + $b_freq = 0; + $b_topo = 0; + $main_key = ''; + $main_id = ''; + } + if (!$fake{'cpu'}){ + if (-r $_) { + my $error; + # significantly faster to skip reader() and do it directly + # $fh always non null, even on error + open(my $fh, '<', $_) or $error = $!; + if (!$error){ + chomp(my @value = <$fh>); + close $fh; + $item = $value[0]; + } + # $item = main::reader($_,'strip',0); + } + else { + $item = main::message('root-required'); + } + $item = main::message('undefined') if !defined $item; + } + # print "$key_1 :: $key_2 :: $item\n"; + if ($b_main){ + $working{'data'}->{$id} = $item; + } + elsif ($b_bug){ + my $type = ($item =~ /^Mitigation:/) ? 'mitigation': 'status'; + $item =~ s/Mitigation: //; + $working{'data'}->{$id}{$key} = [$type,$item]; + } + elsif ($b_cache){ + $working{'cpus'}->{$id}{$key}{$main_id}{$main_key} = $item; + } + elsif ($b_freq || $b_topo){ + $working{'cpus'}->{$id}{$key}{$main_key} = $item; + } + } + main::log_data('dump','%working',\%working) if $b_log; + print Data::Dumper::Dumper \%working if $dbg[39]; eval $end if $b_log; - return %cpu; + return \%working; } - sub sysctl_data { eval $start if $b_log; - my ($type) = @_; my %cpu = set_cpu_data(); - my (@ids,@line,%speeds,@working); + my (@line,%speeds,@working); my ($sep) = (''); my ($die_holder,$die_id,$phys_holder,$phys_id,$proc_count,$speed) = (0,0,0,0,0,0,0); @{$sysctl{'cpu'}} = () if !$sysctl{'cpu'}; # don't want error next! @@ -8783,8 +9450,8 @@ sub sysctl_data { # openbsd 5.6: AMD Sempron(tm) Processor 3400+ ("AuthenticAMD" 686-class, 256KB L2 cache) # openbsd 6.x has Lx cache data in dmesg.boot # freebsd 10: hw.model: AMD Athlon(tm) II X2 245 Processor - $line[1] = main::cleaner($line[1]); - $line[1] = cpu_cleaner($line[1]); + $line[1] = main::clean($line[1]); + $line[1] = clean_cpu($line[1]); if ($line[1] =~ /([0-9]+)[\s-]*([KM]B)\s+L2 cache/i){ my $multiplier = ($2 eq 'MB') ? 1024: 1; $cpu{'l2-cache'} = $1 * $multiplier; @@ -8793,12 +9460,12 @@ sub sysctl_data { $cpu{'max-freq'} = $1; if ($cpu{'max-freq'} =~ /MHz/i){ $cpu{'max-freq'} =~ s/[\s-]*MHz//; - $cpu{'max-freq'} = speed_cleaner($cpu{'max-freq'},'mhz'); + $cpu{'max-freq'} = clean_speed($cpu{'max-freq'},'mhz'); } elsif ($cpu{'max-freq'} =~ /GHz/){ $cpu{'max-freq'} =~ s/[\s-]*GHz//i; $cpu{'max-freq'} = $cpu{'max-freq'} / 1000; - $cpu{'max-freq'} = speed_cleaner($cpu{'max-freq'},'mhz'); + $cpu{'max-freq'} = clean_speed($cpu{'max-freq'},'mhz'); } } if ($line[1] =~ /\)$/){ @@ -8808,8 +9475,11 @@ sub sysctl_data { $cpu{'type'} = cpu_vendor($line[1]); } # NOTE: hw.l1icachesize: hw.l1dcachesize: ; in bytes, apparently + elsif ($line[0] eq 'hw.l1dcachesize'){ + $cpu{'l1d-cache'} = $line[1]/1024; + } elsif ($line[0] eq 'hw.l1icachesize'){ - $cpu{'l1-cache'} = $line[1]/1024; + $cpu{'l1i-cache'} = $line[1]/1024; } elsif ($line[0] eq 'hw.l2cachesize'){ $cpu{'l2-cache'} = $line[1]/1024; @@ -8817,6 +9487,14 @@ sub sysctl_data { elsif ($line[0] eq 'hw.l3cachesize'){ $cpu{'l3-cache'} = $line[1]/1024; } + # hw.smt: openbsd + elsif ($line[0] eq 'hw.smt'){ + $cpu{'smt'} = ($line[1]) ? 'enabled' : 'disabled'; + } + # htl: maybe freebsd, never seen, 1 is disabled, sigh... + elsif ($line[0] eq 'machdep.hlt_logical_cpus'){ + $cpu{'smt'} = ($line[1]) ? 'disabled' : 'enabled'; + } # this is in mghz in samples elsif (!$cpu{'cur-freq'} && ($line[0] eq 'hw.clockrate' || $line[0] eq 'hw.cpuspeed')){ @@ -8835,7 +9513,7 @@ sub sysctl_data { # FB seems to call freq something other than clock speed, unreliable # eg: 1500 Mhz real shows as 2400 freq, which is wrong # elsif ($line[0] =~ /^dev\.cpu\.([0-9]+)\.freq$/){ - # $speed = speed_cleaner($line[1]); + # $speed = clean_speed($line[1]); # $cpu{'processors'}->[$1] = $speed; # } # weird FB thing, freq can be wrong, so just count the cores and call it @@ -8851,6 +9529,7 @@ sub sysctl_data { elsif ($line[0] eq 'machdep.cpu.features'){ $cpu{'flags'} = lc($line[1]); } + # is this per phys or total? elsif ($line[0] eq 'hw.ncpu'){ $cpu{'cores'} = $line[1]; } @@ -8878,7 +9557,6 @@ sub sysctl_data { my @temp = split(/\s+/, $line[1]); my $count = scalar @temp; $count-- if $count > 0; - $cpu{'processors'}->[$count] = 0; # no way to get per processor speeds yet, so assign 0 to each foreach (0 .. $count){ $cpu{'processors'}->[$_] = 0; @@ -8889,63 +9567,52 @@ sub sysctl_data { my @temp = split(/\s+/, $line[1]); $cpu{'siblings'} = scalar @temp; } - # increment by 1 for every new physical id we see. These are in almost all cases - # separate cpus, not separate dies within a single cpu body. + # increment by 1 for every new physical id we see. These are in almost all + # cases separate cpus, not separate dies within a single cpu body. + # This needs DATA!! Almost certainly wrong!! elsif ($line[0] eq 'hw.cpu_topology.cpu0.physical_id'){ if ($phys_holder != $line[1]){ $phys_id++; $phys_holder = $line[1]; - $ids[$phys_id] = [0]; - $ids[$phys_id]->[$die_id] = [0]; + push(@{$cpu{'ids'}->[$phys_id][$die_id]},0); } } elsif ($line[0] eq 'hw.cpu_topology.cpu0.core_id'){ - if ($line[1] > 0){ - $die_holder = $line[1]; - } - # this handles multi die cpus like 16 core ryzen - elsif ($line[1] == 0 && $die_holder > 0){ - $die_id++ ; - $die_holder = $line[1]; - } - $ids[$phys_id]->[$die_id][$line[1]] = $speed; - $cpu{'dies'} = $die_id; + $cpu{'ids'}->[$phys_id][$line[1]] = $speed; } } if (!$cpu{'flags'} || !$cpu{'family'}){ - my %dmesg_boot = dboot_data(); + my $dmesg_boot = dboot_data(); # this core count may fix failed MT detection. - $cpu{'cores'} = $dmesg_boot{'cores'} if $dmesg_boot{'cores'}; - $cpu{'flags'} = $dmesg_boot{'flags'} if !$cpu{'flags'}; - $cpu{'family'} = $dmesg_boot{'family'} if !$cpu{'family'}; - $cpu{'l1-cache'} = $dmesg_boot{'l1-cache'} if !$cpu{'l1-cache'}; - $cpu{'l2-cache'} = $dmesg_boot{'l2-cache'} if !$cpu{'l2-cache'}; - $cpu{'l3-cache'} = $dmesg_boot{'l3-cache'} if !$cpu{'l3-cache'}; - $cpu{'microcode'} = $dmesg_boot{'microcode'} if !$cpu{'microcode'}; - $cpu{'model_id'} = $dmesg_boot{'model_id'} if !$cpu{'model_id'}; - $cpu{'max-freq'} = $dmesg_boot{'max-freq'} if !$cpu{'max-freq'}; - $cpu{'min-freq'} = $dmesg_boot{'min-freq'} if !$cpu{'min-freq'}; - $cpu{'scalings'} = $dmesg_boot{'scalings'} if !$cpu{'scalings'}; - $cpu{'siblings'} = $dmesg_boot{'siblings'} if !$cpu{'siblings'}; - $cpu{'stepping'} = $dmesg_boot{'stepping'} if !$cpu{'stepping'}; - $cpu{'type'} = $dmesg_boot{'type'} if !$cpu{'type'}; - } - if ($extra > 0 && !$cpu{'arch'} && $type ne 'short'){ - ($cpu{'arch'},$cpu{'arch-note'}) = cpu_arch($cpu{'type'},$cpu{'family'},$cpu{'model_id'},$cpu{'stepping'}); - # print "$cpu{'type'},$cpu{'family'},$cpu{'model_id'},$cpu{'arch'}\n"; + $cpu{'cores'} = $dmesg_boot->{'cores'} if $dmesg_boot->{'cores'}; + $cpu{'flags'} = $dmesg_boot->{'flags'} if !$cpu{'flags'}; + $cpu{'family'} = $dmesg_boot->{'family'} if !$cpu{'family'}; + $cpu{'l1d-cache'} = $dmesg_boot->{'l1d-cache'} if !$cpu{'l1d-cache'}; + $cpu{'l1i-cache'} = $dmesg_boot->{'l1i-cache'} if !$cpu{'l1i-cache'}; + $cpu{'l2-cache'} = $dmesg_boot->{'l2-cache'} if !$cpu{'l2-cache'}; + $cpu{'l3-cache'} = $dmesg_boot->{'l3-cache'} if !$cpu{'l3-cache'}; + $cpu{'microcode'} = $dmesg_boot->{'microcode'} if !$cpu{'microcode'}; + $cpu{'model-id'} = $dmesg_boot->{'model-id'} if !$cpu{'model-id'}; + $cpu{'max-freq'} = $dmesg_boot->{'max-freq'} if !$cpu{'max-freq'}; + $cpu{'min-freq'} = $dmesg_boot->{'min-freq'} if !$cpu{'min-freq'}; + $cpu{'scalings'} = $dmesg_boot->{'scalings'} if !$cpu{'scalings'}; + $cpu{'siblings'} = $dmesg_boot->{'siblings'} if !$cpu{'siblings'}; + $cpu{'stepping'} = $dmesg_boot->{'stepping'} if !$cpu{'stepping'}; + $cpu{'type'} = $dmesg_boot->{'type'} if !$cpu{'type'}; } main::log_data('dump','%cpu',\%cpu) if $b_log; print Data::Dumper::Dumper \%cpu if $dbg[8]; eval $end if $b_log; - return %cpu; + return \%cpu; } +## DATA GENERATOR DATA SOURCES ## sub dboot_data { eval $start if $b_log; my ($max_freq,$min_freq,@scalings,%values); my ($family,$flags,$microcode,$model,$sep,$stepping,$type) = ('','','','','','',''); my ($cores,$siblings) = (0,0); - my ($l1,$l2,$l3) = (0,0,0); + my ($l1d,$l1i,$l2,$l3) = (0,0,0,0); # this will be null if it was not readable my $file = $system_files{'dmesg-boot'}; if ($dboot{'cpu'}){ @@ -8982,11 +9649,11 @@ sub dboot_data { elsif (/^cpu0:\s*[0-9\.]+[KMG]B\s/){ # cpu0: 32KB 64b/line 4-way L1 VIPT I-cache, 32KB 64b/line 4-way L1 D-cache # cpu0:48KB 64b/line 3-way L1 PIPT I-cache, 32KB 64b/line 2-way L1 D-cache - if (/\b([0-9\.]+[KMG])i?B\s\S+\s([0-9]+)-way\s(L1 \S+\s)?I[\s-]?cache/){ - $l1 = main::translate_size($1); - } if (/\b([0-9\.]+[KMG])i?B\s\S+\s([0-9]+)-way\sD[\s-]?cache/){ - # do nothing, we aren't going to use the D cache + $l1d = main::translate_size($1); + } + if (/\b([0-9\.]+[KMG])i?B\s\S+\s([0-9]+)-way\s(L1 \S+\s)?I[\s-]?cache/){ + $l1i = main::translate_size($1); } if (/\b([0-9\.]+[KMG])i?B\s\S+\s([0-9]+)-way\sL2[\s-]?cache/){ $l2 = main::translate_size($1); @@ -9008,7 +9675,7 @@ sub dboot_data { } # they don't seem to use hex for steppings, so convert it if (/\bStepping\s*=\s*(0x)?([0-9a-f]+)\b/){ - $stepping = (!$1) ? uc(sprintf("%X", $2)) : $2; + $stepping = (!$1) ? uc(sprintf("%X",$2)) : $2; } } elsif (/^cpu0:.*?[0-9\.]+\s?MHz:\sspeeds:\s(.*?)\s?MHz/){ @@ -9034,20 +9701,21 @@ sub dboot_data { } else { if ($file && ! -r $file){ - $flags = main::row_defaults('dmesg-boot-permissions'); + $flags = main::message('dmesg-boot-permissions'); } } %values = ( 'cores' => $cores, 'family' => $family, 'flags' => $flags, - 'l1-cache' => $l1, + 'l1d-cache' => $l1d, + 'l1i-cache' => $l1i, 'l2-cache' => $l2, 'l3-cache' => $l3, 'max-freq' => $max_freq, 'microcode' => $microcode, 'min-freq' => $min_freq, - 'model_id' => $model, + 'model-id' => $model, 'scalings' => \@scalings, 'siblings' => $siblings, 'stepping' => $stepping, @@ -9055,13 +9723,14 @@ sub dboot_data { ); print Data::Dumper::Dumper \%values if $dbg[27]; eval $end if $b_log; - return %values; + return \%values; } sub dmidecode_data { eval $start if $b_log; return if !@dmi; - my %dmi_data = ('L1' => 0, 'L2' => 0,'L3' => 0, 'ext-clock' => undef, 'socket' => undef, - 'speed' => undef, 'max-speed' => undef, 'upgrade' => undef, 'volts' => undef); + my %dmi_data = ('L1' => 0, 'L2' => 0,'L3' => 0, 'phys-cnt' => 0, + 'ext-clock' => undef, 'socket' => undef, 'speed' => undef, + 'max-speed' => undef, 'upgrade' => undef, 'volts' => undef); my ($id,$amount,$socket,$upgrade); foreach my $item (@dmi){ next if ref $item ne 'ARRAY'; @@ -9069,63 +9738,74 @@ sub dmidecode_data { last if $item->[0] > 7; if ($item->[0] == 7){ # skip first three rows, we don't need that data + # seen very bad data, L2 labeled L3, and random phantom type 7 caches ($id,$amount) = ('',0); + # Configuration: Disabled, Not Socketed, Level 2 + next if $item->[4] =~ /^Configuration:.*Disabled/i; + # labels have to be right before the block, otherwise exiting sub errors + DMI: foreach my $value (@$item[3 .. $#$item]){ - next if $value =~ /~/; + next if $value =~ /^~/; # variants: L3 - Cache; L3 Cache; L3-cache; L2 CACHE; CPU Internal L1 if ($value =~ /^Socket Designation:.*? (L[1-3])\b/){ - $id = $1; + $id = lc($1); } # some cpus only show Socket Designation: Internal cache elsif (!$id && $value =~ /^Configuration:.* Level.*?([1-3])\b/){ - $id = "L$1"; + if ($value !~ /Disabled/i){ + $id = "l$1"; + } } # NOTE: cache is in KiB or MiB but they call it kB or MB # so we send translate_size k or M which trips KiB/MiB mode + # if disabled can be 0. elsif ($id && $value =~ /^Installed Size:\s+(.*?[kKM])i?B$/){ + # Config..Disabled test should have gotten this, but just in case 0 size + next DMI if !$1; $amount = main::translate_size($1); - } + } if ($id && $amount){ - $dmi_data{$id} += $amount; + $dmi_data{$id} = $amount; last; } } } # note: for multi cpu systems, we're hoping that these values are # the same for each cpu, which in most pc situations they will be, - # and ARM etc won't be using dmi data here anyway. + # and most ARM etc won't be using dmi data here anyway. # Older dmidecode appear to have unreliable Upgrade outputs elsif ($item->[0] == 4){ # skip first three row,s we don't need that data - ($socket,$upgrade) = (undef); + ($socket,$upgrade) = (undef,undef); + $dmi_data{'phys-cnt'}++; # try to catch bsds without physical cpu count foreach my $value (@$item[3 .. $#$item]){ - next if $value =~ /~/; + next if $value =~ /^~/; # note: on single cpu systems, Socket Designation shows socket type, # but on multi, shows like, CPU1; CPU Socket #2; Socket 0; so check values a bit. # Socket Designation: Intel(R) Core(TM) i5-3470 CPU @ 3.20GHz # Sometimes shows as CPU Socket... if ($value =~ /^Socket Designation:\s*(CPU\s*Socket|Socket)?[\s-]*(.*)$/i){ - $upgrade = main::dmi_cleaner($2) if $2 !~ /(cpu|[mg]hz|onboard|socket|@|^#?[0-9]$)/i; + $upgrade = main::clean_dmi($2) if $2 !~ /(cpu|[mg]hz|onboard|socket|@|^#?[0-9]$)/i; # print "$socket_temp\n"; } # normally we prefer this value, but sometimes it's garbage # older systems often show: Upgrade: ZIF Socket which is a generic term, legacy elsif ($value =~ /^Upgrade:\s*(CPU\s*Socket|Socket)?[\s-]*(.*)$/i){ # print "$2\n"; - $socket = main::dmi_cleaner($2) if $2 !~ /(ZIF|\bslot\b)/i; + $socket = main::clean_dmi($2) if $2 !~ /(ZIF|\bslot\b)/i; } # seen: Voltage: 5.0 V 2.9 V elsif ($value =~ /^Voltage:\s*([0-9\.]+)\s*(V|Volts)?\b/i){ - $dmi_data{'volts'} = main::dmi_cleaner($1); + $dmi_data{'volts'} = main::clean_dmi($1); } elsif ($value =~ /^Current Speed:\s*([0-9\.]+)\s*([MGK]Hz)?\b/i){ - $dmi_data{'speed'} = main::dmi_cleaner($1); + $dmi_data{'speed'} = main::clean_dmi($1); } elsif ($value =~ /^Max Speed:\s*([0-9\.]+)\s*([MGK]Hz)?\b/i){ - $dmi_data{'max-speed'} = main::dmi_cleaner($1); + $dmi_data{'max-speed'} = main::clean_dmi($1); } elsif ($value =~ /^External Clock:\s*([0-9\.]+\s*[MGK]Hz)\b/){ - $dmi_data{'ext-clock'} = main::dmi_cleaner($1); + $dmi_data{'ext-clock'} = main::clean_dmi($1); } } } @@ -9143,148 +9823,355 @@ sub dmidecode_data { $dmi_data{'upgrade'} = $upgrade; } main::log_data('dump','%dmi_data',\%dmi_data) if $b_log; - # print Data::Dumper::Dumper \%dmi_data; + print Data::Dumper::Dumper \%dmi_data if $dbg[27]; eval $end if $b_log; - return %dmi_data; + return \%dmi_data; } +## CPU PROPERTIES MAIN ## sub cpu_properties { my ($cpu) = @_; - my ($b_amd_zen,$b_epyc,$b_ht,$b_elbrus,$b_intel,$b_ryzen,$b_xeon); - my ($cores_x,$cache_check) = (1,''); - if ($cpu->{'type'}){ - if ($cpu->{'type'} eq 'intel'){ - $b_intel = 1; - $b_xeon = 1 if $cpu->{'model_name'} =~ /Xeon/i; - } - elsif ($cpu->{'type'} eq 'amd'){ - if ($cpu->{'family'} && $cpu->{'family'} eq '17'){ - $b_amd_zen = 1; - if ($cpu->{'model_name'}){ - if ($cpu->{'model_name'} =~ /Ryzen/i){ - $b_ryzen = 1; - } - elsif ($cpu->{'model_name'} =~ /EPYC/i){ - $b_epyc = 1; - } - } - } + my ($cpu_sys,%dmi_data,%tests); + my %caches = ( + 'cache' => 0, # general, non id'ed from cpuinfo generic cache + 'l1' => 0, + 'l1d' => 0, + 'l1i' => 0, + 'l2' => 0, + 'l3' => 0, + ); + my %counts = ( + 'dies' => 0, + 'cpu-cores' => 0, + 'cores' => 0, + 'cores-multiplier' => 0, + 'physical' => 0, + 'processors' => 0, + ); + my ($cache_check) = (''); + if (!$bsd_type && -d '/sys/devices' && !$force{'cpuinfo'}){ + $cpu_sys = cpu_sys_data($cpu->{'sys-freq'}); + } + cp_test_types($cpu,\%tests) if $cpu->{'type'}; + undef $cpu_sys if $dbg[42]; + ## START CPU DATA HANDLERS ## + if (defined $cpu_sys->{'cpus'}){ + cp_data_sys( + $cpu, + $cpu_sys, + \%caches, + \%counts + ); + } + if (!defined $cpu_sys->{'cpus'} || !$counts{'physical'} || + !$counts{'cpu-cores'}){ + cp_data_fallback( + $cpu, + \%caches, + \$cache_check, + \%counts, + \%tests, + ); + } + # some arm cpus report each core as its own die, but that's wrong + if (%risc && $counts{'dies'} > 1 && $counts{'cpu-cores'} == $counts{'dies'}){ + $counts{'dies'} = 1; + $cpu->{'dies'} = 1; + } + if ($type eq 'full' && ($extra > 1 || ($bsd_type && !$cpu->{'l2-cache'}))){ + cp_data_dmi( + $cpu, + \%dmi_data, + \%caches, + \%counts, # only to set BSD phys cpu counts if not found + \$cache_check, + ); + } + ## END CPU DATA HANDLERS ## + + # print "pc: $counts{'processors'} s: $cpu->{'siblings'} cpuc: $counts{'cpu-cores'} corec: $counts{'cores'}\n"; + + ## START CACHE PROCESSING ## + # Get BSD and legacy linux caches if not already from dmidecode or cpu_sys. + if ($type eq 'full' && !$caches{'l1'} && !$caches{'l2'} && !$caches{'l2'}){ + cp_caches_fallback( + \%counts, + $cpu, + \%caches, + \$cache_check, + ); + } + # nothing to check! + if ($type eq 'full'){ + if (!$caches{'l1'} && !$caches{'l2'} && !$caches{'l3'} && !$caches{'cache'}){ + $cache_check = ''; + } + if ($caches{'cache'}){ + # we don't want any math done on this one, who knows what it is + $caches{'cache'} = cp_cache_processor($caches{'cache'},1); + } + if ($caches{'l1'}){ + $caches{'l1'} = cp_cache_processor($caches{'l1'},$counts{'physical'}); } - elsif ($cpu->{'type'} eq 'elbrus'){ - $b_elbrus = 1; + if ($caches{'l2'}){ + $caches{'l2'} = cp_cache_processor($caches{'l2'},$counts{'physical'}); } + if ($caches{'l3'}){ + $caches{'l3'} = cp_cache_processor($caches{'l3'},$counts{'physical'}); + } + } + ## END CACHE PROCESSING ## + + ## START TYPE/LAYOUT/ARCH/BUGS ## + my ($cpu_type) = (''); + $cpu_type = cp_cpu_type( + \%counts, + $cpu, + \%tests + ); + my %topology; + cp_cpu_topology(\%counts,\%topology); + my $arch = cp_cpu_arch( + $cpu->{'type'}, + $cpu->{'family'}, + $cpu->{'model-id'}, + $cpu->{'stepping'} + ); + # arm cpuinfo case only; confirm on bsds, not sure all get family/ids + if ($arch->[0] && !$cpu->{'arch'}){ + ($cpu->{'arch'},$cpu->{'arch-note'}) = @{$arch}; + } + # cpu_arch comes from set_os() + if (!$cpu->{'arch'} && $cpu_arch && %risc){ + $cpu->{'arch'} = $cpu_arch; + } + if ($b_admin && defined $cpu_sys->{'data'}{'vulnerabilities'}){ + $cpu->{'bugs-hash'} = $cpu_sys->{'data'}{'vulnerabilities'}; + } + ## END TYPE/LAYOUT/ARCH/BUGS ## + + ## START SPEED/BITS ## + my $speed_info = cp_speed_data($cpu,$cpu_sys); + if (!$bits_sys && !%risc && $cpu->{'flags'}){ + $bits_sys = ($cpu->{'flags'} =~ /\blm\b/) ? 64 : 32; + } + ## END SPEED/BITS ## + + ## LOAD %cpu_properties + my %cpu_properties = ( + 'avg-speed-key' => $speed_info->{'avg-speed-key'}, + 'bits-sys' => $bits_sys, + 'cache' => $caches{'cache'}, + 'cache-check' => $cache_check, + 'cpu-type' => $cpu_type, + 'dmi-max-speed' => $dmi_data{'max-speed'}, + 'dmi-speed' => $dmi_data{'speed'}, + 'ext-clock' => $dmi_data{'ext-clock'}, + 'high-speed-key' => $speed_info->{'high-speed-key'}, + 'l1-cache' => $caches{'l1'}, + 'l1d-desc' => $caches{'l1d-desc'}, + 'l1i-desc' => $caches{'l1i-desc'}, + 'l2-cache' => $caches{'l2'}, + 'l2-desc' => $caches{'l2-desc'}, + 'l3-cache' => $caches{'l3'}, + 'l3-desc' => $caches{'l3-desc'}, + 'min-max-key' => $speed_info->{'min-max-key'}, + 'min-max' => $speed_info->{'min-max'}, + 'socket' => $dmi_data{'socket'}, + 'speed-key' => $speed_info->{'speed-key'}, + 'speed' => $speed_info->{'speed'}, + 'topology-full' => $topology{'full'}, + 'topology-string' => $topology{'string'}, + 'upgrade' => $dmi_data{'upgrade'}, + 'volts' => $dmi_data{'volts'}, + ); + if ($b_log){ + main::log_data('dump','%cpu_properties',\%cpu_properties); + main::log_data('dump','%topology',\%topology); } - # my @dies = $phys[0]->[0]; - my @phys = @{$cpu->{'ids'}}; - my $physical_count = 0; - # my $physical_count = scalar @phys; - my @processors; - my ($speed,$speed_key); - # handle case where cpu reports say, phys id 0, 2, 4, 6 [yes, seen it] - foreach (@phys){ - $physical_count++ if $_; + # print Data::Dumper::Dumper $cpu; + if ($dbg[38]){ + print Data::Dumper::Dumper \%cpu_properties; + print Data::Dumper::Dumper \%topology; + } + # my $dc = scalar @dies; + # print 'phys: ' . $pc . ' dies: ' . $dc, "\n"; + eval $end if $b_log; + return \%cpu_properties; +} + +## CPU DATA ENGINES ## +# everything is passed by reference so no need to return anything +sub cp_data_dmi { + eval $start if $b_log; + my ($cpu,$dmi_data,$caches,$counts,$cache_check) = @_; + my $cpu_dmi = dmidecode_data(); + # fix for bsds that do not show physical cpus, like openbsd + if ($cpu_dmi->{'phys-cnt'} && $counts->{'physical'} == 1 && + $cpu_dmi->{'phys-cnt'} > 1){ + $counts->{'physical'} = $cpu_dmi->{'phys-cnt'}; + } + # We have to undef all the sys stuff to get back to the true dmidecode results + # Too many variants to treat one by one, just clear it out if forced. + undef %$caches if $force{'dmidecode'}; + # We don't want to use dmi L1/L2/L3 at all for non BSD systems unless forced + # because have seen totally gibberish dmidecode data for caches. /sys cache + # data preferred, more granular and basically consistently right. + # Only run for linux if no cache data found, but BSD use to fill in missing + # (we don't care about legacy errors for BSD since the data isn't adequate). + # legacy dmidecode cache data used the per cache value, NOT the per CPU total + # value like it does today. Which makes it impossible to know for sure if the + # given value is right (new, or if cache matched cpu total) or inadequate. + if ((!$bsd_type && !$caches->{'l1'} && !$caches->{'l2'} && !$caches->{'l3'}) || + ($bsd_type && (!$caches->{'l1'} || !$caches->{'l2'} || !$caches->{'l3'}))){ + # Newer dmi: cache type total per phys cpu; Legacy: raw cache size only + if ($cpu_dmi->{'l1'} && !$caches->{'l1'}){ + $caches->{'l1'} = $cpu_dmi->{'l1'}; + $$cache_check = main::message('note-check'); + } + # note: bsds often won't have L2 catch data found yet, but bsd sysctl can + # have these values so let's check just in case. OpenBSD does have it often. + if ($cpu_dmi->{'l2'} && !$caches->{'l2'}){ + $caches->{'l2'} = $cpu_dmi->{'l2'}; + $$cache_check = main::message('note-check'); + } + if ($cpu_dmi->{'l3'} && !$caches->{'l3'}){ + $caches->{'l3'} = $cpu_dmi->{'l3'}; + $$cache_check = main::message('note-check'); + } + } + $dmi_data->{'max-speed'} = $cpu_dmi->{'max-speed'}; + $dmi_data->{'socket'} = $cpu_dmi->{'socket'} if $cpu_dmi->{'socket'}; + $dmi_data->{'upgrade'} = $cpu_dmi->{'upgrade'} if $cpu_dmi->{'upgrade'}; + $dmi_data->{'speed'} = $cpu_dmi->{'speed'} if $cpu_dmi->{'speed'}; + $dmi_data->{'ext-clock'} = $cpu_dmi->{'ext-clock'} if $cpu_dmi->{'ext-clock'}; + $dmi_data->{'volts'} = $cpu_dmi->{'volts'} if $cpu_dmi->{'volts'}; + eval $end if $b_log; +} +sub cp_data_fallback { + eval $start if $b_log; + my ($cpu,$caches,$cache_check,$counts,$tests) = @_; + if (!$counts->{'physical'}){ + # handle case where cpu reports say, phys id 0, 2, 4, 6 + foreach (@{$cpu->{'ids'}}){ + $counts->{'physical'}++ if $_; + } } # count unique processors ## # note, this fails for intel cpus at times - @processors = @{$cpu->{'processors'}}; # print ref $cpu->{'processors'}, "\n"; - my $processors_count = scalar @processors; - # print "p count:$processors_count\n"; - # print Data::Dumper::Dumper \@processors; - # $cpu_cores is per physical cpu - my ($cpu_layout,$cpu_type,$min_max,$min_max_key) = ('','','',''); - my ($dmi_max_speed,$dmi_speed,$ext_clock,$socket,$upgrade,$volts) = (undef); - my ($l1_cache,$l2_cache,$l3_cache,$core_count,$cpu_cores,$die_count) = (0,0,0,0,0,0); - # note: elbrus supports turning off cores, so we need to add one for cases where rounds to 0 or 1 less - if ($b_elbrus && $processors_count){ - my @elbrus = elbrus_data($cpu->{'family'},$cpu->{'model_id'},$processors_count,$cpu->{'arch'}); - $cpu_cores = $elbrus[0]; - $physical_count = $elbrus[1]; + if (!$counts->{'processors'}){ + $counts->{'processors'} = scalar @{$cpu->{'processors'}}; + } + # print "p count:$counts->{'processors'}\n"; + # print Data::Dumper::Dumper $cpu->{'processors'}; + # $counts->{'cpu-cores'} is per physical cpu + # note: elbrus supports turning off cores, so we need to add one for cases + # where rounds to 0 or 1 less + # print "$cpu{'type'},$cpu{'family'},$cpu{'model-id'},$cpu{'arch'}\n"; + if ($tests->{'elbrus'} && $counts->{'processors'}){ + my @elbrus = cp_elbrus_data($cpu->{'family'},$cpu->{'model-id'}, + $counts->{'processors'},$cpu->{'arch'}); + $counts->{'cpu-cores'} = $elbrus[0]; + $counts->{'physical'} = $elbrus[1]; $cpu->{'arch'} = $elbrus[2]; - # print 'model id: ' . $cpu->{'model_id'} . ' arch: ' . $cpu->{'arch'} . " cpc: $cpu_cores phyc: $physical_count proc: $processors_count \n"; + # print 'model id: ' . $cpu->{'model-id'} . ' arch: ' . $cpu->{'arch'} . " cpc: $counts->{'cpu-cores'} phyc: $counts->{'physical'} proc: $counts->{'processors'} \n"; } - $physical_count ||= 1; # assume 1 if no id found, as with ARM - foreach my $die_ref (@phys){ + $counts->{'physical'} ||= 1; # assume 1 if no id found, as with ARM + foreach my $die_ref (@{$cpu->{'ids'}}){ next if ref $die_ref ne 'ARRAY'; - $core_count = 0; - $die_count = scalar @$die_ref; - #$cpu->{'dies'} = $die_count; + $counts->{'cores'} = 0; + $counts->{'dies'} = scalar @$die_ref; + #$cpu->{'dies'} = $counts->{'dies'}; foreach my $core_ref (@$die_ref){ next if ref $core_ref ne 'ARRAY'; - $core_count = 0;# reset for each die!! + $counts->{'cores'} = 0;# reset for each die!! # NOTE: the counters can be undefined because the index comes from # core id: which can be 0 skip 1 then 2, which leaves index 1 undefined - # arm cpus do not actually show core id so ignore that counter + # risc cpus do not actually show core id so ignore that counter foreach my $id (@$core_ref){ - $core_count++ if defined $id && !$b_arm; + $counts->{'cores'}++ if defined $id && !%risc; } - # print 'cores: ' . $core_count, "\n"; + # print 'cores: ' . $counts->{'cores'}, "\n"; } } # this covers potentially cases where ARM cpus have > 1 die - $cpu->{'dies'} = ($b_arm && $die_count <= 1 && $cpu->{'dies'} > 1) ? $cpu->{'dies'}: $die_count; + # maybe applies to all risc, not sure, but dies is broken anyway for cpuinfo + if (!$cpu->{'dies'}){ + if ($risc{'arm'} && $counts->{'dies'} <= 1 && $cpu->{'dies'} > 1){ + $counts->{'dies'} = $cpu->{'dies'}; + } + else { + $cpu->{'dies'} = $counts->{'dies'}; + } + } # this is an attempt to fix the amd family 15 bug with reported cores vs actual cores # NOTE: amd A6-4400M APU 2 core reports: cores: 1 siblings: 2 # NOTE: AMD A10-5800K APU 4 core reports: cores: 2 siblings: 4 - if (!$cpu_cores){ - if ($cpu->{'cores'} && !$core_count || $cpu->{'cores'} >= $core_count){ - $cpu_cores = $cpu->{'cores'}; + if (!$counts->{'cpu-cores'}){ + if ($cpu->{'cores'} && !$counts->{'cores'} || + $cpu->{'cores'} >= $counts->{'cores'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; } - elsif ($core_count > $cpu->{'cores'}){ - $cpu_cores = $core_count; + elsif ($counts->{'cores'} > $cpu->{'cores'}){ + $counts->{'cpu-cores'} = $counts->{'cores'}; } } - # print "cpu-c:$cpu_cores\n"; - #$cpu_cores = $cpu->{'cores'}; + # print "cpu-c:$counts->{'cpu-cores'}\n"; + # $counts->{'cpu-cores'} = $cpu->{'cores'}; # like, intel core duo # NOTE: sadly, not all core intel are HT/MT, oh well... # xeon may show wrong core / physical id count, if it does, fix it. A xeon # may show a repeated core id : 0 which gives a fake num_of_cores=1 - if ($b_intel){ - if ($cpu->{'siblings'} && $cpu->{'siblings'} > 1 && $cpu->{'cores'} && $cpu->{'cores'} > 1){ + if ($tests->{'intel'}){ + if ($cpu->{'siblings'} && $cpu->{'siblings'} > 1 && + $cpu->{'cores'} && $cpu->{'cores'} > 1){ if ($cpu->{'siblings'}/$cpu->{'cores'} == 1){ - $b_intel = 0; - $b_ht = 0; + $tests->{'intel'} = 0; + $tests->{'ht'} = 0; } else { - $cpu_cores = ($cpu->{'siblings'}/2); - $b_ht = 1; + $counts->{'cpu-cores'} = ($cpu->{'siblings'}/2); + $tests->{'ht'} = 1; } } } - # ryzen is made out of blocks of 8 core dies - elsif ($b_ryzen){ - $cpu_cores = $cpu->{'cores'}; + # ryzen is made out of blocks of 2, 4, or 8 core dies... + if ($tests->{'ryzen'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; # note: posix ceil isn't present in Perl for some reason, deprecated? - my $working = $cpu_cores / 8; + my $working = $counts->{'cpu-cores'} / 8; my @temp = split('\.', $working); $cpu->{'dies'} = ($temp[1] && $temp[1] > 0) ? $temp[0]++ : $temp[0]; + $counts->{'dies'} = $cpu->{'dies'}; } # these always have 4 dies - elsif ($b_epyc){ - $cpu_cores = $cpu->{'cores'}; - $cpu->{'dies'} = 4; + elsif ($tests->{'epyc'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; + $counts->{'dies'} = $cpu->{'dies'} = 4; } -# elsif ($b_elbrus){ -# $cpu_cores = -# } + # elsif ($tests->{'elbrus'}){ + # $counts->{'cpu-cores'} = + # } # final check, override the num of cores value if it clearly is wrong # and use the raw core count and synthesize the total instead of real count - if ($cpu_cores == 0 && ($cpu->{'cores'} * $physical_count > 1)){ - $cpu_cores = ($cpu->{'cores'} * $physical_count); + if ($counts->{'cpu-cores'} == 0 && + $cpu->{'cores'} * $counts->{'physical'} > 1){ + $counts->{'cpu-cores'} = ($cpu->{'cores'} * $counts->{'physical'}); } # last check, seeing some intel cpus and vms with intel cpus that do not show any # core id data at all, or siblings. - if ($cpu_cores == 0 && $processors_count > 0){ - $cpu_cores = $processors_count; + if ($counts->{'cpu-cores'} == 0 && $counts->{'processors'} > 0){ + $counts->{'cpu-cores'} = $counts->{'processors'}; } # this happens with BSDs which have very little cpu data available - if ($processors_count == 0 && $cpu_cores > 0){ - $processors_count = $cpu_cores; - if ($bsd_type && ($b_ht || $b_amd_zen) && $cpu_cores > 2){ - $cpu_cores = $cpu_cores/2;; + if ($counts->{'processors'} == 0 && $counts->{'cpu-cores'} > 0){ + $counts->{'processors'} = $counts->{'cpu-cores'}; + if ($bsd_type && ($tests->{'ht'} || $tests->{'amd-zen'}) && + $counts->{'cpu-cores'} > 2){ + $counts->{'cpu-cores'} = $counts->{'cpu-cores'}/2;; } - my $count = $processors_count; + my $count = $counts->{'processors'}; $count-- if $count > 0; $cpu->{'processors'}[$count] = 0; # no way to get per processor speeds yet, so assign 0 to each @@ -9294,421 +10181,258 @@ sub cpu_properties { $cpu->{'processors'}[$_] = 0; } } - # so far only OpenBSD has a way to detect MT cpus + # so far only OpenBSD has a way to detect MT cpus, but Openbsd has disabled MT if ($bsd_type){ - if ($cpu->{'siblings'}){ - $cores_x = $cpu_cores if $cpu_cores && $cpu_cores > 1; + if ($cpu->{'siblings'} && + $counts->{'cpu-cores'} && $counts->{'cpu-cores'} > 1){ + $counts->{'cores-multiplier'} = $counts->{'cpu-cores'}; } # if no siblings we couldn't get MT status of cpu so can't trust cache else { - $cache_check = main::row_defaults('note-check'); + $$cache_check = main::message('note-check'); } } - # only elbrus shows L1 / L3 cache data in cpuinfo - else { - $cores_x = $cpu_cores if $cpu_cores && $cpu_cores > 1; + # only elbrus shows L1 / L3 cache data in cpuinfo, cpu_sys data should show + # for newer full linux. + elsif ($counts->{'cpu-cores'} && $counts->{'cpu-cores'} > 1) { + $counts->{'cores-multiplier'} = $counts->{'cpu-cores'}; } # last test to catch some corner cases # seen a case where a xeon vm in a dual xeon system actually had 2 cores, no MT # so it reported 4 siblings, 2 cores, but actually only had 1 core per virtual cpu - # print "prc: $processors_count phc: $physical_count coc: $core_count cpc: $cpu_cores\n"; - if (!$b_arm && $processors_count == $physical_count*$core_count && $cpu_cores > $core_count){ - $b_ht = 0; - #$b_xeon = 0; - $b_intel = 0; - $cpu_cores = 1; - $core_count = 1; + # print "prc: $counts->{'processors'} phc: $counts->{'physical'} coc: $counts->{'cores'} cpc: $counts->{'cpu-cores'}\n"; + # this test was for arm but I think it applies to all risc, but risc will be sys + if (!%risc && + $counts->{'processors'} == $counts->{'physical'} * $counts->{'cores'} && + $counts->{'cpu-cores'} > $counts->{'cores'}){ + $tests->{'ht'} = 0; + # $tests->{'xeon'} = 0; + $tests->{'intel'} = 0; + $counts->{'cpu-cores'} = 1; + $counts->{'cores'} = 1; $cpu->{'siblings'} = 1; } - if ($extra > 1 || ($bsd_type && !$cpu->{'l2-cache'})){ - # note: dmidecode has one entry per cpu per cache type, so this already - # has done the arithmetic on > 1 cpus for L1 and L3. - my %cpu_dmi = dmidecode_data(); - my $multi = ($bsd_type) ? $cpu_cores: 1; - $l1_cache = $cpu_dmi{'L1'} * $physical_count if $cpu_dmi{'L1'}; - # note: bsds often won't have L2 catch data found yet - $cpu->{'l2-cache'} = $cpu_dmi{'L2'} if !$cpu->{'l2-cache'} && $cpu_dmi{'L2'}; - $l3_cache = $cpu_dmi{'L3'} * $physical_count if $cpu_dmi{'L3'}; - # bsd sysctl can have these values so let's check just in case - $l1_cache = $cpu->{'l1-cache'} * $cores_x * $physical_count if !$l1_cache && $cpu->{'l1-cache'}; - # L3 is almost always per physical cpu, not per core - $l3_cache = $cpu->{'l3-cache'} * $physical_count if !$l3_cache && $cpu->{'l3-cache'}; - $cache_check = '' if !$l1_cache && !$cpu->{'l2-cache'} && !$l3_cache; # nothing to check! - $dmi_max_speed = $cpu_dmi{'max-speed'} if $cpu_dmi{'max-speed'}; - $socket = $cpu_dmi{'socket'} if $cpu_dmi{'socket'}; - $upgrade = $cpu_dmi{'upgrade'} if $cpu_dmi{'upgrade'}; - $dmi_speed = $cpu_dmi{'speed'} if $cpu_dmi{'speed'}; - $ext_clock = $cpu_dmi{'ext-clock'} if $cpu_dmi{'ext-clock'}; - $volts = $cpu_dmi{'volts'} if $cpu_dmi{'volts'}; - } - # print "pc: $processors_count s: $cpu->{'siblings'} cpuc: $cpu_cores corec: $core_count\n"; - # Algorithm: - # if > 1 processor && processor id (physical id) == core id then Multi threaded (MT) - # if siblings > 1 && siblings == 2 * num_of_cores ($cpu->{'cores'}) then Multi threaded (MT) - # if > 1 processor && processor id (physical id) != core id then Multi-Core Processors (MCP) - # if > 1 processor && processor ids (physical id) > 1 then Symmetric Multi Processing (SMP) - # if = 1 processor then single core/processor Uni-Processor (UP) - if ($processors_count > 1 || ($b_intel && $cpu->{'siblings'} > 0)){ - # non-multicore MT - if ($processors_count == ($physical_count * $cpu_cores * 2)){ - # print "mt:1\n"; - $cpu_type .= 'MT'; - } -# elsif ($b_xeon && $cpu->{'siblings'} > 1){ -# # print "mt:2\n"; -# $cpu_type .= 'MT'; -# } - elsif ($cpu->{'siblings'} > 1 && ($cpu->{'siblings'} == 2 * $cpu_cores)){ - # print "mt:3\n"; - $cpu_type .= 'MT'; - } - # non-MT multi-core or MT multi-core - if (($processors_count == $cpu_cores) || ($physical_count < $cpu_cores)){ - my $sep = ($cpu_type) ? ' ' : '' ; - $cpu_type .= $sep . 'MCP'; - } - # only solidly known > 1 die cpus will use this, ryzen and arm for now - if ($cpu->{'dies'} > 1){ - my $sep = ($cpu_type) ? ' ' : '' ; - $cpu_type .= $sep . 'MCM'; - } - # >1 cpu sockets active: Symetric Multi Processing - if ($physical_count > 1){ - my $sep = ($cpu_type) ? ' ' : '' ; - $cpu_type .= $sep . 'SMP'; - } - } - else { - $cpu_type = 'UP'; - } - if ($physical_count > 1){ - $cpu_layout = $physical_count . 'x '; - } - $cpu_layout .= count_alpha($cpu_cores) . 'Core'; - $cpu_layout .= ' (' . $cpu->{'dies'}. '-Die)' if !$bsd_type && $cpu->{'dies'} > 1; - if (!$cpu->{'l2-cache'}){ - # do nothing - } - # the only possible change for bsds is if we can get phys counts in the future - # Looks like Intel on bsd shows L2 per core, not total. Note: Pentium N3540 - # uses 2(not 4)xL2 cache size for 4 cores, sigh... you just can't win... - elsif ($bsd_type){ - $l2_cache = $cpu->{'l2-cache'} * $cores_x * $physical_count; - } - # AMD SOS chips appear to report full L2 cache per core - elsif ($cpu->{'type'} eq 'amd' && ($cpu->{'family'} eq '14' || $cpu->{'family'} eq '15' || $cpu->{'family'} eq '16')){ - $l2_cache = $cpu->{'l2-cache'} * $physical_count; - } - elsif ($cpu->{'type'} ne 'intel'){ - $l2_cache = $cpu->{'l2-cache'} * $cpu_cores * $physical_count; - } - ## note: this handles how intel reports L2, total instead of per core like AMD does - # note that we need to multiply by number of actual cpus here to get true cache size - else { - $l2_cache = $cpu->{'l2-cache'} * $physical_count; - } - if ($cpu->{'cur-freq'} && $cpu->{'min-freq'} && $cpu->{'max-freq'}){ - $min_max = "$cpu->{'min-freq'}/$cpu->{'max-freq'} MHz"; - $min_max_key = "min/max"; - $speed_key = ($show{'short'} || $show{'cpu-basic'}) ? 'speed' : 'Speed'; - $speed = "$cpu->{'cur-freq'} MHz"; - } - elsif ($cpu->{'cur-freq'} && $cpu->{'max-freq'}){ - $min_max = "$cpu->{'max-freq'} MHz"; - $min_max_key = "max"; - $speed_key = ($show{'short'} || $show{'cpu-basic'}) ? 'speed' : 'Speed'; - $speed = "$cpu->{'cur-freq'} MHz"; - } -# elsif ($cpu->{'cur-freq'} && $cpu->{'max-freq'} && $cpu->{'cur-freq'} == $cpu->{'max-freq'}){ -# $speed_key = ($show{'short'} || $show{'cpu-basic'}) ? 'speed' : 'Speed'; -# $speed = "$cpu->{'cur-freq'} MHz (max)"; -# } - elsif ($cpu->{'cur-freq'} && $cpu->{'min-freq'}){ - $min_max = "$cpu->{'min-freq'} MHz"; - $min_max_key = "min"; - $speed_key = ($show{'short'} || $show{'cpu-basic'}) ? 'speed' : 'Speed'; - $speed = "$cpu->{'cur-freq'} MHz"; - } - elsif ($cpu->{'cur-freq'} && !$cpu->{'max-freq'}){ - $speed_key = ($show{'short'} || $show{'cpu-basic'}) ? 'speed' : 'Speed'; - $speed = "$cpu->{'cur-freq'} MHz"; - } - - if (!$bits_sys && !$b_arm && $cpu->{'flags'}){ - $bits_sys = ($cpu->{'flags'} =~ /\blm\b/) ? 64 : 32; - } - my %cpu_properties = ( - 'bits-sys' => $bits_sys, - 'cache-check' => $cache_check, - 'cpu-layout' => $cpu_layout, - 'cpu-type' => $cpu_type, - 'dmi-max-speed' => $dmi_max_speed, - 'dmi-speed' => $dmi_speed, - 'ext-clock' => $ext_clock, - 'min-max-key' => $min_max_key, - 'min-max' => $min_max, - 'socket' => $socket, - 'speed-key' => $speed_key, - 'speed' => $speed, - 'upgrade' => $upgrade, - 'volts' => $volts, - 'l1-cache' => $l1_cache, - 'l2-cache' => $l2_cache, - 'l3-cache' => $l3_cache, - ); - main::log_data('dump','%cpu_properties',\%cpu_properties) if $b_log; - # print Data::Dumper::Dumper $cpu; - # print Data::Dumper::Dumper \%cpu_properties; - # my $dc = scalar @dies; - # print 'phys: ' . $pc . ' dies: ' . $dc, "\n"; eval $end if $b_log; - return %cpu_properties; } - -sub cpu_bugs_sys { +# all values passed by reference so no need for returns +sub cp_data_sys { eval $start if $b_log; - my (@bugs,$type,$value); - return if ! -d '/sys/devices/system/cpu/vulnerabilities/'; - my @items = main::globber('/sys/devices/system/cpu/vulnerabilities/*'); - if (@items){ - foreach (@items){ - $value = (-r $_) ? main::reader($_,'',0) : main::row_defaults('root-required'); - $type = ($value =~ /^Mitigation:/) ? 'mitigation': 'status'; - $_ =~ s/.*\/([^\/]+)$/$1/; - $value =~ s/Mitigation: //; - push(@bugs,[($_,$type,$value)]); - } + my ($cpu,$cpu_sys,$caches,$counts) = @_; + my (@keys) = (sort keys %{$cpu_sys->{'cpus'}}); + return if !@keys; + $counts->{'physical'} = scalar @keys; + if ($type eq 'full' && $cpu_sys->{'cpus'}{$keys[0]}{'caches'}){ + cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l1','l1d'); + cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l1','l1i'); + cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l2',''); + cp_sys_caches($cpu_sys->{'cpus'}{$keys[0]}{'caches'},$caches,'l3',''); } - main::log_data('dump','@bugs',\@bugs) if $b_log; - # print Data::Dumper::Dumper \@bugs; - eval $end if $b_log; - return @bugs; -} - -sub cpu_speeds { - eval $start if $b_log; - my ($processors) = @_; - my (@speeds); - my @files = main::globber('/sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq'); - foreach (@files){ - my $speed = main::reader($_,'',0); - if (defined $speed){ - $speed = sprintf("%.0f", $speed/1000); - push(@speeds, $speed); - } + if ($cpu_sys->{'data'}{'speeds'}{'all'}){ + $counts->{'processors'} = scalar @{$cpu_sys->{'data'}{'speeds'}{'all'}}; } - if (!@speeds){ - # handle special case, FB, where we use undef for no processor speed found - foreach (@$processors){ - if ($_ || (defined $_ && $_ eq '0')){ - $_ = sprintf("%.0f", $_); - push(@speeds, $_); - } + if (defined $cpu_sys->{'data'}{'smt-active'}){ + if ($cpu_sys->{'data'}{'smt-active'}){ + $cpu->{'smt'} = 'enabled'; + } + # values: on/off/notsupported/notimplemented + elsif (defined $cpu_sys->{'data'}{'smt-control'} && + $cpu_sys->{'data'}{'smt-control'} =~ /^not/){ + $cpu->{'smt'} = main::message('unsupported'); + } + else { + $cpu->{'smt'} = 'disabled'; } } - # print join('; ', @speeds), "\n"; - eval $end if $b_log; - return @speeds; -} -sub set_cpu_speeds_sys { - eval $start if $b_log; - my (@max_freq,@min_freq,@policies,%speeds); - my $sys = '/sys/devices/system/cpu/cpufreq/policy0'; - my $sys2 = '/sys/devices/system/cpu/cpu0/cpufreq/'; - my ($cur,$min,$max) = ('scaling_cur_freq','scaling_min_freq','scaling_max_freq'); - if (!-d $sys && -d $sys2){ - $sys = $sys2; - ($cur,$min,$max) = ('scaling_cur_freq','cpuinfo_min_freq','cpuinfo_max_freq'); - } - if (-d $sys){ - # corner cases, android, will have the files but they may be unreadable - if (-r "$sys/$cur"){ - $speeds{'cur-freq'} = main::reader("$sys/$cur",'',0); - $speeds{'cur-freq'} = speed_cleaner($speeds{'cur-freq'},'khz'); - } - if (-r "$sys/$min"){ - $speeds{'min-freq'} = main::reader("$sys/$min",'',0); - $speeds{'min-freq'} = speed_cleaner($speeds{'min-freq'},'khz'); - } - if (-r "$sys/$max"){ - $speeds{'max-freq'} = main::reader("$sys/$max",'',0); - $speeds{'max-freq'} = speed_cleaner($speeds{'max-freq'},'khz'); - } - if ($b_arm || $b_mips){ - @policies = main::globber('/sys/devices/system/cpu/cpufreq/policy*/'); - # there are arm chips with two dies, that run at different min max speeds!! - # see: https://github.com/smxi/inxi/issues/128 - # it would be slick to show both die min/max/cur speeds, but this is - # ok for now. - if (scalar @policies > 1){ - my ($current,$cur_temp,$max,$max_temp,$min,$min_temp) = (0,0,0,0,0,0); - foreach (@policies){ - $_ =~ s/\/$//; # strip off last slash in case globs have them - $max_temp = (-r "$_/cpuinfo_max_freq") ? main::reader("$_/cpuinfo_max_freq",'',0) : 0; - if ($max_temp){ - $max_temp = speed_cleaner($max_temp,'khz'); - push(@max_freq, $max_temp); - } - $max = $max_temp if ($max_temp > $max); - $min_temp = (-r "$_/cpuinfo_min_freq") ? main::reader("$_/cpuinfo_min_freq",'',0) : 0; - if ($min_temp){ - $min_temp = speed_cleaner($min_temp,'khz'); - push(@min_freq, $min_temp); - } - $min = $min_temp if ($min_temp < $min || $min == 0); - $cur_temp = (-r "$_/scaling_cur_freq") ? main::reader("$_/scaling_cur_freq",'',0) : 0; - $cur_temp = speed_cleaner($cur_temp,'khz') if $cur_temp; - if ($cur_temp > $current){ - $current = $cur_temp; + my $i = 0; + my (@governor,@max,@min,@phys_cores); + foreach my $phys_id (@keys){ + if ($cpu_sys->{'cpus'}{$phys_id}{'cores'}){ + my ($mt,$st) = (0,0); + my (@core_keys) = keys %{$cpu_sys->{'cpus'}{$phys_id}{'cores'}}; + $cpu->{'cores'} = $counts->{'cpu-cores'} = scalar @core_keys; + $counts->{'cpu-topo'}[$i]{'cores'} = $cpu->{'cores'}; + if ($cpu_sys->{'cpus'}{$phys_id}{'dies'}){ + $counts->{'cpu-topo'}[$i]{'dies'} = scalar @{$cpu_sys->{'cpus'}{$phys_id}{'dies'}}; + $cpu->{'dies'} = $counts->{'cpu-topo'}[$i]{'dies'}; + } + # If we ever get > 1 min/max speed per phy cpu, we'll need to fix the [0] + if ($cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]){ + if (!grep {$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0] eq $_} @max){ + push(@max,$cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]); + } + $counts->{'cpu-topo'}[$i]{'max'} = $cpu_sys->{'cpus'}{$phys_id}{'max-freq'}[0]; + } + if ($cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]){ + if (!grep {$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0] eq $_} @min){ + push(@min,$cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]); + } + $counts->{'cpu-topo'}[$i]{'min'} = $cpu_sys->{'cpus'}{$phys_id}{'min-freq'}[0]; + } + # cheating, this is not a count, but we need the data for topology, must + # sort since governors can be in different order if > 1 + if ($cpu_sys->{'cpus'}{$phys_id}{'governor'}){ + foreach my $gov (@{$cpu_sys->{'cpus'}{$phys_id}{'governor'}}){ + push(@governor,$gov) if !grep {$_ eq $gov} @governor; + } + $cpu->{'governor'} = join(',',@governor); + } + if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}){ + $cpu->{'scaling-driver'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}; + } + if ($cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}){ + $cpu->{'scaling-driver'} = $cpu_sys->{'cpus'}{$phys_id}{'scaling-driver'}; + } + if (!grep {$counts->{'cpu-cores'} eq $_} @phys_cores){ + push(@phys_cores,$counts->{'cpu-cores'}); + } + if ($counts->{'processors'}){ + if ($counts->{'processors'} > $counts->{'cpu-cores'}){ + for my $key (@core_keys){ + if ((my $threads = scalar @{$cpu_sys->{'cpus'}{$phys_id}{'cores'}{$key}}) > 1){ + $counts->{'cpu-topo'}[$i]{'cores-mt'}++; + $counts->{'cpu-topo'}[$i]{'threads'} += $threads; + $counts->{'cpu-topo'}[$i]{'tpc'} = $threads; + $counts->{'struct-mt'} = 1; + } + else { + $counts->{'cpu-topo'}[$i]{'cores-st'}++; + $counts->{'cpu-topo'}[$i]{'threads'}++; + $counts->{'struct-st'} = 1; + } } } - if (@max_freq){ - main::uniq(\@max_freq); - $max = join(':', @max_freq); - } - if (@min_freq){ - main::uniq(\@min_freq); - $min = join(':', @min_freq); - } - $speeds{'cur-freq'} = $current if $current; - $speeds{'max-freq'} = $max if $max; - $speeds{'min-freq'} = $min if $min; } - } - # policy4/cpuinfo_max_freq:["2000000"] policy0/cpuinfo_max_freq:["1500000"] - # policy4/cpuinfo_min_freq:["200000"] - if ((scalar @max_freq < 2 && scalar @min_freq < 2) && - (defined $speeds{'min-freq'} && defined $speeds{'max-freq'}) && - ($speeds{'min-freq'} > $speeds{'max-freq'} || - $speeds{'min-freq'} == $speeds{'max-freq'})){ - $speeds{'min-freq'} = 0; + $i++; } } - main::log_data('dump','%speeds',\%speeds) if $b_log; - eval $end if $b_log; - return %speeds; -} - -# right now only using this for ARM cpus, this is not the same in intel/amd -sub cpu_dies_sys { - eval $start if $b_log; - my @data = main::globber('/sys/devices/system/cpu/cpu*/topology/core_siblings_list'); - my (@dies); - foreach (@data){ - my $siblings = main::reader($_,'',0); - if (! grep {/$siblings/} @dies){ - push(@dies, $siblings); - } + $counts->{'struct-max'} = 1 if scalar @max > 1; + $counts->{'struct-min'} = 1 if scalar @min > 1; + $counts->{'struct-cores'} = 1 if scalar @phys_cores > 1; + if ($b_log){ + main::log_data('dump','%cpu_properties',$caches); + main::log_data('dump','%cpu_properties',$counts); } - my $die_count = scalar @dies; + # print Data::Dumper::Dumper $caches; + # print Data::Dumper::Dumper $counts; eval $end if $b_log; - return $die_count; } -# needed because no physical_id in cpuinfo, but > 1 cpu systems exist -# returns: 0 - per cpu cores; 1 - phys cpu count; 2 - override model defaul names -sub elbrus_data { +sub cp_sys_caches { eval $start if $b_log; - my ($family_id,$model_id,$count,$arch) = @_; - # 0: cores - my @return = (0,1,$arch); - my %cores = ( - # key=family id + model id - '41' => 1, - '42' => 1, - '43' => 4, - '44' => 2, - '46' => 1, - '47' => 8, - '48' => 1, - '49' => 8, - '59' => 8, - '4A' => 12, - '4B' => 16, - '4C' => 2, - '6A' => 12, - '6B' => 16, - '6C' => 2, - ); - $return[0] = $cores{$family_id . $model_id} if $cores{$family_id . $model_id}; - if ($return[0]){ - $return[1] = ($count % $return[0]) ? int($count/$return[0]) + 1 : $count/$return[0]; + my ($sys_caches,$caches,$id,$id_di) = @_; + my $cache_id = ($id_di) ? $id_di: $id; + my %cache_desc; + if ($sys_caches->{$cache_id}){ + # print Data::Dumper::Dumper $cpu_sys->{'cpus'}; + foreach (@{$sys_caches->{$cache_id}}){ + # android seen to have cache data without size item + next if !defined $_; + $caches->{$cache_id} += $_; + $cache_desc{$_}++ if $b_admin; + } + $caches->{$id} += $caches->{$id_di} if $id_di; + $caches->{$cache_id . '-desc'} = cp_cache_desc(\%cache_desc) if $b_admin; } eval $end if $b_log; - return @return; } -# only elbrus ID is actually used live -sub cpu_vendor { - eval $start if $b_log; - my ($string) = @_; - my ($vendor) = (''); - $string = lc($string); - if ($string =~ /intel/){ - $vendor = "intel" +## CPU PROPERTIES TOOLS ## +sub cp_cache_desc { + my ($cache_desc) = @_; + my ($desc,$sep) = ('',''); + foreach (sort keys %{$cache_desc}){ + $desc .= $sep . $cache_desc->{$_} . 'x' . main::get_size($_,'string'); + $sep = ', '; } - elsif ($string =~ /amd/){ - $vendor = "amd" - } - # via - elsif ($string =~ /centaur/){ - $vendor = "centaur" + undef %{$cache_desc}; + return $desc; +} +# $caches passed by reference +sub cp_cache_processor { + my ($cache,$count) = @_; + my $output; + if ($count > 1){ + $output = $count . 'x ' . main::get_size($cache,'string'); + $output .= ' (' . main::get_size($cache * $count,'string') . ')'; } - elsif ($string =~ /e2k/){ - $vendor = "elbrus" + else { + $output = main::get_size($cache,'string'); } - eval $end if $b_log; - return $vendor; + # print "$cache :: $count :: $output\n"; + return $output; } -sub get_boost_status { +sub cp_caches_fallback { eval $start if $b_log; - my ($boost); - my $path = '/sys/devices/system/cpu/cpufreq/boost'; - if (-r $path){ - $boost = main::reader($path,'',0); - if (defined $boost && $boost =~ /^[01]$/){ - $boost = ($boost) ? 'enabled' : 'disabled'; - } + my ($counts,$cpu,$caches,$cache_check) = @_; + # L1 Cache + if ($cpu->{'l1-cache'}){ + $caches->{'l1'} = $cpu->{'l1-cache'} * $counts->{'cores-multiplier'}; } - eval $end if $b_log; - return $boost; -} -sub system_cpu_name { - eval $start if $b_log; - my (%cpus,$compat,@working); - if (@working = main::globber('/sys/firmware/devicetree/base/cpus/cpu@*/compatible')){ - foreach my $file (@working){ - $compat = main::reader($file,'',0); - next if $compat =~ /timer/; # seen on android - # these can have non printing ascii... why? As long as we only have the - # splits for: null 00/start header 01/start text 02/end text 03 - $compat = (split(/\x01|\x02|\x03|\x00/, $compat))[0] if $compat; - $compat = (split(/,\s*/, $compat))[-1] if $compat; - $cpus{$compat} = ($cpus{$compat}) ? ++$cpus{$compat}: 1; + else { + if ($cpu->{'l1d-cache'}){ + $caches->{'l1d-desc'} = $counts->{'cores-multiplier'} . 'x'; + $caches->{'l1d-desc'} .= main::get_size($cpu->{'l1d-cache'},'string'); + $caches->{'l1'} += $cpu->{'l1d-cache'} * $counts->{'cores-multiplier'}; + + } + if ($cpu->{'l1i-cache'}){ + $caches->{'l1i-desc'} = $counts->{'cores-multiplier'} . 'x'; + $caches->{'l1i-desc'} .= main::get_size($cpu->{'l1i-cache'},'string'); + $caches->{'l1'} += $cpu->{'l1i-cache'} * $counts->{'cores-multiplier'}; + } + } + # L2 Cache + # If summed by dmidecode or from cpu_sys don't use this + if ($cpu->{'l2-cache'}){ + # the only possible change for bsds is if dmidecode method gives phy counts + # Looks like Intel on bsd shows L2 per core, not total. Note: Pentium N3540 + # uses 2(not 4)xL2 cache size for 4 cores, sigh... you just can't win... + if ($bsd_type){ + $caches->{'l2'} = $cpu->{'l2-cache'} * $counts->{'cores-multiplier'}; } - } - # synthesize it, [4] will be like: cortex-a15-timer; sunxi-timer - # so far all with this directory show soc name, not cpu name for timer - elsif (! -d '/sys/firmware/devicetree/base' && $devices{'timer'}){ - foreach my $working (@{$devices{'timer'}}){ - next if $working->[0] ne 'timer' || !$working->[4] || $working->[4] =~ /timer-mem$/; - $working->[4] =~ s/(-system)?-timer$//; - $compat = $working->[4]; - $cpus{$compat} = ($cpus{$compat}) ? ++$cpus{$compat}: 1; + # AMD SOS chips appear to report full L2 cache per cpu + elsif ($cpu->{'type'} eq 'amd' && ($cpu->{'family'} eq '14' || + $cpu->{'family'} eq '15' || $cpu->{'family'} eq '16')){ + $caches->{'l2'} = $cpu->{'l2-cache'}; + } + elsif ($cpu->{'type'} ne 'intel'){ + $caches->{'l2'} = $cpu->{'l2-cache'} * $counts->{'cpu-cores'}; + } + # note: this handles how intel reports L2, total instead of per core like + # AMD does when cpuinfo sourced, when caches sourced, is per core as expected + else { + $caches->{'l2'} = $cpu->{'l2-cache'}; } } - main::log_data('dump','%cpus',\%cpus) if $b_log; + # l3 Cache - usually per physical cpu, but some rzyen will have per ccx. + if ($cpu->{'l3-cache'}){ + $caches->{'l3'} = $cpu->{'l3-cache'}; + } + # don't do anything with it, we have no ideaw if it's L1, L2, or L3, generic + # cpuinfo fallback, it's junk data essentially, and will show as cache: + # only use this fallback if no cache data was found + if ($cpu->{'cache'} && !$caches->{'l1'} && !$caches->{'l2'} && + !$caches->{'l3'}){ + $caches->{'cache'} = $cpu->{'cache'}; + $$cache_check = main::message('note-check'); + } eval $end if $b_log; - return %cpus; } - -sub cpu_arch { +sub cp_cpu_arch { eval $start if $b_log; my ($type,$family,$model,$stepping) = @_; - $stepping = 0 if !main::is_numeric($stepping); + # we can get various random strings for rev/stepping, particularly for arm,ppc + # but we want stepping to be integer for math comparisons, so convert, or set + # to 0 so it won't break anything. + if (defined $stepping && $stepping =~ /^[A-F0-9]{1,3}$/i){ + $stepping = hex($stepping); + } + else { + $stepping = 0 + } $family ||= ''; - $model ||= ''; + $model = '' if !defined $model; # model can be 0 my ($arch,$note) = ('',''); - my $check = main::row_defaults('note-check'); + my $check = main::message('note-check'); # See: docs/inxi-resources.txt # print "type:$type fam:$family model:$model step:$stepping\n"; if ($type eq 'amd'){ @@ -9775,12 +10499,16 @@ sub cpu_arch { $arch = 'Bobcat'} } elsif ($family eq '15'){ - if ($model =~ /^(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)$/){ + # note: only model 1 confirmd + if ($model =~ /^(0|1|3|4|5|6|7|8|9|A|B|C|D|E|F)$/){ $arch = 'Bulldozer'} - elsif ($model =~ /^(10|11|12|13|14|15|16|17|18|19|1A|1B|1C|1D|1E|1F)$/){ + # note: only 2,11,13 confirmed + elsif ($model =~ /^(2|10|11|12|13|14|15|16|17|18|19|1A|1B|1C|1D|1E|1F)$/){ $arch = 'Piledriver'} + # note: only 30,38 confirmed elsif ($model =~ /^(30|31|32|33|34|35|36|37|38|39|3A|3B|3C|3D|3E|3F)$/){ $arch = 'Steamroller'} + # note; only 60,65,70 confirmed elsif ($model =~ /^(60|61|62|63|64|65|66|67|68|69|6A|6B|6C|6D|6E|6F|70|71|72|73|74|75|76|77|78|79|7A|7B|7C|7D|7E|7F)$/){ $arch = 'Excavator'} else { @@ -9796,9 +10524,12 @@ sub cpu_arch { $arch = 'Jaguar'} } elsif ($family eq '17'){ - if ($model =~ /^(1|11|18|20)$/){ - $arch = 'Zen'} + # can't find stepping/model for no ht 2x2 core/die models, only first ones + if ($model =~ /^(1|11|20)$/){ + $arch = 'Zen'; + } # Seen: stepping 1 is Zen+ Ryzen 7 3750H. But stepping 1 Zen is: Ryzen 3 3200U + # AMD Ryzen 3 3200G is stepping 1, Zen+ # Unknown if stepping 0 is Zen or either. elsif ($model =~ /^(18)$/){ $arch = 'Zen/Zen+'; @@ -9806,14 +10537,17 @@ sub cpu_arch { } # shares model 8 with zen, stepping unknown elsif ($model =~ /^(8)$/){ - $arch = 'Zen+'} + $arch = 'Zen+'; + } # used this but it didn't age well: ^(2[0123456789ABCDEF]| elsif ($model =~ /^(31|47|60|68|71|90)$/){ - $arch = 'Zen 2'} + $arch = 'Zen 2'; + } else { $arch = 'Zen'; $note = $check;} } + # Joint venture between AMD and Chinese companies. Type amd? or hygon? elsif ($family eq '18'){ # model 0 $arch = 'Zen (Hygon Dhyana)'; @@ -9822,10 +10556,10 @@ sub cpu_arch { # model: 0 1 21 40 50 $arch = 'Zen 3'; } - # note: family 20 may be Zen 4 but not known for sure yet + # note: family 20 may be Zen 4 but not known for sure yet, zen 5 also in pipeline # elsif ($family eq '20'){ - # model: unknown - # $arch = 'Zen 4'; + # # model: unknown + # $arch = 'Zen 4'; # } } elsif ($type eq 'arm'){ @@ -9960,13 +10694,15 @@ sub cpu_arch { elsif ($model =~ /^(15)$/){ $arch = 'M Tolapai'} # pentium M system on chip elsif ($model =~ /^(17|1D)$/){ - $arch = 'Penryn'} - elsif ($model =~ /^(1A|1E|1F|25|2C|2E|2F)$/){ + $arch = 'Core Penryn'} + # had 25 also, but that's westmere, at least for stepping 2 + elsif ($model =~ /^(1A|1E|1F|2C|2E|2F)$/){ $arch = 'Nehalem'} elsif ($model =~ /^(1C|26)$/){ $arch = 'Bonnell'} # atom Bonnell? 27? elsif ($model =~ /^(27|35|36)$/){ $arch = 'Saltwell'} + # 25 may be nahelem in a stepping, check. Stepping 2 is westmere elsif ($model =~ /^(25|2C|2F)$/){ $arch = 'Westmere'} elsif ($model =~ /^(2A|2D)$/){ @@ -10066,7 +10802,11 @@ sub cpu_arch { elsif ($model =~ /^(3)$/){ $arch = 'Netburst Prescott'} # 6? Nocona elsif ($model =~ /^(4)$/){ - $arch = 'Netburst Smithfield'} # 6? Nocona + if ($stepping == 1){ + $arch = 'Netburst Prescott'} + else { + $arch = 'Netburst Smithfield'} # 6? Nocona + } elsif ($model =~ /^(6)$/){ $arch = 'Netburst Presler'} else { @@ -10084,27 +10824,344 @@ sub cpu_arch { } } eval $end if $b_log; - return ($arch,$note); + return [$arch,$note]; } - -sub count_alpha { - my ($count) = @_; - # print "$count\n"; +sub cp_cpu_topology { + my ($counts,$topology) = @_; my @alpha = qw(Single Dual Triple Quad); - if ($count > 4){ - $count .= '-'; + my ($sep) = (''); + my (%keys,%done); + my @tests = ('x'); # prefill [0] because iterator runs before 'next' test. + if ($counts->{'cpu-topo'}){ + # first we want to find out how many of each physical variant there are + foreach my $topo (@{$counts->{'cpu-topo'}}){ + # turn sorted hash into string + my $test = join('::', map{$_ . ':' . $topo->{$_}} sort keys %$topo); + if ($keys{$test}){ + $keys{$test}++; + } + else { + $keys{$test} = 1; + } + push(@tests,$test); + } + my ($i,$j) = (0,0); + # then we build up the topology data per variant + foreach my $topo (@{$counts->{'cpu-topo'}}){ + my $key = ''; + $i++; + next if $done{$tests[$i]}; + $done{$tests[$i]} = 1; + if ($b_admin && $type eq 'full'){ + $topology->{'full'}[$j]{'cpus'} = $keys{$tests[$i]}; + $topology->{'full'}[$j]{'cores'} = $topo->{'cores'}; + if ($topo->{'threads'} && $topo->{'cores'} != $topo->{'threads'}){ + $topology->{'full'}[$j]{'threads'} = $topo->{'threads'}; + } + if ($topo->{'dies'} && $topo->{'dies'} > 1){ + $topology->{'full'}[$j]{'dies'} = $topo->{'dies'}; + } + if ($counts->{'struct-mt'}){ + $topology->{'full'}[$j]{'cores-mt'} = $topo->{'cores-mt'}; + } + if ($counts->{'struct-st'}){ + $topology->{'full'}[$j]{'cores-st'} = $topo->{'cores-st'}; + } + if ($counts->{'struct-max'} || $counts->{'struct-min'}){ + $topology->{'full'}[$j]{'max'} = $topo->{'max'}; + $topology->{'full'}[$j]{'min'} = $topo->{'min'}; + } + if ($topo->{'smt'}){ + $topology->{'full'}[$j]{'smt'} = $topo->{'smt'}; + } + if ($topo->{'tpc'}){ + $topology->{'full'}[$j]{'tpc'} = $topo->{'tpc'}; + } + $j++; + } + else { + # start building string + $topology->{'string'} .= $sep; + $sep = ','; + if ($counts->{'physical'} > 1) { + my $phys = ($topology->{'struct-cores'}) ? $keys{$tests[$i]} : $counts->{'physical'}; + $topology->{'string'} .= $phys . 'x '; + $topology->{'string'} .= $topo->{'cores'} . '-core'; + } + else { + $topology->{'string'} .= cp_cpu_alpha($topo->{'cores'}); + } + # alder lake type cpu + if ($topo->{'cores-st'} && $topo->{'cores-mt'}){ + $topology->{'string'} .= ' (' . $topo->{'cores-mt'} . '-mt/'; + $topology->{'string'} .= $topo->{'cores-st'} . '-st)'; + } + # we only want to show > 1 phys short form basic if cpus have different + # core counts, not different min/max frequencies + last if !$topology->{'struct-cores'}; + } + } } else { - $count = $alpha[$count-1] . ' ' if $count > 0; + if ($counts->{'physical'} > 1) { + $topology->{'string'} = $counts->{'physical'} . 'x '; + $topology->{'string'} .= $counts->{'cpu-cores'} . '-core'; + } + else { + $topology->{'string'} = cp_cpu_alpha($counts->{'cpu-cores'}); + } } - return $count; + $topology->{'string'} ||= ''; +} +sub cp_cpu_alpha { + my $cores = $_[0]; + my $string = ''; + if ($cores > 4){ + $string = $cores . '-core'; + } + elsif ($cores == 0){ + $string = main::message('unknown-cpu-topology'); + } + else { + my @alpha = qw(single dual triple quad); + $string = $alpha[$cores-1] . ' core'; + } + return $string; } +# Logic: +# if > 1 processor && processor id (physical id) == core id then Multi threaded (MT) +# if siblings > 1 && siblings == 2 * num_of_cores ($cpu->{'cores'}) then Multi threaded (MT) +# if > 1 processor && processor id (physical id) != core id then Multi-Core Processors (MCP) +# if > 1 processor && processor ids (physical id) > 1 then Symmetric Multi Processing (SMP) +# if = 1 processor then single core/processor Uni-Processor (UP) +sub cp_cpu_type { + eval $start if $b_log; + my ($counts,$cpu,$tests) = @_; + my $cpu_type = ''; + if ($counts->{'processors'} > 1 || + (defined $tests->{'intel'} && $tests->{'intel'} && $cpu->{'siblings'} > 0)){ + # cpu_sys detected MT + if ($counts->{'struct-mt'}){ + if ($counts->{'struct-mt'} && $counts->{'struct-st'}){ + $cpu_type .= 'MST'; + } + else { + $cpu_type .= 'MT'; + } + } + # handle case of OpenBSD that has hw.smt but no other meaningful topology + elsif ($cpu->{'smt'}){ + $cpu_type .= 'MT' if $cpu->{'smt'} eq 'enabled'; + } + # non-multicore MT, with 2 or more threads per core + elsif ($counts->{'processors'} && $counts->{'physical'} && + $counts->{'cpu-cores'} && + $counts->{'processors'}/($counts->{'physical'} * $counts->{'cpu-cores'}) >= 2){ + # print "mt:1\n"; + $cpu_type .= 'MT'; + } + # 2 or more siblings per cpu real core + elsif ($cpu->{'siblings'} > 1 && $cpu->{'siblings'}/$counts->{'cpu-cores'} >= 2){ + # print "mt:3\n"; + $cpu_type .= 'MT'; + } + # non-MT multi-core or MT multi-core + if ($counts->{'cpu-cores'} > 1){ + if ($counts->{'struct-mt'} && $counts->{'struct-st'}){ + $cpu_type .= ' AMCP'; + } + else { + $cpu_type .= ' MCP'; + } + } + # only solidly known > 1 die cpus will use this + if ($cpu->{'dies'} > 1){ + $cpu_type .= ' MCM'; + } + # >1 cpu sockets active: Symetric Multi Processing + if ($counts->{'physical'} > 1){ + if ($counts->{'struct-cores'} || $counts->{'struct-max'} || + $counts->{'struct-min'}){ + $cpu_type .= ' AMP'; + } + else { + $cpu_type .= ' SMP'; + } + } + $cpu_type =~ s/^\s+//; + } + else { + $cpu_type = 'UP'; + } + eval $end if $b_log; + return $cpu_type; +} +# needed because no physical_id in cpuinfo, but > 1 cpu systems exist +# returns: 0 - per cpu cores; 1 - phys cpu count; 2 - override model defaul names +sub cp_elbrus_data { + eval $start if $b_log; + my ($family_id,$model_id,$count,$arch) = @_; + # 0: cores + my @return = (0,1,$arch); + my %cores = ( + # key=family id + model id + '41' => 1, + '42' => 1, + '43' => 4, + '44' => 2, + '46' => 1, + '47' => 8, + '48' => 1, + '49' => 8, + '59' => 8, + '4A' => 12, + '4B' => 16, + '4C' => 2, + '6A' => 12, + '6B' => 16, + '6C' => 2, + ); + $return[0] = $cores{$family_id . $model_id} if $cores{$family_id . $model_id}; + if ($return[0]){ + $return[1] = ($count % $return[0]) ? int($count/$return[0]) + 1 : $count/$return[0]; + } + eval $end if $b_log; + return @return; +} +sub cp_speed_data { + eval $start if $b_log; + my ($cpu,$cpu_sys) = @_; + my %info; + if (defined $cpu_sys->{'data'}){ + if (defined $cpu_sys->{'data'}{'speeds'}{'min-freq'}){ + $cpu->{'min-freq'} = $cpu_sys->{'data'}{'speeds'}{'min-freq'}; + } + if (defined $cpu_sys->{'data'}{'speeds'}{'max-freq'}){ + $cpu->{'max-freq'} = $cpu_sys->{'data'}{'speeds'}{'max-freq'}; + } + if (defined $cpu_sys->{'data'}{'speeds'}{'all'}){ + # only replace if we got actual speed values from cpufreq, or if no legacy + # sourced processors data. Handles fake syz core speeds for counts. + if ((grep {$_} @{$cpu_sys->{'data'}{'speeds'}{'all'}}) || + !@{$cpu->{'processors'}}){ + $cpu->{'processors'} = $cpu_sys->{'data'}{'speeds'}{'all'}; + } + } + if (defined $cpu_sys->{'data'}{'cpufreq-boost'}){ + $cpu->{'boost'} = $cpu_sys->{'data'}{'cpufreq-boost'}; + } + } + if (defined $cpu->{'processors'}){ + if (scalar @{$cpu->{'processors'}} > 1){ + my ($agg,$high) = (0,0); + for (@{$cpu->{'processors'}}){ + next if !$_; # bsds might have 0 or undef value, that's junk + $agg += $_; + $high = $_ if $_ > $high; + } + if ($agg){ + $cpu->{'avg-freq'} = int($agg/scalar @{$cpu->{'processors'}}); + $cpu->{'cur-freq'} = $high; + $info{'avg-speed-key'} = 'avg'; + $info{'speed'} = $cpu->{'avg-freq'}; + if ($high > $cpu->{'avg-freq'}){ + $cpu->{'high-freq'} = $high; + $info{'high-speed-key'} = 'high'; + } + } + } + elsif ($cpu->{'processors'}[0]) { + $cpu->{'cur-freq'} = $cpu->{'processors'}[0]; + $info{'speed'} = $cpu->{'cur-freq'}; + } + } + # BSDs generally will have processors count, but not per core speeds + if ($cpu->{'cur-freq'} && !$info{'speed'}){ + $info{'speed'} = $cpu->{'cur-freq'}; + } + # BSDs generally will have processors count, but not per core speeds + if ($cpu->{'min-freq'} && $cpu->{'max-freq'}){ + $info{'min-max'} = "$cpu->{'min-freq'}/$cpu->{'max-freq'}"; + $info{'min-max-key'} = "min/max"; + } + elsif ($cpu->{'max-freq'}){ + $info{'min-max'} = $cpu->{'max-freq'}; + $info{'min-max-key'} = "max"; + } + elsif ($cpu->{'min-freq'}){ + $info{'min-max'} = $cpu->{'min-freq'}; + $info{'min-max-key'} = "min"; + } + if ($cpu->{'cur-freq'}){ + if ($show{'short'}){ + $info{'speed-key'} = 'speed'; + } + elsif ($show{'cpu-basic'}){ + $info{'speed-key'} = 'speed (MHz)'; + } + else { + $info{'speed-key'} = 'Speed (MHz)'; + } + } + eval $end if $b_log; + return \%info; +} +# update $tests by reference +sub cp_test_types { + my ($cpu,$tests) = @_; + if ($cpu->{'type'} eq 'intel'){ + $$tests{'intel'} = 1; + $$tests{'xeon'} = 1 if $cpu->{'model_name'} =~ /Xeon/i; + } + elsif ($cpu->{'type'} eq 'amd'){ + if ($cpu->{'family'} && $cpu->{'family'} eq '17'){ + $$tests{'amd-zen'} = 1; + if ($cpu->{'model_name'}){ + if ($cpu->{'model_name'} =~ /Ryzen/i){ + $$tests{'ryzen'} = 1; + } + elsif ($cpu->{'model_name'} =~ /EPYC/i){ + $$tests{'epyc'} = 1; + } + } + } + } + elsif ($cpu->{'type'} eq 'elbrus'){ + $$tests{'elbrus'} = 1; + } +} + +## CPU UTILITIES ## +# only elbrus ID is actually used live +sub cpu_vendor { + eval $start if $b_log; + my ($string) = @_; + my ($vendor) = (''); + $string = lc($string); + if ($string =~ /intel/){ + $vendor = "intel" + } + elsif ($string =~ /amd/){ + $vendor = "amd" + } + # via + elsif ($string =~ /centaur/){ + $vendor = "centaur" + } + elsif ($string =~ /(e2k|elbrus)/){ + $vendor = "elbrus" + } + eval $end if $b_log; + return $vendor; +} +# do not define model-id, stepping, or revision, those can be 0 valid value sub set_cpu_data { my %cpu = ( 'arch' => '', + 'avg-freq' => 0, # MHz 'bogomips' => 0, 'cores' => 0, - 'cur-freq' => 0, + 'cur-freq' => 0, # MHz 'dies' => 0, 'family' => '', 'flags' => '', @@ -10112,20 +11169,48 @@ sub set_cpu_data { 'l1-cache' => 0, # store in KB 'l2-cache' => 0, # store in KB 'l3-cache' => 0, # store in KB - 'max-freq' => 0, - 'min-freq' => 0, - 'model_id' => undef, + 'max-freq' => 0, # MHz + 'min-freq' => 0, # MHz 'model_name' => '', 'processors' => [], - 'rev' => '', 'scalings' => [], 'siblings' => 0, 'type' => '', ); return %cpu; } +sub system_cpu_name { + eval $start if $b_log; + my (%cpus,$compat,@working); + if (@working = main::globber('/sys/firmware/devicetree/base/cpus/cpu@*/compatible')){ + foreach my $file (@working){ + $compat = main::reader($file,'',0); + next if $compat =~ /timer/; # seen on android + # these can have non printing ascii... why? As long as we only have the + # splits for: null 00/start header 01/start text 02/end text 03 + $compat = (split(/\x01|\x02|\x03|\x00/, $compat))[0] if $compat; + $compat = (split(/,\s*/, $compat))[-1] if $compat; + $cpus{$compat} = ($cpus{$compat}) ? ++$cpus{$compat}: 1; + } + } + # synthesize it, [4] will be like: cortex-a15-timer; sunxi-timer + # so far all with this directory show soc name, not cpu name for timer + elsif (! -d '/sys/firmware/devicetree/base' && $devices{'timer'}){ + foreach my $working (@{$devices{'timer'}}){ + next if $working->[0] ne 'timer' || !$working->[4] || $working->[4] =~ /timer-mem$/; + $working->[4] =~ s/(-system)?-timer$//; + $compat = $working->[4]; + $cpus{$compat} = ($cpus{$compat}) ? ++$cpus{$compat}: 1; + } + } + main::log_data('dump','%cpus',\%cpus) if $b_log; + eval $end if $b_log; + return \%cpus; +} + +## CLEANERS/OUTPUT HANDLERS ## # MHZ - cell cpus -sub speed_cleaner { +sub clean_speed { my ($speed,$opt) = @_; return if !$speed || $speed eq '0'; $speed =~ s/[GMK]HZ$//gi; @@ -10133,7 +11218,7 @@ sub speed_cleaner { $speed = sprintf("%.0f", $speed); return $speed; } -sub cpu_cleaner { +sub clean_cpu { my ($cpu) = @_; return if !$cpu; my $filters = '@|cpu |cpu deca|([0-9]+|single|dual|two|triple|three|tri|quad|four|'; @@ -10148,7 +11233,11 @@ sub hex_and_decimal { my ($data) = @_; $data = '' if !defined $data; if ($data =~ /\S/){ - $data .= ' (' . hex($data) . ')' if hex($data) ne $data; + # only handle if a short hex number!! No need to prepend 0x to 0-9 + if ($data =~ /^[0-9a-f]{1,3}$/i && hex($data) ne $data){ + $data .= ' (' . hex($data) . ')'; + $data = '0x' . $data; + } } else { $data = 'N/A'; @@ -10181,13 +11270,13 @@ sub get { $key1 = 'Drive Report'; my $file = $system_files{'dmesg-boot'}; if ($file && ! -r $file){ - $val1 = main::row_defaults('dmesg-boot-permissions'); + $val1 = main::message('dmesg-boot-permissions'); } elsif (!$file){ - $val1 = main::row_defaults('dmesg-boot-missing'); + $val1 = main::message('dmesg-boot-missing'); } else { - $val1 = main::row_defaults('disk-data-bsd'); + $val1 = main::message('disk-data-bsd'); } push(@rows,{main::key($num++,0,1,$key1) => $val1,}); } @@ -10200,12 +11289,12 @@ sub get { } else { $key1 = 'Message'; - $val1 = main::row_defaults('disk-data'); + $val1 = main::message('disk-data'); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } if (!@rows){ $key1 = 'Message'; - $val1 = main::row_defaults('disk-data'); + $val1 = main::message('disk-data'); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } # push(@rows,@data); @@ -10327,14 +11416,14 @@ sub drive_output { if ($extra > 1){ if (!$row->{'serial'} && $alerts{'bioctl'} && $alerts{'bioctl'}->{'action'} eq 'permissions'){ - $row->{'serial'} = main::row_defaults('root-required'); + $row->{'serial'} = main::message('root-required'); } else { - $row->{'serial'} = main::apply_filter($row->{'serial'}); + $row->{'serial'} = main::filter($row->{'serial'}); } $rows[$j]->{main::key($num++,0,2,'serial')} = $row->{'serial'}; if ($row->{'drive-serial'}){ - $rows[$j]->{main::key($num++,0,2,'drive serial')} = main::apply_filter($row->{'drive-serial'}); + $rows[$j]->{main::key($num++,0,2,'drive serial')} = main::filter($row->{'drive-serial'}); } if ($row->{'firmware'}){ $rows[$j]->{main::key($num++,0,2,'rev')} = $row->{'firmware'}; @@ -10348,10 +11437,10 @@ sub drive_output { } if ($extra > 1 && $alerts{'bioctl'}){ if (!$row->{'duid'} && $alerts{'bioctl'}->{'action'} eq 'permissions'){ - $rows[$j]->{main::key($num++,0,2,'duid')} = main::row_defaults('root-required'); + $rows[$j]->{main::key($num++,0,2,'duid')} = main::message('root-required'); } elsif ($row->{'duid'}){ - $rows[$j]->{main::key($num++,0,2,'duid')} = main::apply_filter($row->{'duid'}); + $rows[$j]->{main::key($num++,0,2,'duid')} = main::filter($row->{'duid'}); } } # extra level tests already done @@ -10626,7 +11715,7 @@ sub proc_data_advanced { } # maybe rework logic if find good scsi data example, but for now use this elsif ($drives->[$i]{'model'} && !$drives->[$i]{'vendor'}){ - $drives->[$i]{'model'} = main::disk_cleaner($drives->[$i]{'model'}); + $drives->[$i]{'model'} = main::clean_disk($drives->[$i]{'model'}); my @device_data = device_vendor($drives->[$i]{'model'},''); $drives->[$i]{'model'} = $device_data[1] if $device_data[1]; $drives->[$i]{'vendor'} = $device_data[0] if $device_data[0]; @@ -10701,10 +11790,10 @@ sub bsd_data { DiskDataBSD::set() if !$loaded{'disk-data-bsd'}; # we don't want non dboot disk data from gpart or disklabel if ($file && ! -r $file){ - $size = main::row_defaults('dmesg-boot-permissions'); + $size = main::message('dmesg-boot-permissions'); } elsif (!$file){ - $size = main::row_defaults('dmesg-boot-missing'); + $size = main::message('dmesg-boot-missing'); } elsif (%disks_bsd){ if ($sysctl{'softraid'}){ @@ -10752,7 +11841,7 @@ sub bsd_data { $logical_size = ($size - $raw_logical[1] + $raw_logical[0]); } if (!$size){ - $size = main::row_defaults('data-bsd'); + $size = main::message('data-bsd'); } } @data = ({ @@ -10884,20 +11973,20 @@ sub smartctl_data { print 'Drive:/dev/' . $id . ":\n", Data::Dumper::Dumper\@result if $dbg[12]; if (scalar @result < 5){ if (grep {/failed: permission denied/i} @result){ - $data->[$i]{'smart-permissions'} = main::row_defaults('tool-permissions','smartctl'); + $data->[$i]{'smart-permissions'} = main::message('tool-permissions','smartctl'); } elsif (grep {/unknown usb bridge/i} @result){ - $data->[$i]{'smart-error'} = main::row_defaults('smartctl-usb'); + $data->[$i]{'smart-error'} = main::message('smartctl-usb'); } # can come later in output too elsif (grep {/A mandatory SMART command failed/i} @result){ - $data->[$i]{'smart-error'} = main::row_defaults('smartctl-command'); + $data->[$i]{'smart-error'} = main::message('smartctl-command'); } elsif (grep {/open device.*Operation not supported by device/i} @result){ - $data->[$i]{'smart-error'} = main::row_defaults('smartctl-open'); + $data->[$i]{'smart-error'} = main::message('smartctl-open'); } else { - $data->[$i]{'smart-error'} = main::row_defaults('tool-unknown-error','smartctl'); + $data->[$i]{'smart-error'} = main::message('tool-unknown-error','smartctl'); } next; } @@ -10921,7 +12010,7 @@ sub smartctl_data { } # can occur later in output so retest it here if ($split[$a] =~ /A mandatory SMART command failed/i){ - $data->[$i]{'smart-error'} = main::row_defaults('smartctl-command'); + $data->[$i]{'smart-error'} = main::message('smartctl-command'); } ## DEVICE INFO ## if ($split[$a] eq 'Device Model'){ @@ -11137,7 +12226,7 @@ sub smartctl_data { elsif ($split[$a] eq 'UDMA_CRC_Error_Count'){ if (main::is_numeric($split[$r]) && $split[$r] > 50){ $data->[$i]{'smart-udma-crc-errors-ar'} = $split[$r]; - $data->[$i]{'smart-udma-crc-errors-f'} = main::row_defaults('smartctl-udma-crc') if $split[$r] > 500; + $data->[$i]{'smart-udma-crc-errors-f'} = main::message('smartctl-udma-crc') if $split[$r] > 500; } } @@ -11401,7 +12490,7 @@ sub disk_data_by_id { $model = join(' ', @data); # get rid of the ata-|nvme-|mmc- etc $model =~ s/^\/dev\/disk\/by-id\/([^-]+-)?//; - $model = main::disk_cleaner($model); + $model = main::clean_disk($model); @device_data = device_vendor($model,$serial); $vendor = $device_data[0] if $device_data[0]; $model = $device_data[1] if $device_data[1]; @@ -11422,14 +12511,14 @@ sub set_vendors { # H10 HBRPEKNX0202A NVMe INTEL 512GB ['(\bINTEL\b|^SSD(PAM|SA2))','\bINTEL\b','Intel',''], # note: S[AV][1-9][0-9] can trigger false positives - ['(KINGSTON|DataTraveler|DT\s?(DUO|Microduo|101)|^RBU|^SMS|^SHS|^SS0|^SUV|^T52|^T[AB]29|^Ultimate CF|HyperX|^S[AV][1234]00|^SKYMEDI|13fe\b)','KINGSTON','Kingston',''], # maybe SHS: SHSS37A SKC SUV + ['(K(ING)?STON|DataTraveler|DT\s?(DUO|Microduo|101)|^RBU|^SMS|^SHS|^SS0|^SUV|^T52|^T[AB]29|^Ultimate CF|HyperX|^S[AV][1234]00|^SKYMEDI|13fe\b)','KINGSTON','Kingston',''], # maybe SHS: SHSS37A SKC SUV # must come before samsung MU. NOTE: toshiba can have: TOSHIBA_MK6475GSX: mush: MKNSSDCR120GB_ ['(^MKN|Mushkin)','Mushkin','Mushkin',''], # MKNS # MU = Multiple_Flash_Reader too risky: |M[UZ][^L] HD103SI HD start risky # HM320II HM320II - ['(SAMSUNG|^MCG[0-9]+GC|^MCC|^MCBOE|\bEVO\b|^[GS]2 Portable|^DS20|^[DG]3 Station|^DUO\b|^P3|^[BC]GN|^[CD]JN|^BJ[NT]|^[BC]WB|^(HM|SP)[0-9]{2}|^MZMPC|^HD[0-9]{3}[A-Z]{2}$|^G[CD][1-9][QS]|^M[AB]G[0-9][FG]|SV[0-9]|[BE][A-Z][1-9]QT|YP\b)','SAMSUNG','Samsung',''], # maybe ^SM, ^HM + ['(SAMSUNG|^MCG[0-9]+GC|^CKT|^DUT|^MCC|^MCBOE|\bEVO\b|^[GS]2 Portable|^DS20|^[DG]3 Station|^DUO\b|^P3|^[BC]GN|^[CD]JN|^BJ[NT]|^[BC]WB|^(HM|SP)[0-9]{2}|^MZMPC|^HD[0-9]{3}[A-Z]{2}$|^G[CD][1-9][QS]|^M[AB]G[0-9][FG]|SV[0-9]|[BE][A-Z][1-9]QT|YP\b)','SAMSUNG','Samsung',''], # maybe ^SM, ^HM # Android UMS Composite? - ['(SanDisk|^SDS[S]?[DQ]|^D[AB]4|^SL([0-9]+)G|^AFGCE|^ABLCD|^SDW[1-9]|^SEM[1-9]|^U3\b|^SU[0-9]|^DX[1-9]|^S[CD][0-9]{2}G|ULTRA\s(FIT|trek)|Clip Sport|Cruzer|^Extreme|iXpand|SSD (Plus|U100) [1-9])','SanDisk','SanDisk',''], + ['(SanDisk|^SDS[S]?[DQ]|^D[AB]4|^SL([0-9]+)G|^AFGCE|^ABLCD|^SDW[1-9]|^SEM[1-9]|^U3\b|^SU[0-9]|^DX[1-9]|^S[CD][0-9]{2}G|ULTRA\s(FIT|trek)|Clip Sport|Cruzer|^Extreme|iXpand|SSD (Plus|U100) [1-9]|0781)','(SanDisk|0781)','SanDisk',''], # these are HP/Sandisk cobranded. DX110064A5xnNMRI ids as HP and Sandisc ['(^DX[1-9])','^(HP\b|SANDDISK)','Sandisk/HP',''], # ssd drive, must come before seagate ST test # real, SSEAGATE Backup+; XP1600HE30002 | 024 HN (spinpoint) ; possible usb: 24AS @@ -11439,6 +12528,7 @@ sub set_vendors { # rare cases WDC is in middle of string ['(\bWDC\b|1002FAEX)','','Western Digital',''], ## THEN BETTER KNOWN ONESs ## + ['^Acer','^Acer','Acer',''], # A-Data can be in middle of string ['^(.*\bA-?DATA|ASP[0-9]|AX[MN]|CH11|HV[1-9]|IM2|HD[1-9]|HDD\s?CH|IUM)','A-?DATA','A-Data',''], ['^(ASUS|ROG)','^ASUS','ASUS',''], # ROG ESD-S1C @@ -11463,10 +12553,11 @@ sub set_vendors { ['^(PNY|Hook\s?Attache|SSD2SC|(SSD7?)?EP7)','^PNY\s','PNY','','^PNY'], # note: get rid of: M[DGK] becasue mushkin starts with MK # note: seen: KXG50ZNV512G NVMe TOSHIBA 512GB | THNSN51T02DUK NVMe TOSHIBA 1024GB - ['(^[S]?TOS|^THN|TOSHIBA|TransMemory|^M[GKQ][0-9]|KBG4|^HDW|^SA[0-9]{2}G$|^(008|016|032|064|128)G[379E][0-9A]$)','[S]?TOSHIBA','Toshiba',''], # scsi-STOSHIBA_STOR.E_EDITION_ + ['(^[S]?TOS|^THN|TOSHIBA|TransMemory|^M[GKQ][0-9]|KBG4|^HDW|^SA[0-9]{2}G$|^(008|016|032|064|128)G[379E][0-9A]$|0930)','[S]?(TOSHIBA|0930)','Toshiba',''], # scsi-STOSHIBA_STOR.E_EDITION_ ## LAST: THEY ARE SHORT AND COULD LEAD TO FALSE ID, OR ARE UNLIKELY ## # unknown: AL25744_12345678; ADP may be usb 2.5" adapter; udisk unknown: Z1E6FTKJ 00AAKS # SSD2SC240G726A10 MRS020A128GTS25C EHSAJM0016GB + ['^(Alcor(\s?Micro)?|058F)','^(Alcor(\s?Micro)?|058F)','Alcor Micro',''], ['^2[\s-]?Power','^2[\s-]?Power','2-Power',''], ['^(3ware|9650SE)','^3ware','3ware (controller)',''], ['^5ACE','^5ACE','5ACE',''], # could be seagate: ST316021 5ACE @@ -11474,7 +12565,7 @@ sub set_vendors { ['^(AbonMax|ASU[0-9])','^AbonMax','AbonMax',''], ['^Acasis','^Acasis','Acasis (hub)',''], ['^Acclamator','^Acclamator','Acclamator',''], - ['^(Actions|HS USB Flash)','^Actions','Actions',''], + ['^(Actions|HS USB Flash|10d6)','^(Actions|10d6)','Actions',''], ['^Addlink','^Addlink','Addlink',''], ['^(ADplus|SuperVer\b)','^ADplus','ADplus',''], ['^ADTRON','^ADTRON','Adtron',''], @@ -11507,6 +12598,7 @@ sub set_vendors { ['^BIOSTAR','^BIOSTAR','Biostar',''], ['^BIWIN','^BIWIN','BIWIN',''], ['^Blackpcs','^Blackpcs','Blackpcs',''], + ['^(BlueRay|SDM[0-9])','^BlueRay','BlueRay',''], ['^Bory','^Bory','Bory',''], ['^Braveeagle','^Braveeagle','BraveEagle',''], ['^(BUFFALO|BSC)','^BUFFALO','Buffalo',''], # usb: BSCR05TU2 @@ -11531,6 +12623,7 @@ sub set_vendors { ['^DATABAR','^DATABAR','DataBar',''], # Daplink vfs is an ARM software thing ['^Dataram','^Dataram','Dataram',''], + ['^DELAIHE','^DELAIHE','DELAIHE',''], # DataStation can be Trekstore or I/O gear ['^Dell\b','^Dell','Dell',''], ['^DeLOCK','^Delock(\s?products)?','Delock',''], @@ -11546,7 +12639,7 @@ sub set_vendors { ['^(Dogfish|Shark)','^Dogfish(\s*Technology)?','Dogfish Technology',''], ['^DragonDiamond','^DragonDiamond','DragonDiamond',''], ['^DREVO\b','^DREVO','Drevo',''], - ['^DREVO\b','^DREVO','Drevo',''], + ['^DSS','^DSS DAHUA','DSS DAHUA',''], ['^(Dynabook|AE[1-3]00)','^Dynabook','Dynabook',''], # DX1100 is probably sandisk, but could be HP, or it could be hp branded sandisk ['^(Eaget|V8$)','^Eaget','Eaget',''], @@ -11563,8 +12656,10 @@ sub set_vendors { ['^EURS','^EURS','EURS',''], # NOTE: ESA3... may be IBM PCIe SAD card/drives ['^(EXCELSTOR|r technology)','^EXCELSTOR( TECHNO(LOGY)?)?','ExcelStor',''], + ['^EYOTA','^EYOTA','EYOTA',''], ['^EZLINK','^EZLINK','EZLINK',''], ['^Fantom','^Fantom( Drive[s]?)?','Fantom Drives',''], + ['^Fanxiang','^Fanxiang','Fanxiang',''], ['^Faspeed','^Faspeed','Faspeed',''], ['^FASTDISK','^FASTDISK','FASTDISK',''], ['^Festtive','^Festtive','Festtive',''], @@ -11580,12 +12675,14 @@ sub set_vendors { ['^Geil','^Geil','Geil',''], ['^GelL','^GelL','GelL',''], # typo for Geil? GelL ZENITH R3 120GB ['^(Generic|UY[67])','^Generic','Generic',''], + ['^(Genesis(\s?Logic)?|05e3)','(Genesis(\s?Logic)?|05e3)','Genesis Logic',''], ['^Geonix','^Geonix','Geonix',''], ['^Getrich','^Getrich','Getrich',''], ['^Gigabyte','^Gigabyte','Gigabyte',''], # SSD ['^Gigastone','^Gigastone','Gigastone',''], ['^Gigaware','^Gigaware','Gigaware',''], ['^Gloway','^Gloway','Gloway',''], + ['^GLOWY','^GLOWY','Glowy',''], ['^Goldendisk','^Goldendisk','Goldendisk',''], ['^Goldenfir','^Goldenfir','Goldenfir',''], # Wilk Elektronik SA, poland @@ -11617,7 +12714,7 @@ sub set_vendors { ['^(Initio)','^Initio','Initio',''], ['^Inland','^Inland','Inland',''], ['^(InnoDisk|Innolite|SATA\s?Slim)','^InnoDisk( Corp.)?','InnoDisk',''], - ['Innostor','Innostor','Innostor',''], + ['(Innostor|1f75)','(Innostor|1f75)','Innostor',''], ['(^Innovation|Innovation\s?IT)','Innovation(\s*IT)?','Innovation IT',''], ['^Innovera','^Innovera','Innovera',''], ['^Intaiel','^Intaiel','Intaiel',''], @@ -11659,12 +12756,13 @@ sub set_vendors { # LENSE30512GMSP34MEAT3TA / UMIS RPITJ256PED2MWX ['^(LEN|UMIS)','^Lenovo','Lenovo',''], ['^RPFT','','Lenovo O.E.M.',''], - # JAJS300M120C JAJM600M256C JAJS600M1024C JAJS600M256C - ['^(Leven|JAJ[MS][1-9])','^Leven','Leven',''], + # JAJS300M120C JAJM600M256C JAJS600M1024C JAJS600M256C JAJMS600M128G + ['^(Leven|JAJ[MS])','^Leven','Leven',''], ['^LG\b','^LG','LG',''], ['(LITE[-\s]?ON[\s-]?IT)','LITE[-]?ON[\s-]?IT','LITE-ON IT',''], # LITEONIT_LSS-24L6G ['(LITE[-\s]?ON|^PH[1-9])','LITE[-]?ON','LITE-ON',''], # PH6-CE240-L; CL1-3D256-Q11 NVMe LITEON 256GB ['^LONDISK','^LONDISK','LONDISK',''], + ['^Longline','^Longline','Longline',''], ['^(LSI|MegaRAID)','^LSI\b','LSI',''], ['^(M-Systems|DiskOnKey)','^M-Systems','M-Systems',''], ['^(Mach\s*Xtreme|MXSSD|MXU|MX[\s-])','^Mach\s*Xtreme','Mach Xtreme',''], @@ -11686,9 +12784,11 @@ sub set_vendors { ['^MGTEC','^MGTEC','MGTEC',''], ['^(Microsoft|S31)','^Microsoft','Microsoft',''], ['^MidasForce','^MidasForce','MidasForce',''], + ['^Milan','^Milan','Milan',''], ['^(Mimoco|Mimobot)','^Mimoco','Mimoco',''], ['^MINIX','^MINIX','MINIX',''], ['^Miracle','^Miracle','Miracle',''], + ['^MLLSE','^MLLSE','MLLSE',''], ['^Moba','^Moba','Moba',''], # Monster MONSTER DIGITAL ['^(Monster\s)+(Digital)?|OD[\s-]?ADVANCE','^(Monster\s)+(Digital)?','Monster Digital',''], @@ -11750,7 +12850,7 @@ sub set_vendors { ['^(Sea\s?Tech|Transformer)','^Sea\s?Tech','Sea Tech',''], ['^SigmaTel','^SigmaTel','SigmaTel',''], # DIAMOND_040_GB - ['^(SILICON\s?MOTION|SM[0-9])','^SILICON\s?MOTION','Silicon Motion',''], + ['^(SILICON\s?MOTION|SM[0-9]|090c)','^(SILICON\s?MOTION|090c)','Silicon Motion',''], ['(Silicon[\s-]?Power|^SP[CP]C|^Silicon|^Diamond|^HasTopSunlightpeed)','Silicon[\s-]?Power','Silicon Power',''], ['^SINTECHI?','^SINTECHI?','SinTech (adapter)',''], ['^SiS\b','^SiS','SiS',''], @@ -11795,11 +12895,13 @@ sub set_vendors { ['^TopSunligt','^TopSunligt','TopSunligt',''], # is this a typo? hard to know ['^TopSunlight','^TopSunlight','TopSunlight',''], ['^TOROSUS','^TOROSUS','Torosus',''], - ['^([F]?TS|Transcend|JetDrive|JetFlash|USDU|EZEX)','^Transcend','Transcend',''], + ['^([F]?TS|Transcend|JetDrive|JetFlash|USDU|EZEX|1307)','^(Transcend|1307)','Transcend',''], ['^(TrekStor|DS (maxi|pocket)|DataStation)','^TrekStor','TrekStor',''], + ['^Turbox','^Turbox','Turbox',''], ['^(TwinMOS|TW[0-9])','^TwinMOS','TwinMOS',''], # note: udisk means usb disk, it's not a vendor ID ['^UDinfo','^UDinfo','UDinfo',''], + ['^UMAX','^UMAX','UMAX',''], ['^USBTech','^USBTech','USBTech',''], ['^(UNIC2)','^UNIC2','UNIC2',''], ['^(UG|Unigen)','^Unigen','Unigen',''], @@ -12072,7 +13174,7 @@ sub device_speed { else { $working = "/sys/class/ata_link/link$id/sata_spd"; $speed = main::reader($working,'',0) if -r $working; - $speed = main::disk_cleaner($speed) if $speed; + $speed = main::clean_disk($speed) if $speed; $speed =~ s/Gbps/Gb\/s/ if $speed; } } @@ -12093,11 +13195,10 @@ sub get { eval $start if $b_log; my (@rows); my $num = 0; - if (($b_arm || $b_mips) && !$use{'soc-gfx'} && !$use{'pci-tool'}){ - my $type = ($b_arm) ? 'arm' : 'mips'; + if (%risc && !$use{'soc-gfx'} && !$use{'pci-tool'}){ my $key = 'Message'; push(@rows, { - main::key($num++,0,1,$key) => main::row_defaults($type . '-pci',''), + main::key($num++,0,1,$key) => main::message('risc-pci',$risc{'id'}), },); } else { @@ -12109,7 +13210,7 @@ sub get { $type = 'pci-card-data-root'; } push(@rows, { - main::key($num++,0,1,$key) => main::row_defaults($type,''), + main::key($num++,0,1,$key) => main::message($type,''), },); } } @@ -12140,10 +13241,10 @@ sub device_output { $driver = $row->[9]; $driver ||= 'N/A'; my $device = main::trimmer($row->[4]); - $device = ($device) ? main::pci_cleaner($device,'output') : 'N/A'; + $device = ($device) ? main::clean_pci($device,'output') : 'N/A'; # have seen absurdly verbose card descriptions, with non related data etc - if (length($device) > 85 || $size{'max'} < 110){ - $device = main::pci_long_filter($device); + if (length($device) > 85 || $size{'max-cols'} < 110){ + $device = main::filter_pci_long($device); } push(@rows, { main::key($num++,1,1,'Device') => $device, @@ -12188,7 +13289,7 @@ sub usb_output { $j = scalar @rows; # make sure to reset, or second device trips last flag ($driver,$path_id,$product) = ('','',''); - $product = main::cleaner($row->[13]) if $row->[13]; + $product = main::clean($row->[13]) if $row->[13]; $driver = $row->[15] if $row->[15]; $path_id = $row->[2] if $row->[2]; $product ||= 'N/A'; @@ -12217,7 +13318,7 @@ sub usb_output { $rows[$j]->{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]"; } if ($extra > 2 && $row->[16]){ - $rows[$j]->{main::key($num++,0,2,'serial')} = main::apply_filter($row->[16]); + $rows[$j]->{main::key($num++,0,2,'serial')} = main::filter($row->[16]); } } eval $end if $b_log; @@ -12270,7 +13371,7 @@ sub display_output(){ } my @drivers = x_drivers(); if (!$protocol && !$server_string && !$graphics{'x-vendor'} && !@drivers){ - $server_string = main::row_defaults('display-server'); + $server_string = main::message('display-server'); @row = ({ main::key($num++,1,1,'Display') => '', main::key($num++,0,2,'server') => $server_string, @@ -12298,14 +13399,14 @@ sub display_output(){ # $driver comes from the Device lines, and is just last fallback. if ($driver && $driver ne 'N/A'){ if (-e '/var/lib/gdm' && !$b_root){ - $driver_missing = main::row_defaults('display-driver-na') . ' - ' . main::row_defaults('root-suggested'); + $driver_missing = main::message('display-driver-na') . ' - ' . main::message('root-suggested'); } else { - $driver_missing = main::row_defaults('display-driver-na'); + $driver_missing = main::message('display-driver-na'); } } else { - $driver_missing = main::row_defaults('root-suggested') if -e '/var/lib/gdm' && !$b_root; + $driver_missing = main::message('root-suggested') if -e '/var/lib/gdm' && !$b_root; } } else { @@ -12610,7 +13711,7 @@ sub display_data_x { } } else { - $graphics{'no-xdpyinfo'} = main::row_defaults('tool-missing-basic','xdpyinfo'); + $graphics{'no-xdpyinfo'} = main::message('tool-missing-basic','xdpyinfo'); } print 'last: ', Data::Dumper::Dumper $graphics{'screens'} if $dbg[17]; main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log; @@ -12692,7 +13793,7 @@ sub gl_output(){ $type = 'display-null'; } @row = ({ - main::key($num++,0,1,'Message') => main::row_defaults($type), + main::key($num++,0,1,'Message') => main::message($type), }); return @row; } @@ -12705,7 +13806,7 @@ sub gl_output(){ if (/^opengl renderer/i){ @working = split(/:\s*/, $_, 2); if ($working[1]){ - $working[1] = main::cleaner($working[1]); + $working[1] = main::clean($working[1]); # Allow all mesas # if ($working[1] =~ /mesa/i){ # @@ -12715,7 +13816,7 @@ sub gl_output(){ # field value occurs. else { $b_nogl = 1; - $working[1] = main::row_defaults('gl-empty'); + $working[1] = main::message('gl-empty'); } push(@renderer, $working[1]); } @@ -12737,7 +13838,7 @@ sub gl_output(){ $compat_version = $working[0]; } elsif (!$b_nogl){ - push(@opengl_version, main::row_defaults('gl-empty')); + push(@opengl_version, main::message('gl-empty')); } } elsif (/^opengl core profile version/i){ @@ -12788,7 +13889,7 @@ sub gl_output(){ } else { @row = ({ - main::key($num++,0,1,'Message') => main::row_defaults('glxinfo-missing'), + main::key($num++,0,1,'Message') => main::message('glxinfo-missing'), }); } } @@ -12806,7 +13907,7 @@ sub gl_output(){ } } @row = ({ - main::key($num++,0,1,'Message') => main::row_defaults($type), + main::key($num++,0,1,'Message') => main::message($type), }); } eval $end if $b_log; @@ -13058,7 +14159,7 @@ sub get { my $num = 0; if ($bsd_type){ $key1 = 'Message'; - $val1 = main::row_defaults('logical-data-bsd',$uname[0]); + $val1 = main::message('logical-data-bsd',$uname[0]); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } else { @@ -13068,7 +14169,7 @@ sub get { if (!@lvm){ my $key = 'Message'; # note: arch linux has a bug where lvs returns 0 if non root start - my $message = ($use{'logical-lvm'}) ? main::row_defaults('tool-permissions','lvs') : main::row_defaults('logical-data',''); + my $message = ($use{'logical-lvm'}) ? main::message('tool-permissions','lvs') : main::message('logical-data',''); push(@rows, { main::key($num++,0,1,$key) => $message, },); @@ -13088,7 +14189,7 @@ sub get { $alerts{'lvs'}->{'action'} eq 'missing')){ my $key = 'Message'; push(@rows, { - main::key($num++,0,1,$key) => main::row_defaults('logical-data',''), + main::key($num++,0,1,$key) => main::message('logical-data',''), },); } elsif ($alerts{'lvs'}->{'action'} ne 'use'){ @@ -13425,7 +14526,7 @@ sub get { } elsif (!$key1){ $key1 = 'Message'; - $val1 = main::row_defaults('machine-data-force-dmidecode',''); + $val1 = main::message('machine-data-force-dmidecode',''); } } elsif ($bsd_type || $force{'dmidecode'}){ @@ -13441,7 +14542,7 @@ sub get { } elsif (!$key1){ $key1 = 'Message'; - $val1 = main::row_defaults('machine-data'); + $val1 = main::message('machine-data'); } } } @@ -13453,22 +14554,22 @@ sub get { else { $key1 = 'Message'; if ($alerts{'dmidecode'}->{'action'} eq 'missing'){ - $val1 = main::row_defaults('machine-data-dmidecode'); + $val1 = main::message('machine-data-dmidecode'); } else { - $val1 = main::row_defaults('machine-data'); + $val1 = main::message('machine-data'); } } } elsif (!$bsd_type){ # this uses /proc/cpuinfo so only GNU/Linux - if ($b_arm || $b_mips || $b_ppc){ + if (%risc){ %data = machine_data_soc(); @rows = machine_soc_output(\%data) if %data; } if (!%data){ $key1 = 'Message'; - $val1 = main::row_defaults('machine-data-force-dmidecode',''); + $val1 = main::message('machine-data-force-dmidecode',''); } } # if error case, null data, whatever @@ -13527,14 +14628,14 @@ sub machine_output { },); if (!$b_skip_system){ # this has already been tested for above so we know it's not null - $system_vendor = main::cleaner($data->{'sys_vendor'}); + $system_vendor = main::clean($data->{'sys_vendor'}); $product_name = ($data->{'product_name'}) ? $data->{'product_name'}:'N/A'; $product_version = ($data->{'product_version'}) ? $data->{'product_version'}:'N/A'; - $product_serial = main::apply_filter($data->{'product_serial'}); + $product_serial = main::filter($data->{'product_serial'}); $rows[$j]->{main::key($num++,1,1,'System')} = $system_vendor; - $rows[$j]->{main::key($num++,0,2,'product')} = $product_name; - $rows[$j]->{main::key($num++,0,2,'v')} = $product_version; - $rows[$j]->{main::key($num++,0,2,'serial')} = $product_serial; + $rows[$j]->{main::key($num++,1,2,'product')} = $product_name; + $rows[$j]->{main::key($num++,0,3,'v')} = $product_version; + $rows[$j]->{main::key($num++,0,3,'serial')} = $product_serial; # no point in showing chassis if system isn't there, it's very unlikely that # would be correct if ($extra > 1){ @@ -13554,7 +14655,7 @@ sub machine_output { $chassis_version = $data->{'chassis_version'}; $chassis_version =~ s/^v([0-9])/$1/i; } - $chassis_serial = main::apply_filter($data->{'chassis_serial'}); + $chassis_serial = main::filter($data->{'chassis_serial'}); $chassis_vendor ||= ''; $chassis_type ||= ''; $rows[$j]->{main::key($num++,1,1,'Chassis')} = $chassis_vendor; @@ -13572,11 +14673,11 @@ sub machine_output { if ($data->{'firmware'}){ $firmware = $data->{'firmware'}; } - $mobo_vendor = ($data->{'board_vendor'}) ? main::cleaner($data->{'board_vendor'}) : 'N/A'; + $mobo_vendor = ($data->{'board_vendor'}) ? main::clean($data->{'board_vendor'}) : 'N/A'; $mobo_model = ($data->{'board_name'}) ? $data->{'board_name'}: 'N/A'; $mobo_version = ($data->{'board_version'})? $data->{'board_version'} : ''; - $mobo_serial = main::apply_filter($data->{'board_serial'}); - $bios_vendor = ($data->{'bios_vendor'}) ? main::cleaner($data->{'bios_vendor'}) : 'N/A'; + $mobo_serial = main::filter($data->{'board_serial'}); + $bios_vendor = ($data->{'bios_vendor'}) ? main::clean($data->{'bios_vendor'}) : 'N/A'; if ($data->{'bios_version'}){ $bios_version = $data->{'bios_version'}; $bios_version =~ s/^v([0-9])/$1/i; @@ -13593,13 +14694,13 @@ sub machine_output { $bios_romsize = $data->{'bios_romsize'}; } $rows[$j]->{main::key($num++,1,1,'Mobo')} = $mobo_vendor; - $rows[$j]->{main::key($num++,0,2,'model')} = $mobo_model; + $rows[$j]->{main::key($num++,1,2,'model')} = $mobo_model; if ($mobo_version){ - $rows[$j]->{main::key($num++,0,2,'v')} = $mobo_version; + $rows[$j]->{main::key($num++,0,3,'v')} = $mobo_version; } - $rows[$j]->{main::key($num++,0,2,'serial')} = $mobo_serial; + $rows[$j]->{main::key($num++,0,3,'serial')} = $mobo_serial; if ($extra > 2 && $data->{'board_uuid'}){ - $rows[$j]->{main::key($num++,0,2,'uuid')} = $data->{'board_uuid'}; + $rows[$j]->{main::key($num++,0,3,'uuid')} = $data->{'board_uuid'}; } $rows[$j]->{main::key($num++,1,1,$firmware)} = $bios_vendor; $rows[$j]->{main::key($num++,0,2,'v')} = $bios_version; @@ -13621,10 +14722,7 @@ sub machine_soc_output { # this is sketchy, /proc/device-tree/model may be similar to Hardware value from /proc/cpuinfo # raspi: Hardware : BCM2835 model: Raspberry Pi Model B Rev 2 if ($soc_machine->{'device'} || $soc_machine->{'model'}){ - if ($b_arm){$key = 'ARM Device'} - elsif ($b_mips){$key = 'MIPS Device'} - elsif ($b_ppc){$key = 'PowerPC Device'} - $rows[$j]->{main::key($num++,0,1,'Type')} = $key; + $rows[$j]->{main::key($num++,0,1,'Type')} = uc($risc{'id'}); my $system = 'System'; if (defined $soc_machine->{'model'}){ $rows[$j]->{main::key($num++,1,1,'System')} = $soc_machine->{'model'}; @@ -13634,6 +14732,9 @@ sub machine_soc_output { $soc_machine->{'device'} ||= 'N/A'; $rows[$j]->{main::key($num++,$cont_sys,$ind_sys,$system)} = $soc_machine->{'device'}; } + if ($soc_machine->{'mobo'}){ + $rows[$j]->{main::key($num++,1,1,'mobo')} = $soc_machine->{'mobo'}; + } # we're going to print N/A for 0000 values sine the item was there. if ($soc_machine->{'firmware'}){ # most samples I've seen are like: 0000 @@ -13645,7 +14746,7 @@ sub machine_soc_output { if (defined $soc_machine->{'serial'}){ # most samples I've seen are like: 0000 $soc_machine->{'serial'} =~ s/^[0]+$//; - $rows[$j]->{main::key($num++,0,2,'serial')} = main::apply_filter($soc_machine->{'serial'}); + $rows[$j]->{main::key($num++,0,2,'serial')} = main::filter($soc_machine->{'serial'}); } eval $end if $b_log; return @rows; @@ -13683,10 +14784,10 @@ sub machine_data_sys { $path = "$sys_dir$_"; if (-r $path){ $data{$_} = main::reader($path,'',0); - $data{$_} = ($data{$_}) ? main::dmi_cleaner($data{$_}) : ''; + $data{$_} = ($data{$_}) ? main::clean_dmi($data{$_}) : ''; } elsif (!$b_root && -e $path && !-r $path){ - $data{$_} = main::row_defaults('root-required'); + $data{$_} = main::message('root-required'); } else { $data{$_} = ''; @@ -13701,10 +14802,10 @@ sub machine_data_sys { $data{'device'} = get_device_sys($data{'chassis_type'}); } } -# print "sys:\n"; -# foreach (keys %data){ -# print "$_: $data{$_}\n"; -# } + # print "sys:\n"; + # foreach (keys %data){ + # print "$_: $data{$_}\n"; + # } print Data::Dumper::Dumper \%data if $dbg[28]; main::log_data('dump','%data',\%data) if $b_log; eval $end if $b_log; @@ -13716,31 +14817,34 @@ sub machine_data_sys { # certain actions for arm only. sub machine_data_soc { eval $end if $b_log; - my (%data,@temp); + my (%data); if (my $file = $system_files{'proc-cpuinfo'}){ - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/cpu/arm/arm-shevaplug-1.2ghz.txt"; - my @data = main::reader($file); - foreach (@data){ - if (/^(Hardware|machine)\s*:/i){ - @temp = split(/\s*:\s*/, $_, 2); - $temp[1] = main::arm_cleaner($temp[1]); - $temp[1] = main::dmi_cleaner($temp[1]); - $data{'device'} = main::cleaner($temp[1]); - } - elsif (/^(system type|model)\s*:/i){ - @temp = split(/\s*:\s*/, $_, 2); - $temp[1] = main::dmi_cleaner($temp[1]); - $data{'model'} = main::cleaner($temp[1]); - } - elsif (/^Revision/i){ - @temp = split(/\s*:\s*/, $_, 2); - $data{'firmware'} = $temp[1]; - } - elsif (/^Serial/i){ - @temp = split(/\s*:\s*/, $_, 2); - $data{'serial'} = $temp[1]; - } + CpuItem::cpuinfo_data_grabber($file) if !$loaded{'cpuinfo'}; + # grabber sets keys to lower case to avoid error here + if ($cpuinfo_machine{'hardware'} || $cpuinfo_machine{'machine'}){ + $data{'device'} = main::get_defined($cpuinfo_machine{'hardware'}, + $cpuinfo_machine{'machine'}); + $data{'device'} = main::clean_arm($data{'device'}); + $data{'device'} = main::clean_dmi($data{'device'}); + $data{'device'} = main::clean($data{'device'}); + } + if (defined $cpuinfo_machine{'system type'} || $cpuinfo_machine{'model'}){ + $data{'model'} = main::get_defined($cpuinfo_machine{'system type'}, + $cpuinfo_machine{'model'}); + $data{'model'} = main::clean_dmi($data{'model'}); + $data{'model'} = main::clean($data{'model'}); + } + # seen with PowerMac PPC + if (defined $cpuinfo_machine{'motherboard'}){ + $data{'mobo'} = $cpuinfo_machine{'motherboard'}; + } + if (defined $cpuinfo_machine{'revision'}){ + $data{'firmware'} = $cpuinfo_machine{'revision'}; } + if (defined $cpuinfo_machine{'serial'}){ + $data{'serial'} = $cpuinfo_machine{'serial'}; + } + undef %cpuinfo_machine; # we're done with it, don't need it anymore } if (!$data{'model'} && $b_android){ main::set_build_prop() if !$loaded{'build-prop'}; @@ -13763,11 +14867,11 @@ sub machine_data_soc { my $model = main::reader('/proc/device-tree/model','',0); main::log_data('data',"device-tree-model: $model") if $b_log; if ($model){ - $model = main::dmi_cleaner($model); + $model = main::clean_dmi($model); $model = (split(/\x01|\x02|\x03|\x00/, $model))[0] if $model; - my $device_temp = main::regex_cleaner($data{'device'}); + my $device_temp = main::clean_regex($data{'device'}); if (!$data{'device'} || ($model && $model !~ /\Q$device_temp\E/i)){ - $model = main::arm_cleaner($model); + $model = main::clean_arm($model); $data{'model'} = $model; } } @@ -13820,15 +14924,15 @@ sub machine_data_dmi { if ($item !~ /^~/){ # skip the indented rows my @value = split(/:\s+/, $item); if ($value[0] eq 'Release Date'){ - $data{'bios_date'} = main::dmi_cleaner($value[1]) } + $data{'bios_date'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Vendor'){ - $data{'bios_vendor'} = main::dmi_cleaner($value[1]) } + $data{'bios_vendor'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Version'){ - $data{'bios_version'} = main::dmi_cleaner($value[1]) } + $data{'bios_version'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'ROM Size'){ - $data{'bios_romsize'} = main::dmi_cleaner($value[1]) } + $data{'bios_romsize'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'BIOS Revision'){ - $data{'bios_rev'} = main::dmi_cleaner($value[1]) } + $data{'bios_rev'} = main::clean_dmi($value[1]) } } else { if ($item eq '~UEFI is supported'){ @@ -13844,15 +14948,15 @@ sub machine_data_dmi { if ($item !~ /^~/){ # skip the indented rows my @value = split(/:\s+/, $item); if ($value[0] eq 'Product Name'){ - $data{'product_name'} = main::dmi_cleaner($value[1]) } + $data{'product_name'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Version'){ - $data{'product_version'} = main::dmi_cleaner($value[1]) } + $data{'product_version'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Serial Number'){ - $data{'product_serial'} = main::dmi_cleaner($value[1]) } + $data{'product_serial'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Manufacturer'){ - $data{'sys_vendor'} = main::dmi_cleaner($value[1]) } + $data{'sys_vendor'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'UUID'){ - $data{'sys_uuid'} = main::dmi_cleaner($value[1]) } + $data{'sys_uuid'} = main::clean_dmi($value[1]) } } } next; @@ -13864,13 +14968,13 @@ sub machine_data_dmi { if ($item !~ /^~/){ # skip the indented rows my @value = split(/:\s+/, $item); if ($value[0] eq 'Product Name'){ - $data{'board_name'} = main::dmi_cleaner($value[1]) } + $data{'board_name'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Serial Number'){ - $data{'board_serial'} = main::dmi_cleaner($value[1]) } + $data{'board_serial'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Manufacturer'){ - $data{'board_vendor'} = main::dmi_cleaner($value[1]) } + $data{'board_vendor'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Version'){ - $data{'board_version'} = main::dmi_cleaner($value[1]) } + $data{'board_version'} = main::clean_dmi($value[1]) } } } next; @@ -13882,13 +14986,13 @@ sub machine_data_dmi { if ($item !~ /^~/){ # skip the indented rows my @value = split(/:\s+/, $item); if ($value[0] eq 'Serial Number'){ - $data{'chassis_serial'} = main::dmi_cleaner($value[1]) } + $data{'chassis_serial'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Type'){ - $data{'chassis_type'} = main::dmi_cleaner($value[1]) } + $data{'chassis_type'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Manufacturer'){ - $data{'chassis_vendor'} = main::dmi_cleaner($value[1]) } + $data{'chassis_vendor'} = main::clean_dmi($value[1]) } elsif ($value[0] eq 'Version'){ - $data{'chassis_version'} = main::dmi_cleaner($value[1]) } + $data{'chassis_version'} = main::clean_dmi($value[1]) } } } if ($data{'chassis_type'} && $data{'chassis_type'} ne 'Other'){ @@ -13935,37 +15039,37 @@ sub machine_data_sysctl { my @item = split(':', $_); next if !$item[1]; if ($item[0] eq 'hw.vendor' || $item[0] eq 'machdep.dmi.board-vendor'){ - $data{'board_vendor'} = main::dmi_cleaner($item[1]); + $data{'board_vendor'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'hw.product' || $item[0] eq 'machdep.dmi.board-product'){ - $data{'board_name'} = main::dmi_cleaner($item[1]); + $data{'board_name'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'hw.version' || $item[0] eq 'machdep.dmi.board-version'){ - $data{'board_version'} = main::dmi_cleaner($item[1]); + $data{'board_version'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'hw.serialno' || $item[0] eq 'machdep.dmi.board-serial'){ - $data{'board_serial'} = main::dmi_cleaner($item[1]); + $data{'board_serial'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'hw.serial'){ - $data{'board_serial'} = main::dmi_cleaner($item[1]); + $data{'board_serial'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'hw.uuid'){ - $data{'board_uuid'} = main::dmi_cleaner($item[1]); + $data{'board_uuid'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'machdep.dmi.system-vendor'){ - $data{'sys_vendor'} = main::dmi_cleaner($item[1]); + $data{'sys_vendor'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'machdep.dmi.system-product'){ - $data{'product_name'} = main::dmi_cleaner($item[1]); + $data{'product_name'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'machdep.dmi.system-version'){ - $data{'product_version'} = main::dmi_cleaner($item[1]); + $data{'product_version'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'machdep.dmi.system-serial'){ - $data{'product_serial'} = main::dmi_cleaner($item[1]); + $data{'product_serial'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'machdep.dmi.system-uuid'){ - $data{'sys_uuid'} = main::dmi_cleaner($item[1]); + $data{'sys_uuid'} = main::clean_dmi($item[1]); } # bios0:at mainbus0: AT/286+ BIOS, date 06/30/06, BIOS32 rev. 0 @ 0xf2030, SMBIOS rev. 2.4 @ 0xf0000 (47 entries) # bios0:vendor Phoenix Technologies, LTD version "3.00" date 06/30/2006 @@ -13982,13 +15086,13 @@ sub machine_data_sysctl { } } elsif ($item[0] eq 'machdep.dmi.bios-vendor'){ - $data{'bios_vendor'} = main::dmi_cleaner($item[1]); + $data{'bios_vendor'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'machdep.dmi.bios-version'){ - $data{'bios_version'} = main::dmi_cleaner($item[1]); + $data{'bios_version'} = main::clean_dmi($item[1]); } elsif ($item[0] eq 'machdep.dmi.bios-date'){ - $data{'bios_date'} = main::dmi_cleaner($item[1]); + $data{'bios_date'} = main::clean_dmi($item[1]); } } if ($data{'board_vendor'} || $data{'sys_vendor'} || $data{'board_name'} || $data{'product_name'}){ @@ -14157,7 +15261,7 @@ sub get { eval $start if $b_log; my (@rows); my $num = 0; - if (($b_arm || $b_mips) && !$use{'soc-network'} && !$use{'pci-tool'}){ + if (%risc && !$use{'soc-network'} && !$use{'pci-tool'}){ # do nothing, but keep the test conditions to force # the non arm case to always run } @@ -14167,11 +15271,10 @@ sub get { push(@rows,usb_output()); # note: raspberry pi uses usb networking only if (!@rows){ - if ($b_arm || $b_mips){ - my $type = ($b_arm) ? 'arm' : 'mips'; + if (%risc){ my $key = 'Message'; push(@rows, { - main::key($num++,0,1,$key) => main::row_defaults($type . '-pci',''), + main::key($num++,0,1,$key) => main::message('risc-pci',$risc{'id'}), },); } else { @@ -14181,7 +15284,7 @@ sub get { $type = 'pci-card-data-root'; } push(@rows,{ - main::key($num++,0,1,$key) => main::row_defaults($type,''), + main::key($num++,0,1,$key) => main::message($type,''), },); } } @@ -14225,7 +15328,7 @@ sub device_output { # first check if it's a known wifi id'ed card, if so, no print of duplex/speed $b_wifi = check_wifi($row->[4]); my $device = $row->[4]; - $device = ($device) ? main::pci_cleaner($device,'output') : 'N/A'; + $device = ($device) ? main::clean_pci($device,'output') : 'N/A'; #$device ||= 'N/A'; $driver ||= 'N/A'; push(@rows, { @@ -14280,14 +15383,14 @@ sub device_output { } # @rows = (); # we want to handle ARM errors in main get - if (!@rows && !$b_arm && !$b_mips){ + if (!@rows && !%risc){ my $key = 'Message'; my $type = 'pci-card-data'; if ($pci_tool && $alerts{$pci_tool}->{'action'} eq 'permissions'){ $type = 'pci-card-data-root'; } push(@rows, { - main::key($num++,0,1,$key) => main::row_defaults($type,''), + main::key($num++,0,1,$key) => main::message($type,''), },); } eval $end if $b_log; @@ -14301,7 +15404,7 @@ sub usb_output { foreach my $row (@{$usb{'network'}}){ $num = 1; ($driver,$path,$path_id,$product,$type) = ('','','','',''); - $product = main::cleaner($row->[13]) if $row->[13]; + $product = main::clean($row->[13]) if $row->[13]; $driver = $row->[15] if $row->[15]; $path = $row->[3] if $row->[3]; $path_id = $row->[2] if $row->[2]; @@ -14324,7 +15427,7 @@ sub usb_output { $rows[$j]->{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]"; } if ($extra > 2 && $row->[16]){ - $rows[$j]->{main::key($num++,0,2,'serial')} = main::apply_filter($row->[16]); + $rows[$j]->{main::key($num++,0,2,'serial')} = main::filter($row->[16]); } if ($show{'network-advanced'}){ my @data; @@ -14378,7 +15481,7 @@ sub advanced_data_sys { # for usb, we already know where we are if (!$b_usb){ # pi mmcnr has pcitool and also these vendor/device paths. - if ((!$b_arm && !$b_ppc) || $use{'pci-tool'}){ + if (!%risc || $use{'pci-tool'}){ $path = "$_/device/vendor"; $data1 = main::reader($path,'',0) if -r $path; $data1 =~ s/^0x// if $data1; @@ -14391,7 +15494,7 @@ sub advanced_data_sys { # there are cases where arm devices have a small pci bus # or, with mmcnr devices, will show device/vendor info in data1/2 # which won't match with the path IDs - if (($b_arm || $b_ppc || $b_mips || $b_sparc) && $chip && Cwd::abs_path($_) =~ /\b$chip\b/){ + if (%risc && $chip && Cwd::abs_path($_) =~ /\b$chip\b/){ $data1 = $vendor; $data2 = $chip; } @@ -14399,7 +15502,7 @@ sub advanced_data_sys { # print "d1:$data1 v:$vendor d2:$data2 c:$chip bus_id: $bus_id\n"; # print Cwd::abs_path($_), "\n" if $bus_id; if ($b_usb || $b_check || ($data1 && $data2 && $data1 eq $vendor && $data2 eq $chip && - (($b_arm || $b_mips || $b_ppc || $b_sparc) || check_bus_id($_,$bus_id)))){ + (%risc || check_bus_id($_,$bus_id)))){ $if = $_; $if =~ s/^\/.+\///; # print "top: if: $if ifs: @ifs_found\n"; @@ -14409,7 +15512,7 @@ sub advanced_data_sys { $duplex ||= 'N/A'; $path = "$_/address"; $mac = main::reader($path,'',0) if -r $path; - $mac = main::apply_filter($mac); + $mac = main::filter($mac); $path = "$_/speed"; $speed = main::reader($path,'',0) if -r $path; $speed ||= 'N/A'; @@ -14484,7 +15587,7 @@ sub advanced_data_bsd { # ($state,$speed,$duplex,$mac) $duplex = $data[2]; $duplex ||= 'N/A'; - $mac = main::apply_filter($data[3]); + $mac = main::filter($data[3]); $speed = $data[1]; $speed ||= 'N/A'; $state = $data[0]; @@ -14551,14 +15654,14 @@ sub if_ip { $num = 1; if ($limit > 0 && $j >= $limit){ push(@rows, { - main::key($num++,0,$cont_ip,'Message') => main::row_defaults('output-limit',scalar @data), + main::key($num++,0,$cont_ip,'Message') => main::message('output-limit',scalar @data), },); last OUTER; } # print "$data2->[0] $data2->[1]\n"; my ($ipv,$ip,$broadcast,$scope,$scope_id); $ipv = ($data2->[0])? $data2->[0]: 'N/A'; - $ip = main::apply_filter($data2->[1]); + $ip = main::filter($data2->[1]); $scope = ($data2->[3])? $data2->[3]: 'N/A'; # note: where is this ever set to 'all'? Old test condition? if ($if ne 'all'){ @@ -14596,7 +15699,7 @@ sub if_ip { },); } if ($extra > 1 && $data2->[2]){ - $broadcast = main::apply_filter($data2->[2]); + $broadcast = main::filter($data2->[2]); $rows[$j]->{main::key($num++,0,$ind_ip,'broadcast')} = $broadcast; } } @@ -14659,13 +15762,13 @@ sub wan_ip { if (!$ip){ # true case trips if (!$b_dig){ - $ip = main::row_defaults('IP-no-dig', 'WAN IP'); + $ip = main::message('IP-no-dig', 'WAN IP'); } elsif ($b_dig && !$b_html){ - $ip = main::row_defaults('IP-dig', 'WAN IP'); + $ip = main::message('IP-dig', 'WAN IP'); } else { - $ip = main::row_defaults('IP', 'WAN IP'); + $ip = main::message('IP', 'WAN IP'); } } @data = ({ @@ -14706,7 +15809,7 @@ sub get { my $num = 0; if ($bsd_type){ $key1 = 'Optical Report'; - $val1 = main::row_defaults('optical-data-bsd'); + $val1 = main::message('optical-data-bsd'); @rows = ({main::key($num++,0,1,$key1) => $val1,}); if ($dboot{'optical'}){ %data = drive_data_bsd(); @@ -14715,13 +15818,13 @@ sub get { else{ my $file = $system_files{'dmesg-boot'}; if ($file && ! -r $file){ - $val1 = main::row_defaults('dmesg-boot-permissions'); + $val1 = main::message('dmesg-boot-permissions'); } elsif (!$file){ - $val1 = main::row_defaults('dmesg-boot-missing'); + $val1 = main::message('dmesg-boot-missing'); } else { - $val1 = main::row_defaults('optical-data-bsd'); + $val1 = main::message('optical-data-bsd'); } $key1 = 'Optical Report'; @rows = ({main::key($num++,0,1,$key1) => $val1,}); @@ -14733,7 +15836,7 @@ sub get { } if (!@rows){ $key1 = 'Message'; - $val1 = main::row_defaults('optical-data'); + $val1 = main::message('optical-data'); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } eval $end if $b_log; @@ -14772,7 +15875,7 @@ sub drive_output { $rows[$j]->{ main::key($num++,0,2,'rev')} = $rev; } if ($extra > 1 && $drives->{$key}{'serial'}){ - $rows[$j]->{ main::key($num++,0,2,'serial')} = main::apply_filter($drives->{$key}{'serial'}); + $rows[$j]->{ main::key($num++,0,2,'serial')} = main::filter($drives->{$key}{'serial'}); } my $links = (@{$drives->{$key}{'links'}}) ? join(',', sort @{$drives->{$key}{'links'}}) : 'N/A' ; $rows[$j]->{ main::key($num++,0,2,'dev-links')} = $links; @@ -14964,16 +16067,16 @@ sub drive_data_linux { if (-d $device){ if (-r "$device/vendor"){ $drives{$key}->{'vendor'} = main::reader("$device/vendor",'',0); - $drives{$key}->{'vendor'} = main::cleaner($drives{$key}->{'vendor'}); + $drives{$key}->{'vendor'} = main::clean($drives{$key}->{'vendor'}); $drives{$key}->{'state'} = main::reader("$device/state",'',0); $drives{$key}->{'model'} = main::reader("$device/model",'',0); - $drives{$key}->{'model'} = main::cleaner($drives{$key}->{'model'}); + $drives{$key}->{'model'} = main::clean($drives{$key}->{'model'}); $drives{$key}->{'rev'} = main::reader("$device/rev",'',0); } } elsif (-r "/proc/ide/$key/model"){ $drives{$key}->{'vendor'} = main::reader("/proc/ide/$key/model",'',0); - $drives{$key}->{'vendor'} = main::cleaner($drives{$key}->{'vendor'}); + $drives{$key}->{'vendor'} = main::clean($drives{$key}->{'vendor'}); } if ($show{'optical'} && @info){ my $index = 0; @@ -15037,8 +16140,8 @@ sub get { if (!@partitions){ $key1 = 'Message'; #$val1 = ($bsd_type && $bsd_type eq 'darwin') ? - # main::row_defaults('darwin-feature') : main::row_defaults('partition-data'); - $val1 = main::row_defaults('partition-data'); + # main::message('darwin-feature') : main::message('partition-data'); + $val1 = main::message('partition-data'); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } else { @@ -15072,7 +16175,7 @@ sub create_output { } else { $percent = ''; - $used = $size = (!$b_root) ? main::row_defaults('root-required') : main::row_defaults('partition-hidden'); + $used = $size = (!$b_root) ? main::message('root-required') : main::message('partition-hidden'); } $fs = ($row->{'fs'}) ? lc($row->{'fs'}): 'N/A'; $dev_type = ($row->{'dev-type'}) ? $row->{'dev-type'} : 'dev'; @@ -15120,14 +16223,14 @@ sub create_output { $fs !~ /^$fs_skip$/){ if ($show{'label'}){ if ($use{'filter-label'}){ - $row->{'label'} = main::apply_partition_filter('part', $row->{'label'}, ''); + $row->{'label'} = main::filter_partition('part', $row->{'label'}, ''); } $row->{'label'} ||= 'N/A'; $rows[$j]->{main::key($num++,0,2,'label')} = $row->{'label'}; } if ($show{'uuid'}){ if ($use{'filter-uuid'}){ - $row->{'uuid'} = main::apply_partition_filter('part', $row->{'uuid'}, ''); + $row->{'uuid'} = main::filter_partition('part', $row->{'uuid'}, ''); } $row->{'uuid'} ||= 'N/A'; $rows[$j]->{main::key($num++,0,2,'uuid')} = $row->{'uuid'}; @@ -15351,7 +16454,7 @@ sub set_partitions { # an error has occurred almost for sure elsif (!$dev_base){ $dev_type = 'source'; - $dev_base = main::row_defaults('unknown-dev'); + $dev_base = main::message('unknown-dev'); } else { $dev_type = 'dev'; @@ -15775,7 +16878,7 @@ sub get { else { my $key = 'Message'; push(@rows, ({ - main::key($num++,0,1,$key) => main::row_defaults('ps-data-null',''), + main::key($num++,0,1,$key) => main::message('ps-data-null',''), },)); } eval $end if $b_log; @@ -15949,7 +17052,7 @@ sub get { !@hardware_raid){ if ($show{'raid-forced'}){ $key1 = 'Message'; - $val1 = main::row_defaults('raid-data'); + $val1 = main::message('raid-data'); } } else { @@ -16004,7 +17107,7 @@ sub hw_output { $rows[$j]->{main::key($num++,0,2,'bus-ID')} = $bus_id; } if ($extra > 1){ - my $chip_id = main::get_chip_id($row->[5],$row->[6]); + my $chip_id = main::get_chip_id($row->{'vendor-id'},$row->{'chip-id'}); $rows[$j]->{main::key($num++,0,2,'chip-ID')} = $chip_id; } if ($extra > 2){ @@ -16129,7 +17232,7 @@ sub md_output { $size = main::get_size($row->{'size'},'string'); } else { - $size = (!$b_root && !@lsblk) ? main::row_defaults('root-required'): 'N/A'; + $size = (!$b_root && !@lsblk) ? main::message('root-required'): 'N/A'; } $rows[$j]->{main::key($num++,0,2,'size')} = $size; $report = ($row->{'report'}) ? $row->{'report'}: ''; @@ -16221,7 +17324,7 @@ sub soft_output { my ($j,$num) = (0,0); if (@soft_raid && $alerts{'bioctl'}->{'action'} eq 'permissions'){ push(@rows,{ - main::key($num++,1,1,'Message') => main::row_defaults('root-item-incomplete','softraid'), + main::key($num++,1,1,'Message') => main::message('root-item-incomplete','softraid'), }); } # print Data::Dumper::Dumper \@soft_raid; @@ -16539,7 +17642,6 @@ sub btrfs_data { } print Data::Dumper::Dumper \@working if $dbg[37]; - print Data::Dumper::Dumper \@btraid if $dbg[37]; main::log_data('dump','@lvraid',\@btraid) if $b_log; eval $end if $b_log; @@ -16579,7 +17681,7 @@ sub lvm_data { } if ($item->{'segtype'}){ if ($item->{'segtype'} eq 'raid1'){$item->{'segtype'} = 'mirror';} - else {$item->{'segtype'} =~ s/^raid([0-9]+)/raid-$1/; } + else {$item->{'segtype'} =~ s/^raid([0-9]+)/raid-$1/;} } push(@lvraid, { 'components' => \@components, @@ -16902,6 +18004,7 @@ sub zfs_data { # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/raid/zpool-list-2-mirror-main-solestar.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/raid/zpool-list-v-tank-1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/raid/zpool-list-v-gojev-1.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/raid/zpool-list-v-w-spares-1.txt"; #@working = main::reader($file);$zpool = ''; } else { @@ -16981,20 +18084,22 @@ sub zfs_data { $zfs[$j]->{'arrays'}[$k]{'raw-size'} = $size; } # https://blogs.oracle.com/eschrock/entry/zfs_hot_spares - elsif ($row[1] =~ /spares/){ + elsif ($row[1] =~ /spares?/){ next; } - # the first is a member of a raid array - # ada2 - - - - - - - # this second is a single device not in an array + # A member of a raid array: + # ada2 - - - - - - + # A single device not in an array: # ada0s2 25.9G 14.6G 11.3G - 0% 56% # gptid/3838f796-5c46-11e6-a931-d05099ac4dc2 - - - - - - - # third is using /dev/disk/by-id - # ata-VBOX_HARDDISK_VB5b6350cd-06618d58 - - - - - - - - ONLINE + # Using /dev/disk/by-id: + # ata-VBOX_HARDDISK_VB5b6350cd-06618d58 - - - - - - - - ONLINE + # Spare in use: + # /home/fred/zvol/hdd-2-3 - - - - - - - - INUSE elsif ($row[1] =~ /^(sd[a-z]+|[a-z0-9]+[0-9]+|([\S]+)\/.*|(ata|mmc|nvme|pci|scsi|wwn)-\S+)$/ && ($row[2] eq '-' || $row[2] =~ /^[0-9\.]+[MGTPE]$/)){ #print "r1:$row[1]",' :: ', Cwd::abs_path('/dev/disk/by-id/'.$row[1]), "\n"; - $row[1] =~ /^(sd[a-z]+|[a-z0-9]+[0-9]+|([\S]+)\/.*|(ata|mmc|nvme|pci|scsi|wwn)-\S+)\s.*?(DEGRADED|FAULTED|OFFLINE)?$/; + $row[1] =~ /^(sd[a-z]+|[a-z0-9]+[0-9]+|([\S]+)\/.*|(ata|mmc|nvme|pci|scsi|wwn)-\S+)\s.*?(DEGRADED|FAULTED|INUSE|OFFLINE)?$/; #my $working = ''; my $working = ($1) ? $1 : ''; # note: the negative case can never happen my $state = ($4) ? $4 : ''; @@ -17069,14 +18174,23 @@ sub zfs_data { sub zfs_fs_sizes { my ($path,$id) = @_; eval $start if $b_log; + my @data; my @result = main::grabber("$path list -pH $id 2>/dev/null",'','strip'); main::log_data('dump','zfs list @result',\@result) if $b_log; print Data::Dumper::Dumper \@result if $dbg[37]; - my @working = split(/\s+/,$result[0]); + # some zfs devices do not have zfs data, lake spare storage devices + if (@result){ + my @working = split(/\s+/,$result[0]); + $data[0] = $working[1]/1024 if $working[1]; + $data[1] = $working[2]/1024 if $working[2]; + } + elsif ($b_log || $dbg[37]) { + @result = main::grabber("$path list -pH $id 2>&1",'','strip'); + main::log_data('dump','zfs list w/error @result',\@result) if $b_log; + print '@result w/error: ', Data::Dumper::Dumper \@result if $dbg[37]; + } eval $end if $b_log; - $working[1] = $working[1]/1024 if $working[1]; - $working[2] = $working[2]/1024 if $working[2]; - return ($working[1],$working[2]); + return @data; } sub zfs_status { eval $start if $b_log; @@ -17162,7 +18276,7 @@ sub get { } else { $key1 = 'message'; - $val1 = main::row_defaults('ram-data-dmidecode'); + $val1 = main::message('ram-data-dmidecode'); @data = ({ main::key($num++,1,1,'RAM Report') => '', main::key($num++,0,2,$key1) => $val1, @@ -17176,7 +18290,7 @@ sub get { } else { $key1 = 'message'; - $val1 = main::row_defaults('ram-data'); + $val1 = main::message('ram-data'); @data = ({ main::key($num++,1,1,'RAM Report') => '', main::key($num++,0,2,$key1) => $val1, @@ -17206,7 +18320,7 @@ sub ram_output { my ($arrays,$modules,$slots,$type_holder) = (0,0,0,''); if ($source eq 'dboot'){ push(@rows, { - main::key($num++,0,1,'Message') => main::row_defaults('ram-data-complete'), + main::key($num++,0,1,'Message') => main::message('ram-data-complete'), }); } foreach my $item (@$ram){ @@ -17307,7 +18421,7 @@ sub ram_output { $rows[$j]->{main::key($num++,0,3,'part-no')} = $mod->{'part-number'}; } if ($source ne 'dboot' && $extra > 2){ - $mod->{'serial'} = main::apply_filter($mod->{'serial'}); + $mod->{'serial'} = main::filter($mod->{'serial'}); $rows[$j]->{main::key($num++,0,3,'serial')} = $mod->{'serial'}; } } @@ -17333,7 +18447,7 @@ sub dmidecode_data { my ($b_5,$handle,@ram,@temp); my ($derived_module_size,$max_cap_5,$max_cap_16,$max_module_size) = (0,0,0,0); my ($i,$j,$k) = (0,0,0); - my $check = main::row_defaults('note-check'); + my $check = main::message('note-check'); # print Data::Dumper::Dumper \@dmi; foreach my $entry (@dmi){ ## NOTE: do NOT reset these values, that causes failures @@ -17386,7 +18500,7 @@ sub dmidecode_data { $type = lc($temp[1]); } elsif ($temp[0] eq 'Current Speed'){ - $speed = main::dmi_cleaner($temp[1]); + $speed = main::clean_dmi($temp[1]); } elsif ($temp[0] eq 'Locator' || $temp[0] eq 'Socket Designation'){ $temp[1] =~ s/D?RAM slot #?/Slot/i; # can be with or without # @@ -17511,16 +18625,14 @@ sub dmidecode_data { ($configured_speed,$configured_note) = process_speed($temp[1],$device_type,$check); } elsif ($temp[0] eq 'Manufacturer'){ - $temp[1] = main::dmi_cleaner($temp[1]); + $temp[1] = main::clean_dmi($temp[1]); $manufacturer = $temp[1]; } elsif ($temp[0] eq 'Part Number'){ - $temp[1] =~ s/(^[0]+$||.*Module.*|Undefined.*|PartNum.*|\[Empty\]|^To be filled.*)//g; - $part_number = $temp[1]; + $part_number = main::clean_unset($temp[1],'^[0]+$|.*Module.*|PartNum.*'); } elsif ($temp[0] eq 'Serial Number'){ - $temp[1] =~ s/(^[0]+$|Undefined.*|SerNum.*|\[Empty\]|^To be filled.*)//g; - $serial = $temp[1]; + $serial = main::clean_unset($temp[1],'^[0]+$|SerNum.*'); } } # because of the wide range of bank/slot type data, we will just use @@ -17600,7 +18712,7 @@ sub dmidecode_data { sub dboot_data { eval $start if $b_log; my (@ram); - my $est = main::row_defaults('note-est'); + my $est = main::message('note-est'); my ($arr,$derived_module_size,$subtract) = (0,0,0); my ($holder); foreach (@{$dboot{'ram'}}){ @@ -17686,8 +18798,8 @@ sub process_data { my ($ram) = @_; my $b_debug = 0; my (@return); - my $check = main::row_defaults('note-check'); - my $est = main::row_defaults('note-est'); + my $check = main::message('note-check'); + my $est = main::message('note-est'); foreach my $item (@$ram){ # because we use the actual array handle as the index, # there will be many undefined keys @@ -17859,7 +18971,7 @@ sub process_data { sub process_speed { my ($speed,$device_type,$check) = @_; my $speed_note; - $speed = main::dmi_cleaner($speed) if $speed; + $speed = main::clean_dmi($speed) if $speed; if ($device_type && $device_type =~ /ddr/i && $speed && $speed =~ /^([0-9]+)\s*MHz/){ $speed = ($1 * 2) . " MT/s ($speed)"; } @@ -18091,10 +19203,10 @@ sub get { if (!@rows_r){ my $pm_missing; if ($bsd_type){ - $pm_missing = main::row_defaults('repo-data-bsd',$uname[0]); + $pm_missing = main::message('repo-data-bsd',$uname[0]); } else { - $pm_missing = main::row_defaults('repo-data'); + $pm_missing = main::message('repo-data'); } @data = ({main::key($num++,0,1,'Alert') => $pm_missing}); } @@ -18222,7 +19334,7 @@ sub get_repos_linux { } if (@apt_urls){ $key = repo_data('active','apt'); - url_cleaner(\@apt_urls); + clean_url(\@apt_urls); } else { $key = repo_data('missing','apt'); @@ -18316,14 +19428,14 @@ sub get_repos_linux { $key = repo_data('missing','slackpkg+'); } else { - url_cleaner(\@content); + clean_url(\@content); $key = repo_data('active','slackpkg+'); } @data = ( {main::key($num++,1,1,$key) => $slackpkg_plus}, [@content], ); - url_cleaner(\@data); + clean_url(\@data); push(@rows,@data); @content = (); } @@ -18399,7 +19511,7 @@ sub get_repos_linux { $key = repo_data('missing',$repo); } else { - url_cleaner(\@content); + clean_url(\@content); $key = repo_data('active',$repo); } push(@rows, @@ -18462,7 +19574,7 @@ sub get_repos_linux { $key = repo_data('missing','portage'); } else { - url_cleaner(\@content); + clean_url(\@content); $key = repo_data('active','portage'); } push(@rows, @@ -18497,7 +19609,7 @@ sub get_repos_linux { $key = repo_data('missing','cards'); } else { - url_cleaner(\@content); + clean_url(\@content); $key = repo_data('active','cards'); } push(@rows, @@ -18548,7 +19660,7 @@ sub get_repos_linux { if (/(.+)\s([\S]+:\/\/.+)/){ # pack the repo url push(@content, $1); - url_cleaner(\@content); + clean_url(\@content); # get the repo $repo = $2; push(@rows, @@ -18594,7 +19706,7 @@ sub get_repos_linux { $repo = ($2 =~ /^activ/i) ? $repo : ''; } if ($repo && @content){ - url_cleaner(\@content); + clean_url(\@content); $key = repo_data('active',$which); push(@rows, {main::key($num++,1,1,$key) => $repo}, @@ -18606,7 +19718,7 @@ sub get_repos_linux { } # last one if present if ($repo && @content){ - url_cleaner(\@content); + clean_url(\@content); $key = repo_data('active',$which); push(@rows, {main::key($num++,1,1,$key) => $repo}, @@ -18621,7 +19733,7 @@ sub get_repos_linux { $key = repo_data('missing','nix'); } else { - url_cleaner(\@content); + clean_url(\@content); $key = repo_data('active','nix'); } my $user = ($ENV{'USER'}) ? $ENV{'USER'}: 'N/A'; @@ -18673,13 +19785,13 @@ sub get_repos_bsd { # first dump all lines that start with # @content = main::reader($_,'strip'); # then do some clean up on the lines - @content = map { $_ =~ s/{|}|,|\*//g; $_; } @content if @content; + @content = map { $_ =~ s/{|}|,|\*//g; $_;} @content if @content; # get all rows not starting with a # and starting with a non space character my $url = ''; foreach my $line (@content){ if ($line !~ /^\s*$/){ my @data2 = split(/\s*:\s*/, $line); - @data2 = map { $_ =~ s/^\s+|\s+$//g; $_; } @data2; + @data2 = map { $_ =~ s/^\s+|\s+$//g; $_;} @data2; if ($data2[0] eq 'url'){ $url = "$data2[1]:$data2[2]"; $url =~ s/"|,//g; @@ -18697,7 +19809,7 @@ sub get_repos_bsd { $key = repo_data('missing','bsd-package'); } else { - url_cleaner(\@data3); + clean_url(\@data3); $key = repo_data('active','bsd-package'); } push(@rows, @@ -18741,7 +19853,7 @@ sub get_repos_bsd { # $key = repo_data('missing','mports'); # } # else { -# url_cleaner(\@data3); +# clean_url(\@data3); # $key = repo_data('active','mports'); # } # push(@rows, @@ -18844,7 +19956,7 @@ sub repo_builder { if (-r $file){ @content = main::reader($file); @content = grep {/$search/i && !/^\s*$/} @content if @content; - data_cleaner(\@content) if @content; + clean_data(\@content) if @content; } if ($split && @content){ @content = map { @@ -18857,7 +19969,7 @@ sub repo_builder { } else { $key = repo_data('active',$type); - url_cleaner(\@content); + clean_url(\@content); } @data = ( {main::key($num++,1,1,$key) => $file}, @@ -18866,13 +19978,20 @@ sub repo_builder { eval $end if $b_log; return @data; } -sub data_cleaner { - # basics: trim white space, get rid of double spaces - @{$_[0]} = map {$_ =~ s/^\s+|\s+$//g; $_ =~ s/\s\s+/ /g; $_} @{$_[0]}; +sub clean_data { + # basics: trim white space, get rid of double spaces; trim comments at + # ends of repo values + @{$_[0]} = map { + $_ =~ s/\s\s+/ /g; + $_ =~ s/^\s+|\s+$//g; + $_ =~ s/^(.*\/.*) #.*/$1/; + $_;} @{$_[0]}; } # clean if irc -sub url_cleaner { +sub clean_url { @{$_[0]} = map {$_ =~ s/:\//: \//; $_} @{$_[0]} if $b_irc; + # trim comments at ends of repo values + @{$_[0]} = map {$_ =~ s/^(.*\/.*) #.*/$1/; $_} @{$_[0]}; } sub file_path { my ($filename,$dir) = @_; @@ -18903,8 +20022,8 @@ sub get { @data = sensors_output('ipmi',\%sensors); if (!@data){ $key1 = 'Message'; - $val1 = main::row_defaults('sensors-data-ipmi'); - # $val1 = main::row_defaults('dev'); + $val1 = main::message('sensors-data-ipmi'); + # $val1 = main::message('dev'); @data = ({main::key($num++,0,1,$key1) => $val1,}); } push(@rows,@data); @@ -18912,7 +20031,7 @@ sub get { } else { $key1 = 'Permissions'; - $val1 = main::row_defaults('sensors-ipmi-root'); + $val1 = main::message('sensors-ipmi-root'); @data = ({main::key($num++,0,1,$key1) => $val1,}); push(@rows,@data); } @@ -18922,7 +20041,7 @@ sub get { @data = sensors_output('sysctl-sensors',\%sensors); if (!@data){ $key1 = 'Message'; - $val1 = main::row_defaults('sensors-data-bsd',$uname[0]); + $val1 = main::message('sensors-data-bsd',$uname[0]); @data = ({main::key($num++,0,1,$key1) => $val1,}); } push(@rows,@data); @@ -18932,7 +20051,7 @@ sub get { # print "here 1\n"; if ($bsd_type && $bsd_type =~ /^(free|open)bsd/){ $key1 = 'Message'; - $val1 = main::row_defaults('sensors-data-bsd-ok'); + $val1 = main::message('sensors-data-bsd-ok'); } else { $key1 = $alerts{'sensors'}->{'action'}; @@ -18948,7 +20067,7 @@ sub get { # print "here 2\n"; if (!@data){ $key1 = 'Message'; - $val1 = main::row_defaults('sensors-data-linux'); + $val1 = main::message('sensors-data-linux'); @data = ({main::key($num++,0,1,$key1) => $val1,}); } push(@rows,@data); @@ -18960,14 +20079,14 @@ sub get { sub sensors_output { eval $start if $b_log; my ($source,$sensors) = @_; - # note: might revisit this, since gpu sensors data might be present - return if ! %$sensors; my (@gpu,@rows,@fan_default,@fan_main); my ($data_source) = (''); my $fan_number = 0; my $num = 0; my $j = 0; @gpu = gpu_data() if ($source eq 'sensors' || $source eq 'lm-sensors'); + # gpu sensors data might be present even if standard sensors data wasn't + return if !%$sensors && !@gpu; my $temp_unit = (defined $sensors->{'temp-unit'}) ? " $sensors->{'temp-unit'}": ''; my $cpu_temp = (defined $sensors->{'cpu-temp'}) ? $sensors->{'cpu-temp'} . $temp_unit: 'N/A'; my $mobo_temp = (defined $sensors->{'mobo-temp'}) ? $sensors->{'mobo-temp'} . $temp_unit: 'N/A'; @@ -18986,6 +20105,10 @@ sub sensors_output { if ($sensors->{'cpu4-temp'}){ $rows[$j]->{main::key($num++,0,2,'cpu-4')} = $sensors->{'cpu4-temp'} . $temp_unit; } + if (defined $sensors->{'pch-temp'}){ + my $pch_temp = $sensors->{'pch-temp'} . $temp_unit; + $rows[$j]->{main::key($num++,0,2,'pch')} = $pch_temp; + } $rows[$j]->{main::key($num++,0,2,'mobo')} = $mobo_temp; if (defined $sensors->{'sodimm-temp'}){ my $sodimm_temp = $sensors->{'sodimm-temp'} . $temp_unit; @@ -19010,8 +20133,8 @@ sub sensors_output { } } $j = scalar @rows; - @fan_main = @{$sensors->{'fan-main'}} if @{$sensors->{'fan-main'}}; - @fan_default = @{$sensors->{'fan-default'}} if @{$sensors->{'fan-default'}}; + @fan_main = @{$sensors->{'fan-main'}} if $sensors->{'fan-main'}; + @fan_default = @{$sensors->{'fan-default'}} if $sensors->{'fan-default'}; my $fan_def = ($data_source) ? $data_source : ''; if (!@fan_main && !@fan_default){ $fan_def = ($fan_def) ? "$data_source N/A" : 'N/A'; @@ -19129,8 +20252,8 @@ sub ipmi_data { # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmi-sensors-zwerg.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmi-sensors-arm-server-1.txt"; # @data = main::reader($file); - #($b_ipmitool,$i_key,$i_value,$i_unit) = (0,1,3,4); # ipmi-sensors - #($b_ipmitool,$i_key,$i_value,$i_unit) = (1,0,1,2); # ipmitool sensors + # ($b_ipmitool,$i_key,$i_value,$i_unit) = (0,1,3,4); # ipmi-sensors + # ($b_ipmitool,$i_key,$i_value,$i_unit) = (1,0,1,2); # ipmitool sensors } else { if ($program =~ /ipmi-sensors$/){ @@ -19327,7 +20450,7 @@ sub lm_sensors_data { # NOTE: I've seen an inexplicable case where: CPU:52.0°C fails to match with [\s°] but # does match with: [\s°]*. I can't account for this, but that's why the * is there # Tdie is a new k10temp-pci syntax for cpu die temp - elsif ($_ =~ /^(T?CPU.*|Tdie.*):([0-9\.]+)[\s°]*(C|F)/i){ + elsif ($_ =~ /^(Chip 0.*?|T?CPU.*|Tdie.*):([0-9\.]+)[\s°]*(C|F)/i){ $temp_working = $2; $working_unit = $3; if (!$sensors{'cpu-temp'} || @@ -19346,7 +20469,7 @@ sub lm_sensors_data { $working_unit = $3; $sensors{'temp-unit'} = set_temp_unit($sensors{'temp-unit'},$working_unit) if $working_unit; } - elsif ($_ =~ /^T?(dimm|mem|sodimm).*:([0-9\.]+)[\s°]*(C|F)/i){ + elsif ($_ =~ /^T?(dimm|mem|sodimm).*?:([0-9\.]+)[\s°]*(C|F)/i){ $sensors{'sodimm-temp'} = $1; $working_unit = $2; $sensors{'temp-unit'} = set_temp_unit($sensors{'temp-unit'},$working_unit) if $working_unit; @@ -19456,6 +20579,27 @@ sub lm_sensors_data { } } } + foreach $adapter (keys %{$sensors_raw{'pch'}}){ + next if !$adapter || ref $sensors_raw{'pch'}->{$adapter} ne 'ARRAY'; + if ((@sensors_use && !(grep {/$adapter/} @sensors_use)) || + (@sensors_exclude && (grep {/$adapter/} @sensors_exclude))){ + next; + } + $temp_working = ''; + foreach (@{$sensors_raw{'pch'}->{$adapter}}){ + if ($_ =~ /^[^:]+:([0-9\.]+)[\s°]*(C|F)/i){ + $temp_working = $1; + $working_unit = $2; + if (!$sensors{'pch-temp'} || + (defined $temp_working && $temp_working > 0 && $temp_working > $sensors{'pch-temp'})){ + $sensors{'pch-temp'} = $temp_working; + } + if (!$sensors{'temp-unit'} && $working_unit){ + $sensors{'temp-unit'} = set_temp_unit($sensors{'temp-unit'},$working_unit); + } + } + } + } print Data::Dumper::Dumper \%sensors if $dbg[31]; %sensors = process_data(%sensors) if %sensors; main::log_data('dump','lm-sensors: %sensors',\%sensors) if $b_log; @@ -19478,7 +20622,9 @@ sub process_lm_sensors { # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-maximus-arch-1.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/kernel-58-sensors-ant-1.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-zenpower-nvme-2.txt"; - #@sensors_data = main::reader($file); + # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-pch-intel-1.txt"; + # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/sensors/sensors-ppc-sr71.txt"; + # @sensors_data = main::reader($file); } else { # only way to get sensor array data? Unless using sensors -j, but can't assume json @@ -19499,15 +20645,20 @@ sub process_lm_sensors { if ($adapter =~ /^(drive|nvme)/){ $type = 'disk'; } - elsif ($adapter =~ /^(amdgpu|intel|nouveau|radeon)-/){ - $type = 'gpu'; + # intel on die io controller, like southbridge/northbridge used to be + elsif ($adapter =~ /^(pch[_-])/){ + $type = 'pch'; + } + elsif ($adapter =~ /^(.*hwmon)-/){ + $type = 'hwmon'; } # ath/iwl: wifi; enp/eno/eth: lan nic elsif ($adapter =~ /^(ath|iwl|en[op][0-9]|eth)[\S]+-/){ $type = 'network'; } - elsif ($adapter =~ /^(.*hwmon)-/){ - $type = 'hwmon'; + # put last just in case some other sensor type above had intel in name + elsif ($adapter =~ /^(amdgpu|intel|nouveau|radeon)-/){ + $type = 'gpu'; } else { $type = 'main'; @@ -19624,7 +20775,7 @@ sub set_temp_unit { sub process_data { eval $start if $b_log; my (%sensors) = @_; - my ($cpu_temp,$cpu2_temp,$cpu3_temp,$cpu4_temp,$mobo_temp,$psu_temp); + my ($cpu_temp,$cpu2_temp,$cpu3_temp,$cpu4_temp,$mobo_temp,$pch_temp,$psu_temp); my ($fan_type,$i,$j,$index_count_fan_default,$index_count_fan_main) = (0,0,0,0,0); my $temp_diff = 20; # for C, handled for F after that is determined my (@fan_main,@fan_default); @@ -19823,12 +20974,13 @@ sub process_data { $cpu3_temp = $sensors{'cpu3-temp'} if $sensors{'cpu3-temp'}; $cpu4_temp = $sensors{'cpu4-temp'} if $sensors{'cpu4-temp'}; $ambient_temp = $sensors{'ambient-temp'} if $sensors{'ambient-temp'}; + $pch_temp = $sensors{'pch-temp'} if $sensors{'pch-temp'}; $psu_fan = $sensors{'fan-psu'} if $sensors{'fan-psu'}; $psu1_fan = $sensors{'fan-psu-1'} if $sensors{'fan-psu-1'}; $psu2_fan = $sensors{'fan-psu-2'} if $sensors{'fan-psu-2'}; # so far only for ipmi, sensors data is junk for volts - if ($extra > 0 && - ($sensors{'volts-12'} || $sensors{'volts-5'} || $sensors{'volts-3.3'} || $sensors{'volts-vbat'})){ + if ($extra > 0 && ($sensors{'volts-12'} || $sensors{'volts-5'} || + $sensors{'volts-3.3'} || $sensors{'volts-vbat'})){ $v_12 = $sensors{'volts-12'} if $sensors{'volts-12'}; $v_5 = $sensors{'volts-5'} if $sensors{'volts-5'}; $v_3_3 = $sensors{'volts-3.3'} if $sensors{'volts-3.3'}; @@ -19845,6 +20997,7 @@ sub process_data { 'cpu3-temp' => $cpu3_temp, 'cpu4-temp' => $cpu4_temp, 'mobo-temp' => $mobo_temp, + 'pch-temp' => $pch_temp, 'psu-temp' => $psu_temp, 'temp-unit' => $sensors{'temp-unit'}, 'fan-main' => \@fan_main, @@ -19979,7 +21132,7 @@ sub gpu_data { # print "temp: $_\n"; } # speeds can be in percents or rpms, so need the 'fan' in regex - elsif (/^.*fan.*:([0-9\.]+).*(RPM)?/i){ + elsif (/^.*?fan.*?:([0-9\.]+).*(RPM)?/i){ $gpudata[$j]->{'fan-speed'} = $1; # NOTE: we test for nvidia %, everything else stays with nothing $gpudata[$j]->{'speed-unit'} = ''; @@ -20010,12 +21163,12 @@ sub get { my (@rows,$key1,$val1); my $num = 0; if ($fake{'dmidecode'} || ($alerts{'dmidecode'}->{'action'} eq 'use' && - (!$b_arm || $use{'slot-tool'}))){ + (!%risc || $use{'slot-tool'}))){ @rows = slot_output(); } - elsif ($b_arm && !$use{'slot-tool'}){ - $key1 = 'ARM'; - $val1 = main::row_defaults('arm-pci',''); + elsif (%risc && !$use{'slot-tool'}){ + $key1 = 'Message'; + $val1 = main::message('risc-pci',$risc{'id'}); @rows = ({main::key($num++,0,1,$key1) => $val1,}); } elsif ($alerts{'dmidecode'}->{'action'} ne 'use'){ @@ -20080,7 +21233,7 @@ sub slot_output { if (!@rows){ my $key = 'Message'; push(@rows, { - main::key($num++,0,1,$key) => main::row_defaults('pci-slot-data',''), + main::key($num++,0,1,$key) => main::message('pci-slot-data',''), },); } eval $end if $b_log; @@ -20099,7 +21252,7 @@ sub get { @rows = create_output(); if (!@rows){ push(@rows, - {main::key($num++,0,1,'Alert') => main::row_defaults('swap-data')}, + {main::key($num++,0,1,'Alert') => main::message('swap-data')}, ); } eval $end if $b_log; @@ -20133,7 +21286,7 @@ sub create_output { } } else { - $rows[$j]->{main::key($num++,0,1,'Message')} = main::row_defaults('swap-admin'); + $rows[$j]->{main::key($num++,0,1,'Message')} = main::message('swap-admin'); } } $j = scalar @rows; @@ -20172,14 +21325,14 @@ sub create_output { } if ($show{'label'} && ($row->{'label'} || $row->{'swap-type'} eq 'partition')){ if ($use{'filter-label'}){ - $row->{'label'} = main::apply_partition_filter('part', $row->{'label'}, ''); + $row->{'label'} = main::filter_partition('part', $row->{'label'}, ''); } $row->{'label'} ||= 'N/A'; $rows[$j]->{main::key($num++,0,2,'label')} = $row->{'label'}; } if ($show{'uuid'} && ($row->{'uuid'} || $row->{'swap-type'} eq 'partition')){ if ($use{'filter-uuid'}){ - $row->{'uuid'} = main::apply_partition_filter('part', $row->{'uuid'}, ''); + $row->{'uuid'} = main::filter_partition('part', $row->{'uuid'}, ''); } $row->{'uuid'} ||= 'N/A'; $rows[$j]->{main::key($num++,0,2,'uuid')} = $row->{'uuid'}; @@ -20206,7 +21359,7 @@ sub get { @data = bsd_data(); if (!@data){ $key1 = 'Message'; - $val1 = main::row_defaults('unmounted-data'); + $val1 = main::message('unmounted-data'); } else { @rows = create_output(\@data); @@ -20219,7 +21372,7 @@ sub get { } else { $key1 = 'Message'; - $val1 = main::row_defaults('unmounted-data-bsd',$uname[0]); + $val1 = main::message('unmounted-data-bsd',$uname[0]); } } } @@ -20228,7 +21381,7 @@ sub get { @data = proc_data(); if (!@data){ $key1 = 'Message'; - $val1 = main::row_defaults('unmounted-data'); + $val1 = main::message('unmounted-data'); } else { @rows = create_output(\@data); @@ -20236,7 +21389,7 @@ sub get { } else { $key1 = 'Message'; - $val1 = main::row_defaults('unmounted-file'); + $val1 = main::message('unmounted-file'); } } if (!@rows && $key1){ @@ -20263,10 +21416,10 @@ sub create_output { $fs = 'N/A'; } elsif (main::check_program('file')){ - $fs = ($b_root) ? 'N/A' : main::row_defaults('root-required'); + $fs = ($b_root) ? 'N/A' : main::message('root-required'); } else { - $fs = main::row_defaults('tool-missing-basic','file'); + $fs = main::message('tool-missing-basic','file'); } } $j = scalar @rows; @@ -20287,14 +21440,14 @@ sub create_output { if (($show{'label'} || $show{'uuid'}) && $fs !~ /^$fs_skip$/){ if ($show{'label'}){ if ($use{'filter-label'}){ - $row->{'label'} = main::apply_partition_filter('part', $row->{'label'}, ''); + $row->{'label'} = main::filter_partition('part', $row->{'label'}, ''); } $row->{'label'} ||= 'N/A'; $rows[$j]->{main::key($num++,0,2,'label')} = $row->{'label'}; } if ($show{'uuid'}){ if ($use{'filter-uuid'}){ - $row->{'uuid'} = main::apply_partition_filter('part', $row->{'uuid'}, ''); + $row->{'uuid'} = main::filter_partition('part', $row->{'uuid'}, ''); } $row->{'uuid'} ||= 'N/A'; $rows[$j]->{main::key($num++,0,2,'uuid')} = $row->{'uuid'}; @@ -20505,7 +21658,7 @@ sub get { if ($alerts{'usbdevs'}->{'action'} eq 'missing' && $alerts{'usbconfig'}->{'action'} eq 'missing'){ $key1 = $alerts{'usbdevs'}->{'action'}; - $val1 = main::row_defaults('tools-missing-bsd','usbdevs/usbconfig'); + $val1 = main::message('tools-missing-bsd','usbdevs/usbconfig'); } elsif ($alerts{'usbconfig'}->{'action'} eq 'permissions'){ $key1 = $alerts{'usbconfig'}->{'action'}; @@ -20524,7 +21677,7 @@ sub get { if (!@rows){ my $key = 'Message'; push(@rows, { - main::key($num++,0,1,$key) => main::row_defaults('usb-data',''), + main::key($num++,0,1,$key) => main::message('usb-data',''), },); } } @@ -20546,8 +21699,8 @@ sub usb_output { ($driver,$path_id,$ports,$product, $serial,$speed,$type) = ('','','','','','',''); $speed = (main::is_numeric($id->[8])) ? sprintf("%1.1f",$id->[8]) : $id->[8] if $id->[8]; - $product = main::cleaner($id->[13]) if $id->[13]; - $serial = main::apply_filter($id->[16]) if $id->[16]; + $product = main::clean($id->[13]) if $id->[13]; + $serial = main::filter($id->[16]) if $id->[16]; $product ||= 'N/A'; $speed ||= 'N/A'; $path_id = $id->[2] if $id->[2]; @@ -20605,7 +21758,7 @@ sub usb_output { } if (!$b_hub && $extra > 2){ if ($serial){ - $rows[$j]->{main::key($num++,0,$ind_sc,'serial')} = main::apply_filter($serial); + $rows[$j]->{main::key($num++,0,$ind_sc,'serial')} = main::filter($serial); } } } @@ -20647,26 +21800,26 @@ sub weather_output { } $location_string = $string; } - $location_string = main::apply_filter($location_string); + $location_string = main::filter($location_string); @location = ($show{'weather-location'},$location_string,''); } else { @location = get_location(); if (!$location[0]){ return @rows = ({ - main::key($num++,0,1,'Message') => main::row_defaults('weather-null','current location'), + main::key($num++,0,1,'Message') => main::message('weather-null','current location'), }); } } %weather = get_weather(\@location); if ($weather{'error'}){ return @rows = ({ - main::key($num++,0,1,'Message') => main::row_defaults('weather-error',$weather{'error'}), + main::key($num++,0,1,'Message') => main::message('weather-error',$weather{'error'}), }); } if (!$weather{'weather'}){ return @rows = ({ - main::key($num++,0,1,'Message') => main::row_defaults('weather-null','weather data'), + main::key($num++,0,1,'Message') => main::message('weather-null','weather data'), }); } $conditions = "$weather{'weather'}"; @@ -21240,7 +22393,7 @@ sub get_location { $country = ($loc{'country3'}) ? $loc{'country3'} : $loc{'country'}; $city = ($loc{'city'}) ? $loc{'city'} : 'City N/A'; $state = ($loc{'region-id'}) ? $loc{'region-id'} : 'Region N/A'; - $loc_string = main::apply_filter("$city, $state, $country"); + $loc_string = main::filter("$city, $state, $country"); my @location = ($loc_arg,$loc_string,$loc{'tz'}); # print ($loc_arg,"\n", join("\n", @loc_data), "\n",scalar @loc_data, "\n"); eval $end if $b_log; @@ -21701,7 +22854,7 @@ sub get_kde_trinity_data { $desktop[0] = 'KDE Plasma'; } if (!$desktop[1]){ - $desktop[1] = ($kde_session_version) ? $kde_session_version: main::row_defaults('unknown-desktop-version'); + $desktop[1] = ($kde_session_version) ? $kde_session_version: main::message('unknown-desktop-version'); } # print Data::Dumper::Dumper \@version_data; if ($extra > 1){ @@ -22294,7 +23447,7 @@ sub set { # ! -d '/proc/bus/pci' # this is sketchy, a sbc won't have pci, but a non sbc arm may have it, so # build up both and see what happens - if ($b_arm || $b_mips || $b_ppc || $b_sparc){ + if (%risc){ soc_data(); } } @@ -22351,9 +23504,9 @@ sub lspci_data { $subsystem_id = $1; $subsystem = (split(/^Subsystem:\s*/, $_))[1]; $subsystem =~ s/(\s?\[[^\]]+\])+$//g; - $subsystem = main::cleaner($subsystem); - $subsystem = main::pci_cleaner($subsystem,'pci'); - $subsystem = main::pci_cleaner_subsystem($subsystem); + $subsystem = main::clean($subsystem); + $subsystem = main::clean_pci($subsystem,'pci'); + $subsystem = main::clean_pci_subsystem($subsystem); # print "ss:$subsystem\n"; } elsif ($_ =~ /^I\/O\sports/){ @@ -22384,7 +23537,7 @@ sub lspci_data { $type_id = $3; $_ =~ s/^\Q$1\E//; $type = lc($type); - $type = main::pci_cleaner($type,'pci'); + $type = main::clean_pci($type,'pci'); $type =~ s/\s+$//; } # trim off end prog-if and rev items @@ -22411,7 +23564,7 @@ sub lspci_data { } $device = $_; # cases of corrupted string set to '' - $device = main::cleaner($device); + $device = main::clean($device); # corrupted lspci truncation bug; and ancient lspci, 2.4 kernels if (!$vendor_id){ my @temp = lspci_n_data($busid_full); @@ -22441,6 +23594,7 @@ sub lspci_n_data { my (@data); if ($fake{'lspci'}){ # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/steve-mint-topaz-lspci-n.txt"; + # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/ben81-hwraid-lspci-n.txt"; # @data = main::reader($file,'strip'); } else { @@ -22473,13 +23627,13 @@ sub pciconf_data { foreach (@data){ if ($driver){ if ($_ =~ /^~$/){ - $vendor = main::cleaner($vendor); - $device = main::cleaner($device); + $vendor = main::clean($vendor); + $device = main::clean($device); # handle possible regex in device name, like [ConnectX-3] # and which could make matches fail - my $device_temp = main::regex_cleaner($device); + my $device_temp = main::clean_regex($device); if ($vendor && $device){ - if (main::regex_cleaner($vendor) !~ /\Q$device_temp\E/i){ + if (main::clean_regex($vendor) !~ /\Q$device_temp\E/i){ $device = "$vendor $device"; } } @@ -22557,7 +23711,7 @@ sub pcidump_data { $busid = $1; $busid_nu = $2; ($driver,$driver_nu) = pcidump_driver("$busid:$busid_nu") if $dboot{'pci'}; - $device = main::cleaner($3); + $device = main::clean($3); } elsif ($_ =~ /^0x[\S]{4}:\s+Vendor ID:\s+([0-9a-f]{4}),?\s+Product ID:\s+([0-9a-f]{4})/){ $vendor_id = $1; @@ -22615,7 +23769,7 @@ sub pcictl_data { if ($_ =~ /^([0-9a-f:]+):([0-9]+):\s+([^.]+?)$/i){ $busid = $1; $busid_nu = $2; - $device = main::cleaner($3); + $device = main::clean($3); my $working = (grep {/^${busid}:${busid_nu}:\s/} @data2)[0]; if ($working && $working =~ /^${busid}:${busid_nu}:\s+0x([0-9a-f]{4})([0-9a-f]{4})\s+\(0x([0-9a-f]{2})([0-9a-f]{2})[0-9a-f]+\)/){ @@ -22669,6 +23823,7 @@ sub pci_grabber { # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/rk016013-knnv.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/kot--book-lspci-nnv.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/steve-mint-topaz-lspci-nnkv.txt"; + # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/ben81-hwraid-lspci-nnv.txt"; # @data = main::reader($file,'strip'); } else { @@ -22886,7 +24041,7 @@ sub assign_data { $use{'soc-timer'} = 1 if $tool eq 'soc'; } # not used at this point, -M comes before ANG - # $device_vm = check_vm($data[4]) if ((!$b_ppc && !$b_mips) && !$device_vm); + # $device_vm = check_vm($data[4]) if ((!$risc{'ppc'} && !$risc{'mips'}) && !$device_vm); push(@devices,[@$data]); } # note: for soc, these have been converted in soc_type() @@ -23123,7 +24278,7 @@ sub set_dboot_disks { $disks_bsd{$id}->{'speed'} = $1; $disks_bsd{$id}->{'speed'} =~ s/\.[0-9]+// if $disks_bsd{$id}->{'speed'}; } - $disks_bsd{$id}->{'model'} = main::disk_cleaner($disks_bsd{$id}->{'model'}); + $disks_bsd{$id}->{'model'} = main::clean_disk($disks_bsd{$id}->{'model'}); if (!$disks_bsd{$id}->{'serial'} && $show{'disk'} && $extra > 1 && $alerts{'bioctl'}->{'action'} eq 'use'){ $disks_bsd{$id}->{'serial'} = bioctl_data($id); @@ -23164,7 +24319,7 @@ sub set_disklabel_data { main::log_data('dump','disklabel @data', \@data) if $b_log; if (scalar @data < 4 && (grep {/permission/i} @data)){ $alerts{'disklabel'}->{'action'} = 'permissions'; - $alerts{'disklabel'}->{'message'} = main::row_defaults('root-feature'); + $alerts{'disklabel'}->{'message'} = main::message('root-feature'); last; } else { @@ -23406,7 +24561,7 @@ sub get_bsd_os { @working = main::reader($distro_file); @working = grep {/(ProductName|ProductVersion)/} @working if @working; @working = grep {/<string>/} @working if @working; - @working = map {s/<[\/]?string>//g; } @working if @working; + @working = map {s/<[\/]?string>//g;} @working if @working; $distro = join(' ', @working); } } @@ -24253,7 +25408,7 @@ sub get_init_data { # output: /sbin/init --version: init (upstart 1.1) # init (upstart 0.6.3) # openwrt /sbin/init hangs on --version command, I think - if ((!$b_mips && !$b_sparc && !$b_arm) && + if (!%risc && ($init_version = program_version('init', 'upstart', '3','--version'))){ $init = 'Upstart'; } @@ -24501,9 +25656,8 @@ sub get_kernel_bits { $bits = (grabber("$program LONG_BIT 2>/dev/null"))[0]; } # fallback test - if (!$bits && @uname){ - $bits = $uname[-1]; - $bits = ($bits =~ /64/) ? 64 : 32; + if (!$bits && $bits_sys){ + $bits = $bits_sys; } $bits ||= 'N/A'; eval $end if $b_log; @@ -24530,6 +25684,7 @@ sub parameters_linux { my ($file) = @_; # unrooted android may have file only root readable my $line = main::reader($file,'',0) if -r $file; + $line =~ s/\s\s+/ /g; eval $end if $b_log; return $line; } @@ -24699,7 +25854,7 @@ sub meminfo_data { $available = main::get_piece($_,2); } } - $gpu = gpu_ram_arm() if $b_arm; + $gpu = gpu_ram_arm() if $risc{'arm'}; #$gpu = main::translate_size('128M'); $total += $gpu; if ($available){ @@ -24921,7 +26076,7 @@ sub create_output { $total = 'N/A'; } else { - $total = main::row_defaults('package-data'); + $total = main::message('package-data'); } } if ($counts{'total'} && $extra > 1){ @@ -25027,7 +26182,7 @@ sub package_counts { } else { @list = undef; - $error = main::row_defaults('pm-disabled'); + $error = main::message('pm-disabled'); } $libs = undef; # print Data::Dumper::Dumper \@list; @@ -25125,7 +26280,7 @@ sub get_pci_vendor { my ($vendor,$sep,$temp) = ('','',''); # get rid of any [({ type characters that will make regex fail # and similar matches show as non-match - $subsystem = regex_cleaner($subsystem); + $subsystem = clean_regex($subsystem); my @data = split(/\s+/, $subsystem); # when using strings in patterns for regex have to escape them foreach (@data){ @@ -25172,6 +26327,9 @@ sub set_ps_aux { my $final = $#split; # some stuff has a lot of data, chrome for example $final = ($final > ($ps_cols + 2)) ? $ps_cols + 2 : $final; + # handle case of ps wrapping lines despite ww unlimited width, which + # should NOT be happening, but is. + next if !defined $split[$ps_cols]; if ($split[$ps_cols] !~ /^\[/){ push(@ps_cmd,join(' ', @split[$ps_cols .. $final])); } @@ -25578,7 +26736,7 @@ sub set { } } else { - $client{'version'} = main::row_defaults('unknown-shell'); + $client{'version'} = main::message('unknown-shell'); } print "6: shell not app version: $client{'version'}\n" if $b_debug; } @@ -25836,8 +26994,8 @@ sub set_sysctl_data { } # Must go AFTER sensor because sometimes freebsd puts sensors in dev.cpu # hw.l1dcachesize hw.l2cachesize - elsif ($use{'bsd-cpu'} && (/^hw\.(busfreq|clock|n?cpu|l[123].?cach|model)/ || - /^dev\.cpu/ || /^machdep\.cpu/)){ + elsif ($use{'bsd-cpu'} && (/^hw\.(busfreq|clock|n?cpu|l[123].?cach|model|smt)/ || + /^dev\.cpu/ || /^machdep\.(cpu|hlt_logical_cpus)/)){ push(@{$sysctl{'cpu'}}, $_); } # only activate if using the diskname feature in dboot!! @@ -26151,17 +27309,17 @@ sub usbconfig_data { $product_id = $1; } elsif (/^iManufacturer\s*=\s*0x([a-f0-9]{4})\s*(<([^>]+)>)?/){ - $vendor = main::cleaner($3); + $vendor = main::clean($3); $vendor =~ s/^0x.*//; # seen case where vendor string was ID $working[11] = $vendor; } elsif (/^iProduct\s*=\s*0x([a-f0-9]{4})\s*(<([^>]+)>)?/){ - $product = main::cleaner($3); + $product = main::clean($3); $product =~ s/^0x.*//; # in case they put product ID in, sigh $working[12] = $product; } elsif (/^iSerialNumber\s*=\s*0x([a-f0-9]{4})\s*(<([^>]+)>)?/){ - $working[16] = main::cleaner($3); + $working[16] = main::clean($3); } } main::log_data('dump','$usb{main}: usbconfig',$usb{'main'}) if $b_log; @@ -26266,7 +27424,7 @@ sub usbdevs_data { elsif (/^addr\s*([0-9a-f]+):\s+([a-f0-9]{4}:[a-f0-9]{4})\s*([^,]+)?(,\s[^,]+?)?,\s+([^,]+)$/){ $addr_id = $1; $chip_id = $2; - $vendor = main::cleaner($3) if $3; + $vendor = main::clean($3) if $3; $vendor ||= ''; $name = main::remove_duplicates("$vendor $5"); $type = check_type($name,'',''); @@ -26415,7 +27573,11 @@ sub sys_data { # this will be a hex number $class_id = sys_item("$_/bDeviceClass"); # $subclass_id = sys_item("$_/bDeviceSubClass"); + # $protocol_id = sys_item("$_/bDeviceProtocol"); $class_id = hex($class_id) if $class_id; + # $subclass_id = hex($subclass_id) if $subclass_id; + # $protocol_id = hex($protocol_id) if $protocol_id; + # print "$path_id $class_id/$subclass_id/$protocol_id\n"; $power = sys_item("$_/bMaxPower"); process_power(\$power) if $power; # this populates class, subclass, and protocol id with decimal numbers @@ -26474,9 +27636,9 @@ sub sys_data { # we don't want the device, it's probably a bad path in /sys/bus/usb/devices next if !$vendor_id && !$chip_id; $product = sys_item("$_/product"); - $product = main::cleaner($product) if $product; + $product = main::clean($product) if $product; $vendor = sys_item("$_/manufacturer"); - $vendor = main::cleaner($vendor) if $vendor; + $vendor = main::clean($vendor) if $vendor; if (!$b_hub && ($product || $vendor)){ if ($vendor && $product && $product !~ /$vendor/){ $name = "$vendor $product"; @@ -26545,8 +27707,14 @@ sub uevent_data { # print join("\n",@working), "\n"; if (@working){ $driver = main::awk(\@working,'^DRIVER',2,'='); - $interface = main::awk(\@working,'^INTERFACE',2,'='); + $interface = main::awk(\@working,'^INTERFACE',2,'='); if ($interface){ + # for hubs, we need the specific protocol, which is in TYPE + if ($interface eq '9/0/0' && + (my $temp = main::awk(\@working,'^TYPE',2,'='))){ + $interface = $temp; + } + # print "$interface\n"; $interface = device_type($interface); if ($interface){ if ($interface ne '<vendor specific>'){ @@ -26661,10 +27829,15 @@ sub device_type { elsif ($types[0] eq '6'){$type = 'Still Imaging';} elsif ($types[0] eq '7'){$type = 'Printer';} elsif ($types[0] eq '8'){$type = 'Mass Storage';} + # note: there is a bug in linux kernel that always makes hubs 9/0/0 elsif ($types[0] eq '9'){ - if ($types[2] eq '0'){$type = 'Full speed (or root) Hub';} + if ($types[2] eq '0'){$type = 'Full speed or root hub';} elsif ($types[2] eq '1'){$type = 'Hi-speed hub with single TT';} elsif ($types[2] eq '2'){$type = 'Hi-speed hub with multiple TTs';} + # seen protocol 3, usb3 type hub, but not documented on usb.org + elsif ($types[2] eq '3'){$type = 'Super-speed hub';} + # this is a guess, never seen it + elsif ($types[2] eq '4'){$type = 'Super-speed+ hub';} } elsif ($types[0] eq '10'){$type = 'CDC-Data';} elsif ($types[0] eq '11'){$type = 'Smart Card';} @@ -26779,6 +27952,12 @@ sub prep_speed { elsif ($_[0] =~ /^([0-9\.]+)+\s*Gb/){ $speed = $1 * 1000; } + elsif ($_[0] =~ /usb\s?40/i){ + $speed = 40000;# 4 40gbps + } + elsif ($_[0] =~ /usb\s?20/i){ + $speed = 20000;# 4 20gbps + } # could be 3.2, 20000 too, also superspeed+ elsif ($_[0] =~ /super[\s-]?speed\s?(\+|plus)/i){ $speed = 10000;# 3.1; # can't trust bsds to use superspeed+ but we'll hope @@ -26814,7 +27993,7 @@ sub bus_id_alpha { # note: seen instance in android where reading file hangs endlessly!!! sub get_wakeups { eval $start if $b_log; - return if $b_arm || $b_mips || $b_ppc; + return if %risc; my ($wakeups); my $path = '/sys/power/wakeup_count'; $wakeups = reader($path,'strip',0) if -r $path; @@ -26875,7 +28054,7 @@ sub generate { assign_data(\%row); } if ($show{'cpu'} || $show{'cpu-basic'}){ - DeviceData::set(\$checks{'device'}) if $b_arm && !$checks{'device'}; + DeviceData::set(\$checks{'device'}) if %risc && !$checks{'device'}; DmidecodeData::set(\$checks{'dmi'}) if $use{'dmidecode'} && !$checks{'dmi'}; my $arg = ($show{'cpu-basic'}) ? 'basic' : 'full' ; %row = item_handler('CPU','cpu',$arg); @@ -26975,14 +28154,13 @@ sub short_output { ($speed,$speed_key) = ('',''); if ($cpu[6]){ $speed_key = "$cpu[3]/$cpu[5]"; - $cpu[4] =~ s/ MHz//; - $speed = "$cpu[4]/$cpu[6]"; + $speed = "$cpu[4]/$cpu[6] MHz"; } else { $speed_key = $cpu[3]; - $speed = $cpu[4]; + $speed = "$cpu[4] MHz"; } - $cpu[1] ||= main::row_defaults('cpu-model-null'); + $cpu[1] ||= main::message('cpu-model-null'); $cpu_string = $cpu[0] . ' ' . $cpu[1] . $type; } elsif ($bsd_type){ @@ -26997,6 +28175,7 @@ sub short_output { } } } + $speed ||= 'N/A'; # totally unexpected situation, what happened? my @disk = DriveItem::get('short'); # print Dumper \@disk; my $disk_string = 'N/A'; @@ -27020,7 +28199,7 @@ sub short_output { $disk_string = "$size$percent"; } else { - $size ||= main::row_defaults('disk-size-0'); + $size ||= main::message('disk-size-0'); $disk_string = "$used/$size"; } } @@ -27231,13 +28410,13 @@ sub system_item { } } if ($b_admin && (my $params = KernelParameters::get())){ - $index = scalar(@{$data{$data_name}}); + # $index = scalar(@{$data{$data_name}}); # not on own line for now # print "$params\n"; if ($use{'filter-label'}){ - $params = main::apply_partition_filter('system', $params, 'label'); + $params = main::filter_partition('system', $params, 'label'); } if ($use{'filter-uuid'}){ - $params = main::apply_partition_filter('system', $params, 'uuid'); + $params = main::filter_partition('system', $params, 'uuid'); } $data{$data_name}->[$index]{main::key($num++,0,2,'parameters')} = $params; $index = scalar(@{$data{$data_name}}); |
