From 4c3ab65d467facc4d7de335219bc84c70188fd8b Mon Sep 17 00:00:00 2001 From: Harald Hope Date: Tue, 14 Dec 2021 10:35:42 -0800 Subject: [PATCH] Huge refactor of CPU physical/core/cache logic. That was some very old logic with a lot of hacks and patches, but it had never been actually rewritten to take advantage of Perl's far more powerful and robust data structures and logic. This caused a continuous stream of error cases in subtle ways, or not so subtle, and fixes were just changing how the errors manifested. Tnanks very much to linuxquestions.org Slackware forum people for massive help, and also to linux.org forum members for ongoing help and data and debugging. Note Changes 5, change of default widths in display to 80 columns, and out (aka, console, or ssh into remote system), 100. You can still use other widths if you like something wider using the configuration options shown. Also upped max columns wrapping line starters to own rows to 110 columns from 90, again the idea being to make output more readable to other users when posted in public. I've been thinking of this change for a long time, but was hoping -y would register with users, but it hasn't gained enough traction, so the result is way too many super hard to read issue reports, forum posts, linux kernel issues, etc, it's honestly gotten sort of embarrassing because they make it look like inxi has bad output. Sidescrolling code blocks in forums in particular are absurdly hard to read and scan rapidly for data. Going along with the width and indentation changes, for most main row types, if they wrap to a second row, they are further indented 2 column2, to make it easier to see what they belong to. The two levels of indentation contain more useful visual cues as to what belongs to what. There was a temptation to release this as either 3.4.00 or 4.0.00 but in the end, I decided to follow the numbering rules, and to just roll it to 3.3.10 since there aren't really any primary new features even though CPU was basically rewritten in large part, and big parts of inxi were also changed, upgraded, and enhanced. But no truly new features, just some display control items like -Y, --indent, --indents. I hope this refactor meets its primary goals, and that the new defaults for display help resolve public posting issues which have grown increasingly annoying for anyone trying to read those pasted in too long outputs. -------------------------------------------------------------------------------- KNOWN ISSUES: 1. Android seems to have CPU cache data, but does not show any 'size' item. But it does have the other data for each cache type internally, which is odd. 2. In some instances, the parent key:value pairs with '' as value, those are parents of children key:value pairs, are left hanging at end of line, with the children on the following line. This can look awkward, but in other cases, actually looks very good, it depends if it's at the start or end of the line. I won't say this is not correctable, but it would be very difficult, and outside the scope of this release, but that is something that I may look at for a future release now that the output generator logic was reworked slightly for Change 5b. It's tricky though, because in cases where it's the first item on the line, you want that behavior, but when it's last, you don't. But this may be worth revisiting in the future. 3. In some cases, -Y + -y1 may lead to the start of the block scrolling off the top of the visible screen. This isn't really correctable, so if that's an issue for you, just don't use -y1 with -Y and all the output will wrap nicely. 4. There is an unaccountable ~10-20ms delay reading cpufreq/scaling_cur_freq, per thread/core, which really adds up on high thread count CPUs. There is a workaround in inxi to use cpufreq_cur_freq if it is readable, ie, if you are root or use sudo, but to fallback to scaling_cur_freq if can't read cpuinfo_... This is a drag, and really looks like a kernel bug, or a frequency driver bug. -------------------------------------------------------------------------------- BUGS: 1. 3.3.09 and 3.3.10 CPU bug fixes: * Failed to filter out certain virtual machine CPU core speeds, and showed more speeds than the instance actually has. Noticed this with KVM running on Xeon CPUs. * For many cases, L2 cache, particularly for Intel, was completely wrong, it was showing L3 caches, or L3+L2. Failed to handle cases where L2 cache belongs to more than 1 core, except for using a crude hack for AMD Bulldozer microarch. Older Intel Core 4 core CPUs would sometimes be 1 L2 per die, and the 4 cores were actually 2 core duo cpu dies, with one L2 cache per die. * Shows wrong core count for complex core complexes like those found in Intel Alder Lake, now shows correct count of actual cores, regardless of the MT or ST state of each core. * Showed invalid L3 cache values in some legacy cpus that had no L3 cache, that is due to a bug in the dmidecode data itself. Solution is to never use dmidecode cache data if any other valid L1, L2, or L3 cache data found for Linux, and to only use dmidecode data for bsds if no L1, or L2, or L3 data found. Or if forced with --dmidecode. 2. An unfortunately long standing bug found and fixed, thanks slackware users! cp_cpu_arch was, and has been for a while, failing to convert hex stepping to decimal, or test if the string it gets is even a possible hex value, this resulted in all Intel CPUs with stepping > 9 failing to ID correctly for cpu arch. 3. In a related bug, hex to decimal tool used to create --admin hex/decimal output for family/model/stepping was also not testing if the string was an actual valid hex number. Case in particular, power pc with revision field contained a long string, which was of course not a valid hex number, and that tripped a Perl error when it was asked to convert a non hex string to decimal. 4. Long standing bug found while doing Change 5: inxi actually never applied separate in/out of dispay to widths because using a legacy boolean that was not updated, so it was always using out of display widths. -------------------------------------------------------------------------------- FIXES: 1. Incorrectly calling PowerPC 'revision' 'stepping' for -Ca, that is now stored as $cpu{'revision'} to avoid mixing up the logics there. For PowerPC shows as rev: [string]. 2. Microarch: * AMD family 15, model 2 as bulldozer, actually piledriver. * AMD family 17, model 18, was supposed to be zen/zen+, since I can't tell those apart, seen stepping 1 is zen+, but had incorrect match. * Intel family 6, model 25, stepping 2 as nehalem, should have been westmere. * Changed Penryn to Core Penryn, intel family 6, model 17 * misc other micro arch fine tunings. 3. Code fix 8, switched to global %risc for arm, mips, ppc, riscv, sparc. This corrects many sloppy handlers, and makes all risc processing the same, and calls device tree readers for all risc systems, not just arm or arm and mips. 4. In cases where bogomips were 0 due to false values in risc results, show N/A. 5. Removed all attempts to guess at what /proc/cpuinfo cache size: refers to, it can literally be anything, a per core L1, a per core or cpu L2, or an L3. So applying any math to it is just a random guess at that point. If any L1,2,3 cache data is found, don't use the cache: value at all, but that will only be present if no /sys data was found anyway, and if cpuinfo had no specific cache type fields, only generic cache. 6. Added failsafe tests for stepping and model id before doing conversion to hex. Make sure integer! 7. Added L1 D cache, was only using I cache for BSDs. Output will show total for L1 A + L1 D. No idea why I didn't use L1 D, makes little sense, but that's how it goes. 8. Made bogomips tests more granular, now only rejects low sub 50 bogomips values if %risc cpu type. Legacy ancient cpus like 486 could and did have bogomip counts below 50. https://tldp.org/HOWTO/BogoMips/bogo-list.html 9. See Enhancement 12 as well. If OpenBSD, which has no per core data or physical cpu data, is running on MT capable cpu, but for security OpenBSD has disabled MT, will now force MT to be not shown via the hw.smt value. This removes a small glitch that would have bothered OpenBSD users who know that OpenBSD has disabled MT for security purposes. 10. Changed BSD hack to use L2 cache totals to deduce > 1 physical cpus, that was flat out dumb, since we can just use dmidecode type 4 to iterate physical cpu counts and skip the pointless logic. Thus, if dmidecode, and if > 1 dmidecode type 4 found, and if physical cpu counts equal 1, then replace the found counts with the dmidecode physical cpu counts. 11. Corrected bad assumption that threads would always be 2 per core for MT tests. Still no way to reliably determine threads per core for non x86 cpus like powerpc however, but those are very fringe and should rarely be an issue since that data is only missing on very old linux now I think. 12. Fixed 'parameters:' going to its own line with -Sa, that wasn't supposed to. -S is two lines, the kernel / host stuff, and the desktop/console/distro stuff. 13. Fixed case when key: value first word plus other parts of line longer than max width, failed to wrap as expected. 14. Added start/end ' and " start / end \s to main filters. -------------------------------------------------------------------------------- ENHANCEMENTS: 1. CPU: most Linux will now show L1 and L3 cache with -Cx without needing sudo/root, and it will be more accurate than ever before. 2. CPU: shows per CPU L1/L2/L3 totals, and shows actual full system physical processor count * L1/L2/L3 total in parentheses, like: L2: 1.5 MiB (3 MiB). 3. CPU: A long standing annoyance, previously for main CPU 'Speed:' item, showed the fastest core speed found, now shows avg: [speed] and with -Cx, shows the 'high:' as well if > 1 cores, and if 1 or more cores have a higher speed than the other(s). 4. CPU: Handles advanced cases of new architectures, like Alder Lake with Performance and Efficiency cores, future Zen, and existing ARM CPUs with 2 or more different core sets, with different max/min frequencies. Previously a hack was used to handle only ARM CPUs with this type of architecture. Will show correct CPU core counts, which previous inxi versions would fail to do for Alder Lake type scenarios of 8 single threaded CPUs and 4-8 multithreaded )MT) perforance cores. This should also in theory show different the different min/max speeds if they were detected. Those did not seem to be set correctly in Alder Lake sample data I saw however, P and E cores were set to the same min/max speeds. 5. Added CPU types MST (Multi+Single Thread), AMP (Asymmetric Multi Processing), and AMCP (Asymmetrical Multi Core Processor). This will be applied to any CPU that has this type of complex topology that has been dynamically detected, like Alder Lake or different core count or min/max speed RISC CPUs. 6. CPU: shows with -Ca for cases where different L1/L2/L3 caches found per physical CPU, as with Alder Lake, but also many other variants that were poorly or not at all handled before, how many of each cache type (L1 Data, instruction) were found, otherwise will show how many of each cache were found. 7. CPU: shows with -Ca in Topology: report, for cases like Alder Lake with different core types in one physical CPU (type: MST AMCP), the number that are single threaded (st) and number that are multi-threaded (mt). 8. Basic support for rsyc-v systems, going along with code fix 8, fix 3, now it's easy to add this type of support. 9. Added shortcut options for --filter-label (--zl), --filter-uuid (--zu), and andded new filter option, --filter-vulnerabilities (--zv). The latter is added by request, a decent idea to have option to not show cpu vulnerabilities. 10. Going with fix 7, switched to a sort of pseudo L1 d/i with desc report for any BSD with L1 I/D cache found, or elbrus cache0 (icache) / cache1 (d cache). Elbrus should hopefully be handled by the /sys tool. Guesses on the L1 are ok, since those are almost always per core, so it's fine. Didn't expect to enhance any BSD cpu data this time around, but there you go!! If they have the data, then it will be used. Not going to go overboard though in that, quite useless overall since usually can't see how many CPUs are present, at least not usually. 11. For -Ca, full CPU topology report if any complex topogy is detected, otherwise shows the same basic Info: 2x 6-core or Info: dual core as before, no point in wasting a line for something with no more data than the short string. Complex types include MT CPUs since they will have different thread counts etc, and will have 2 or more threads per core, which will also be listed. 12. If smt status is defined (0/1), shows smt: enabled|disabled in Topology section, can be useful for systems with disabled MT, but supporting it. If no topology data found (OpenBSD for example), for -C shows 'smt: disabled' after 'type:' section, and enabled if -Cxxx (since MT really already tells you that). 13. For -Ca Speed: report, added 'governor:' item, if found. Can show 1 or more active governors. 14. Output height (in lines) control: -Y [-2|-1|0|1-xxx]]. This lets you break up any of the output into whatever number of lines you want. Also useful out of DISPLAY for reading -h options menu items etc. It came tp my attention that the long standing shift+pgup/pgdown (aka 'softscrollback) behavior had stopped working, and in fact has been removed from the current Linux kernel, at least until it is rewritten to be more clean and understandable. Read more about it in these kernel post/commit messages: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=50145474f6ef4a9c19205b173da6264a644c7489 https://lwn.net/ml/linux-kernel/CAHk-=whe4ZdTdCebneWqC4gSQZwsVJ5-Emg0BucOGCwPhOAJpw@mail.gmail.com/ Options for -Y are: * -Y 0 or -Y: Set maximum block height to terminal line height. * -Y [1-xxx]: Set maximum block line height to given integer. * -Y -1: Print out one primary data block item at a time, with -F for example. * -Y -2: Restore default unlimited height if LINES_MAX configuration item used. 15. And finally, more disk vendors/vendor ids. As usual. As expected. -------------------------------------------------------------------------------- CHANGES: 1. If /sys or /proc/cpuinfo speed data available: * For -b CPU item: speed: [speed MHz] min/max: [min]/[max] MHz becomes: speed (MHz): avg: [speed] min/max: [min]/[max] * For -C, Speed item Speed: [speed MHz] min/max: [min]/[max] MHz Cores (MHz): ... becomes: Speed (MHz): avg: [speed] min/max: [min]/[max] cores: ... * For short form, shows speed/min/max but uses average speed if available. For -b and -C, only shows one MHz in Speed line starter, which slightly shortens the line even with the added 'avg:' item since 3 MHz are replaced with 1. 2. Going with change 1, now the 'avg:' item shows not the fastest cpu speed found, which was the case before, but shows an average of all cpu speeds found. Showing the fastest made some sense back in the days of single core, or even dual core CPUs, but makes little sense today with many core/threaded cpus. With -x, it will show the high: [speed] item as well, after 'avg:'. 3. By suggestion, wrapped first Type item in Vulnerabilities to its own line, that's a verbose --admin option after all, no need to save lines! 4. Going along with Fix 5, give up on trying to pretend we can guess at L2 cache, now if only 'cache' data was available from cpuinfo, will just say: cache: [cache size] note: check and call it a day. 5a. Change default width to 80 columns, in and out of display. Too many users are posting horribly wrapping inxi output in forums, issue trackers, etc, and it frankly makes inxi look really bad, creates awful side scrolling code boxes, etc. So now default widths in and out of console are 80 (since often data is generated in SSH or out of X/Wayland) for issues. This essentially makes -y 80/-y the default width. This is what I've been using for a few years now, and after seeing far too many side scrolling or badly wrapping inxi outputs online, I think it's probably time to just force 80 column widths as default and call it a day. You can change these new defaults using configuration options (these are the previous options, though due to a bug, COLS_MAX_CONSOLE was never being used): COLS_MAX_CONSOLE=115 # in display, terminal client max width COLS_MAX_IRC=100 COLS_MAX_NO_DISPLAY=130 # not in display, no X/Wayland running 5b. Changed output wrapped indent to 1 column from 2, and make second and greater rows of a line indent +1 to make it more clear that it is a child row of its parent row. Note that because no arg short form, -S, and -I are special types of rows, this behavior is not used, they just print out as usual. This 1 column indent also applies to -y1, making for a little more data per line but more readable and easy to follow. 6. If > 1 physical cpu detected, no longer uses single/dual/triple/quad core strings, rather uses: 2x 2-core. Also uses lower case -core, not -Core. 7. Only show die counts for CPU (on rare occasions > 1 found) with -xx. Not particularly important bit of data afterall. 8. Make L1, L3 cache data show with -Cx, not -Cxx, now that it's working well. 9. Removed CPU die for -Cxx, that's only going to show with -Ca now. 10. If -Ca, and if certain complexity conditions are met, shows a separate Topology line rather than the Info: 6-core type item. For -b, short, -Cx, -Cxxx shows the Info: topology short form. 11. Bogomips always shows before flags data, whether -f or just -Cx trips flag output. 12. Flags/Features now shows in the same place, under Speeds: always, whether -Cx shortlist, or -Cf full list. Makes more sense that way, and code is much cleaner too. 13. Bogomips, being essentially bogus units of speed for cpu, are moved into Speed: report. -------------------------------------------------------------------------------- DOCUMENTATION: 1. Updated man/help for new CPU extra data options and output changes. 2. Cleaned up and added sample outputs for man CPU items. 3. Now that doas is getting into Linux distros, removed all mentions of doas as a BSD option, and made it a general doas/sudo item. Glad to see doas making it into linux distros, it's a good tool, much easier to configure and use than sudo. Good job OpenBSD guys. Note that inxi already has had full doas support for a while now, but this finalizes it, and makes it fully agnostic. Internally doas is actually preferred over sudo, by the way. 4. Added documention items for INDENT (--indent), INDENT_MIN (--inident-min). 5. Re-ordered help menu and man page, created new Filters and Output Controls sections to make stuff easier to find. In man page, also added on top a list of OPTIONS sections to make finding stuff easier. -------------------------------------------------------------------------------- CODE: 1. Removed legacy /sys cpu functions: cpu_bugs_sys(); get_boost_status(); set_cpu_speeds_sys(). cpu_speeds() is deprecated and now will only be used for legacy Linux and BSDs if they had any per core speeds found; get_caches() was only a placeholder for the full featured cpu_sys data source, and was removed; cpu_speeds() no longer needed, integrated into other logic; cpu_dies_sys() removed, integrated into other logic. This logic is now integrated into cpu_data_sys() data generator. 2. Changed the main CpuItems functions to use array/hash references, not passing full hashes or arrays in most cases now. 3. For machine_data_soc(), switched to CpuItem::cpuinfo_grabber() which then sets the global @cpuinfo and %cpuinfo_machine items, which will be used again in Cpu if cpu data is requested. This gets rid of a full parsing of cpuinfo just to get the machine data section, and also makes it so cpuinfo in cpu does not need to worry about the machine data block, which is not related to the processor blocks anyway, that was always a hack done by the kernel guys to toss that SOC data somewhere as far as I can tell. 4. New tools: * either_or() - takes a list, and returns the first defined element of list. * regex_range() - generate ranges from comma, space, or ranges like 2-29, or any combination of those, like 3,6,12-29 5. Added --force cpuinfo to bypass all /sys based cpu logic, useful for testing to see what would have happened using old logic. 6. Added --dbg switches 39, 40, 41, for the new cpu sys data features, also made more consistent --dbg 8 and --dbg 38 switches. 7. Added sys/cpuinfo pair debugger to support debugging complex sys/cpuinfo issues. 8. Got rid of $b_arm,$b_mips,$b_ppc,$b_sparc, replaced with global %risc, also added $risc{'riscv'} type. this makes general risc type feature testing a lot easier since inxi can either test for %risc defined, or for a specific type of risc cpu. This is much cleaner, and use $risc{'id'} for print purposes, which got rid of a lot of tests. Also made all risc tests consistent, some were ARM only, or arm/mips, but were supposed to be for all risc cpus. 9. Set help menu code to roughly 80 columns width assuming 2 space tab indentation. 10. Changed all xxx_cleaner subs to clean_xxx, all filter subs to filter_xxx, and row_defaults() to message(). 11. Dumped redundant fallback logic in get_kernel_bits, if first getconf method fails, use $sys_bits, and call it good, it was repeating the 32/64 bit tests pointlessly. 12. Cleaned up print_data() to allow for more fine tuned indentation for the new 2 indent levels. 13. Made help menu code more or less wrap to 80 columns, or close. Ongoing to bring to 80 columns where practical, but never at expense of clarity or logic. -------------------------------------------------------------------------------- -- Harald Hope - Tue, 13 Dec 2021 10:25:49 -0800 --- inxi | 5685 +++++++++++++++++++++++++++--------------------- inxi.1 | 838 ++++--- inxi.changelog | 433 ++++ 3 files changed, 4199 insertions(+), 2757 deletions(-) diff --git a/inxi b/inxi index ed77f65..c7d6299 100755 --- a/inxi +++ b/inxi @@ -47,8 +47,8 @@ use POSIX qw(ceil uname strftime ttyname); ## INXI INFO ## my $self_name='inxi'; -my $self_version='3.3.09'; -my $self_date='2021-11-22'; +my $self_version='3.3.10'; +my $self_date='2021-12-13'; my $self_patch='00'; ## END INXI INFO ## my ($b_pledge,@pledges); @@ -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; - } +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}); } - # 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'}; + # 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; } - # 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'}; + 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 = ; - chomp($response); + chomp(my $response = ); if (!main::is_int($response) || $response > ($count + 3)){ @data = ( [0, '', '', "Error - Invalid Selection. You entered this: $response. Hit 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 = ( @@ -2068,7 +2076,7 @@ sub system_data { my $glob = '/sys/devices/system/cpu/'; $glob .= '{cpufreq,cpu*/topology,cpu*/cpufreq,cpu*/cache/index*,smt,'; $glob .= 'vulnerabilities}/*'; - get_glob('sys','cpu-data',$glob); + get_glob('sys','cpu',$glob); @files = main::globber('/dev/bus/usb/*/*'); copy_files(\@files, 'system'); } @@ -2204,13 +2212,13 @@ sub get_glob { $item = main::reader($_,'strip',0); } else { - $item = main::row_defaults('root-required'); + $item = main::message('root-required'); } - $item = main::row_defaults('undefined') if ! defined $item; + $item = main::message('undefined') if ! defined $item; push(@result,$_ . '::' . $item); } # print Data::Dumper::Dumper \@result; - main::writer("$data_dir/$type-glob-$id.txt",\@result); + main::writer("$data_dir/$type-data-$id-glob.txt",\@result); } sub write_data { my ($data_ref, $type) = @_; @@ -2419,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 @@ -3328,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', @@ -3527,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"; @@ -3535,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; @@ -3690,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 @@ -4486,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')){ @@ -4500,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; @@ -4515,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; @@ -4533,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; @@ -4548,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 { @@ -4567,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; @@ -4581,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)$/){ @@ -4609,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; @@ -4628,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; @@ -4798,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; }, + $use{'filter'} = 1;}, + 'filter-label|zl' => sub { + $use{'filter-label'} = 1;}, 'Z|filter-override|no-filter' => sub { - $use{'filter-override'} = 1; }, - 'filter-uuid' => sub { - $use{'filter-uuid'} = 1; }, + $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) = @_; @@ -4835,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){ @@ -4889,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; @@ -4910,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\.]+)?$/){ @@ -4970,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; @@ -4999,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)$/){ @@ -5015,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){ @@ -5045,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){ @@ -5067,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);}, @@ -5090,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", "");} @@ -5275,131 +5335,129 @@ 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: ^^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: ^^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, full CPU $flags; triggers -xxx."], ['2', '8', '', "Everything available, including repos (-r), @@ -5416,318 +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." ], + [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." ], - ['1', '', '--filter-uuid', "Filters out ${partition_string} UUIDs in -j, - -o, -p, -P, -Sa." ], - ['0', '', '', "$line" ], - ['0', '', '', "Extra Data Options:" ], + 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:^^ALL^=^NOPASSWD:^/usr/sbin/hddtemp" ], + (sudo v. 1.7 or newer)(or try doas). + Example:^^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 most Linux, or 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."], + 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', '', '', "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|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', '', '--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. - See -Z for disabling output filters as well."], - ['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 @@ -6151,41 +6255,25 @@ sub set_konvi_data { ######################################################################## #### ------------------------------------------------------------------- -#### FILTERS AND TOOLS +#### CLEANERS, FILTERS, AND TOOLS #### ------------------------------------------------------------------- -sub apply_filter { - my ($string) = @_; - if ($string){ - if ($use{'filter'} && $string ne row_defaults('root-required')){ - $string = $filter_string; - } - } - else { - $string = 'N/A'; - } - 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\.||\bltd\b|inc\.||\binc\b|intl\.|co\.||corp\.||\(tm\)|\(r\)|®|\(rev ..\)|\'|\"|\sinc\s*$|\?//gi; + $item =~ s/,|\*/ /g; + $item =~ s/^\s+|\s+$//g; + $item =~ s/\s\s+/ /g; + return $item; } -# 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 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; } @@ -6201,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\.||\bltd\b|inc\.||\binc\b|intl\.|co\.||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; # ?| $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\]|||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 { - my ($string) = @_; - my $cleaner = '\b(defauult string|empty|none|undefined.*|unknown|unspecified)\b'; - $string =~ s/$cleaner//i; +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) = @_; + # 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 { @@ -6319,88 +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; -} - -# string of range types 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; -} - -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.', @@ -6409,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.', @@ -6436,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.', @@ -6458,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' => '', @@ -6487,7 +6574,9 @@ sub row_defaults { 'unmounted-data' => 'No unmounted partitions found.', 'unmounted-data-bsd' => "Unmounted partition feature unsupported in $id.", 'unmounted-file' => 'No /proc/partitions file found.', + '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', @@ -6497,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 @@ -6636,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 = ); + if (!$response){ + $size{'lines'} = 1; + } + else { + print message('output-control-exit'), "\n"; + exit 0; + } +} + sub print_basic { my ($data) = @_; my $indent = 18; @@ -6646,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"; @@ -6683,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); @@ -6696,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); @@ -6725,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); @@ -6756,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 = ( @@ -6777,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; @@ -6808,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 .= "$_ "; @@ -6848,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"; } @@ -6857,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 = ''; @@ -6915,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); @@ -6950,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'}; } } @@ -6970,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)); } @@ -6992,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()); @@ -7011,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, @@ -7078,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',''); } } } @@ -7097,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'; @@ -7117,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; } @@ -7231,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,}); } } @@ -7245,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,}); } } @@ -7258,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,}); } } @@ -7269,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,}); } } @@ -7314,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 . '%)'; } @@ -7328,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'}%)"; @@ -7341,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'}; @@ -7371,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'; @@ -7401,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){ @@ -7426,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; @@ -7452,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; @@ -7500,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"; @@ -7600,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 @@ -7660,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); @@ -7736,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 { @@ -7753,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'), },); } } @@ -7776,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, @@ -7833,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]; @@ -7857,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; } @@ -7941,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 @@ -8007,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, @@ -8062,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; @@ -8114,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]; @@ -8181,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); } @@ -8199,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'}); @@ -8230,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){ @@ -8249,134 +8439,199 @@ 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'}); + } + elsif (defined $cpu->{'revision'}){ + $rows[$j]->{main::key($num++,0,2,'rev')} = $cpu->{'revision'}; + } + + 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 > 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')} = $properties{'l1-cache'}; - } - # the arm + l2 will never be true since arm cpus don't have l2 cache - $properties{'l2-cache'} = ($properties{'l2-cache'}) ? $properties{'l2-cache'} : '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')} = $properties{'l3-cache'}; - } - if ($properties{'cache-check'}){ - $rows[$j]->{main::key($num++,0,3,'note')} = $properties{'cache-check'}; - } + # 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); } - if ($extra > 0 && !$show{'cpu-flag'}){ + # 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]?|ht|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, @@ -8384,24 +8639,29 @@ sub full_output { } if ($b_admin){ my $value = ''; - if (!defined $cpu{'bugs-hash'}){ - if ($cpu{'bugs-string'}){ - my @proc_bugs = split(/\s+/, $cpu{'bugs-string'}); + 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 (defined $cpu{'bugs-hash'}){ - $j = $#rows; - foreach my $key (sort keys %{$cpu{'bugs-hash'}}){ + 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]; + $rows[$j]->{main::key($num++,0,3,$cpu->{'bugs-hash'}->{$key}[0])} = $cpu->{'bugs-hash'}->{$key}[1]; $j++; } } @@ -8409,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'}); @@ -8468,53 +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,%caches); + my ($file)= @_; + my ($arch,$note,$temp); # has to be set above fake cpu section my %cpu = set_cpu_data(); - my $cpu_sys = cpu_data_sys(); + # 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"; @@ -8522,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"; @@ -8531,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"; @@ -8544,1077 +9102,122 @@ 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); - if (my $path = main::check_program('getconf')){ - get_caches($path,\%caches); - $cpu{'caches'} = 1 if %caches; - } - if (defined $cpu_sys->{'data'}{'vulnerabilities'}){ - $cpu{'bugs-hash'} = $cpu_sys->{'data'}{'vulnerabilities'}; - } - # 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'; + 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; + } + else { + $b_processor = 1; + } + 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) - 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"; - } + $key = ($key eq 'Processor') ? 'model name' : lc($key); + $cpuinfo[$i]->{$key} = $value; } - 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]; - } - elsif (!$cpu{'cores'} && $line[0] eq 'cpu cores'){ - $cpu{'cores'} = $line[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; - } - } - 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]); - } - ## this is only for -C full cpu output - if ($type eq 'full'){ - if (!$cpu{'l2-cache'}){ - if ($caches{'L2'}){ - $cpu{'l2-cache'} = $caches{'L2'}; - } - elsif (($line[0] eq 'cache size' || $line[0] eq 'l2 cache size') && - $line[1] =~ /(\d+\s*[KMG])i?B?$/){ - $cpu{'l2-cache'} = main::translate_size($1); - } - } - if (!$cpu{'l1-cache'}){ - if ($caches{'L1'}){ - $cpu{'l1-cache'} = $caches{'L1'}; - } - elsif ($line[0] eq 'l1 cache size' && $line[1] =~ /(\d+\s*[KMG])i?B?$/){ - $cpu{'l1-cache'} = main::translate_size($1); - } - } - if (!$cpu{'l3-cache'}){ - if ($caches{'L3'}){ - $cpu{'l3-cache'} = $caches{'L3'}; - } - elsif ($line[0] eq 'l3 cache size' && $line[1] =~ /(\d+\s*[KMG])i?B?$/){ - $cpu{'l3-cache'} = main::translate_size($1); - } - } - 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; - } - } - } - 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-string'} && $line[0] eq 'bugs'){ - $cpu{'bugs-string'} = $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])); - } - } - } - } - $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; - } - $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; - } - } - $cpu{'ids'} = (\@ids); - if (!$speeds{'cur-freq'}){ - $cpu{'cur-freq'} = $cpu{'processors'}->[0]; - $speeds{'min-freq'} = 0; - $speeds{'max-freq'} = 0; - } - else { - $cpu{'cur-freq'} = $speeds{'cur-freq'}; - $cpu{'min-freq'} = $speeds{'min-freq'}; - $cpu{'max-freq'} = $speeds{'max-freq'}; - } - 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 get_caches { - eval $start if $b_log; - my @data = main::grabber("$_[0] -a 2>/dev/null",'','strip'); - # print Data::Dumper::Dumper \@data; - foreach (@data){ - next if !/^LEVEL[1-4]_\S+?_SIZE\s/; - my @split = split(/\s+/,$_); - $split[0] =~ s/^LEVEL([1-4])_\S+/L$1/; - # are in byte units, not KiB - $_[1]->{$split[0]} += $split[1] / 1024; # add L1-D and L1-I as L1 total - } - main::log_data('dump','%cpu',$_[1]) if $b_log; - print Data::Dumper::Dumper $_[1] if $dbg[8]; - eval $end if $b_log; -} - -sub sysctl_data { - eval $start if $b_log; - my ($type) = @_; - my %cpu = set_cpu_data(); - my (@ids,@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! - foreach (@{$sysctl{'cpu'}}){ - @line = split(/\s*:\s*/, $_); - next if !$line[0]; - # darwin shows machine, like MacBook7,1, not cpu - # machdep.cpu.brand_string: Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz - if (($bsd_type ne 'darwin' && $line[0] eq 'hw.model') || - $line[0] eq 'machdep.cpu.brand_string'){ - # cut L2 cache/cpu max speed out of model string, if available - # 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]); - if ($line[1] =~ /([0-9]+)[\s-]*([KM]B)\s+L2 cache/i){ - my $multiplier = ($2 eq 'MB') ? 1024: 1; - $cpu{'l2-cache'} = $1 * $multiplier; - } - if ($line[1] =~ /([^0-9\.][0-9\.]+)[\s-]*[MG]Hz/){ - $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'); - } - 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'); - } - } - if ($line[1] =~ /\)$/){ - $line[1] =~ s/\s*\(.*\)$//; - } - $cpu{'model_name'} = $line[1]; - $cpu{'type'} = cpu_vendor($line[1]); - } - # NOTE: hw.l1icachesize: hw.l1dcachesize: ; in bytes, apparently - elsif ($line[0] eq 'hw.l1icachesize'){ - $cpu{'l1-cache'} = $line[1]/1024; - } - elsif ($line[0] eq 'hw.l2cachesize'){ - $cpu{'l2-cache'} = $line[1]/1024; - } - elsif ($line[0] eq 'hw.l3cachesize'){ - $cpu{'l3-cache'} = $line[1]/1024; - } - # this is in mghz in samples - elsif (!$cpu{'cur-freq'} && - ($line[0] eq 'hw.clockrate' || $line[0] eq 'hw.cpuspeed')){ - $cpu{'cur-freq'} = $line[1]; - } - # these are in hz: 2400000000 - elsif ($line[0] eq 'hw.cpufrequency'){ - $cpu{'cur-freq'} = $line[1]/1000000; - } - elsif ($line[0] eq 'hw.busfrequency_min'){ - $cpu{'min-freq'} = $line[1]/1000000; - } - elsif ($line[0] eq 'hw.busfrequency_max'){ - $cpu{'max-freq'} = $line[1]/1000000; - } - # 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]); - # $cpu{'processors'}->[$1] = $speed; - # } - # weird FB thing, freq can be wrong, so just count the cores and call it - # done. - elsif ($line[0] =~ /^dev\.cpu\.([0-9]+)\./ && - (!$cpu{'processors'} || !defined $cpu{'processors'}->[$1])){ - $cpu{'processors'}->[$1] = undef; - } - elsif ($line[0] eq 'machdep.cpu.vendor'){ - $cpu{'type'} = cpu_vendor($line[1]); - } - # darwin only? - elsif ($line[0] eq 'machdep.cpu.features'){ - $cpu{'flags'} = lc($line[1]); - } - elsif ($line[0] eq 'hw.ncpu'){ - $cpu{'cores'} = $line[1]; - } - # Freebsd does some voltage hacking to actually run at lowest listed - # frequencies. The cpu does not actually support all the speeds output - # here but works in freebsd. Disabled this, the freq appear to refer to - # something else, not cpu clock. Remove XXX to enable - elsif ($line[0] eq 'dev.cpu.0.freq_levelsXXX'){ - $line[1] =~ s/^\s+|\/[0-9]+|\s+$//g; - if ($line[1] =~ /[0-9]+\s+[0-9]+/){ - # get rid of -1 in FB: 2400/-1 2200/-1 2000/-1 1800/-1 - $line[1] =~ s|/-1||g; - my @temp = split(/\s+/, $line[1]); - $cpu{'max-freq'} = $temp[0]; - $cpu{'min-freq'} = $temp[-1]; - $cpu{'scalings'} = \@temp; - } - } - # Disabled w/XXX. this is almost certainly bad data, should not be used - elsif (!$cpu{'cur-freq'} && $line[0] eq 'dev.cpu.0.freqXXX'){ - $cpu{'cur-freq'} = $line[1]; - } - # the following have only been seen in DragonflyBSD data but thumbs up! - elsif ($line[0] eq 'hw.cpu_topology.members'){ - 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; - } - } - elsif ($line[0] eq 'hw.cpu_topology.cpu1.physical_siblings'){ - # string, like: cpu0 cpu1 - 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. - 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]; - } - } - 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; - } - } - if (!$cpu{'flags'} || !$cpu{'family'}){ - 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'}; - } - 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 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); - # this will be null if it was not readable - my $file = $system_files{'dmesg-boot'}; - if ($dboot{'cpu'}){ - foreach (@{$dboot{'cpu'}}){ - # can be ~Features/Features2/AMD Features - if (/Features/ || ($bsd_type eq "openbsd" && - /^cpu0:\s*[a-z0-9]{2,3}(\s|,)[a-z0-9]{2,3}(\s|,)/i)){ - my @line = split(/:\s*/, lc($_)); - # free bsd has to have weird syntax: <....,> - # Features2=0x1e98220b - $line[1] =~ s/^[^<]*<|>[^>]*$//g; - # then get rid of stuff - $line[1] =~ s/<[^>]+>//g; - # handle corner case like ,EL3 32, - $line[1] =~ s/ (32|64)/_$1/g; - # and replace commas with spaces - $line[1] =~ s/,/ /g; - $flags .= $sep . $line[1]; - $sep = ' '; - } - # cpu0:AMD E1-1200 APU with Radeon(tm) HD Graphics, 1398.66 MHz, 14-02-00 - elsif (/^cpu0:\s*([^,]+),\s+([0-9\.]+\s*MHz),\s+([0-9a-f]+)-([0-9a-f]+)-([0-9a-f]+)/){ - $type = cpu_vendor($1); - $family = uc($3); - $model = uc($4); - $stepping = uc($5); - $family =~ s/^0//; - $model =~ s/^0//; - $stepping =~ s/^0//; # can be 00 - } - # note: cpu cache is in KiB MiB even though they call it KB and MB - # cpu31: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache - # 8-way means 1 per core, 16-way means 1/2 per core - 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 - } - if (/\b([0-9\.]+[KMG])i?B\s\S+\s([0-9]+)-way\sL2[\s-]?cache/){ - $l2 = main::translate_size($1); - } - if (/\b([0-9\.]+[KMG])i?B\s\S+\s([0-9]+)-way\sL3[\s-]?cache/){ - $l3 = main::translate_size($1); - } - } - elsif (/^~Origin:(.+?)[\s,]+(Id|Family|Model|Stepping)/){ - $type = cpu_vendor($1); - if (/\bId\s*=\s*(0x)?([0-9a-f]+)\b/){ - $microcode = ($1) ? uc($2) : $2; - } - if (/\bFamily\s*=\s*(0x)?([a-f0-9]+)\b/){ - $family = ($1) ? uc($2) : $2; - } - if (/\bModel\s*=\s*(0x)?([a-f0-9]+)\b/){ - $model = ($1) ? uc($2) : $2; - } - # 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; - } - } - elsif (/^cpu0:.*?[0-9\.]+\s?MHz:\sspeeds:\s(.*?)\s?MHz/){ - @scalings = split(/[,\s]+/,$1); - $min_freq = $scalings[-1]; - $max_freq = $scalings[0]; - } - # 2 core MT Intel Core/Rzyen similar, use smt 0 as trigger to count: - # cpu2:smt 0, core 1, package 0 - # cpu3:smt 1, core 1, package 0 - ## but: older AMD Athlon 2 core: - # cpu0:smt 0, core 0, package 0 - # cpu0:smt 0, core 0, package 1 - elsif (/cpu([0-9]+):smt\s([0-9]+),\score\s([0-9]+)(,\spackage\s([0-9]+))?/){ - $siblings = $1 + 1; - $cores += 1 if $2 == 0; - } - } - if ($flags){ - $flags =~ s/\s+/ /g; - $flags =~ s/^\s+|\s+$//g; - } - } - else { - if ($file && ! -r $file){ - $flags = main::row_defaults('dmesg-boot-permissions'); - } - } - %values = ( - 'cores' => $cores, - 'family' => $family, - 'flags' => $flags, - 'l1-cache' => $l1, - 'l2-cache' => $l2, - 'l3-cache' => $l3, - 'max-freq' => $max_freq, - 'microcode' => $microcode, - 'min-freq' => $min_freq, - 'model-id' => $model, - 'scalings' => \@scalings, - 'siblings' => $siblings, - 'stepping' => $stepping, - 'type' => $type, - ); - print Data::Dumper::Dumper \%values if $dbg[27]; - eval $end if $b_log; - 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 ($id,$amount,$socket,$upgrade); - foreach my $item (@dmi){ - next if ref $item ne 'ARRAY'; - next if ($item->[0] < 4 || $item->[0] == 5 || $item->[0] == 6); - last if $item->[0] > 7; - if ($item->[0] == 7){ - # skip first three rows, we don't need that data - ($id,$amount) = ('',0); - foreach my $value (@$item[3 .. $#$item]){ - 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; - } - # some cpus only show Socket Designation: Internal cache - elsif (!$id && $value =~ /^Configuration:.* Level.*?([1-3])\b/){ - $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 - elsif ($id && $value =~ /^Installed Size:\s+(.*?[kKM])i?B$/){ - $amount = main::translate_size($1); - } - if ($id && $amount){ - $dmi_data{$id} = $amount; - $dmi_data{$id . '-total'} += $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. - # 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); - foreach my $value (@$item[3 .. $#$item]){ - 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; - # 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; - } - # 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); - } - elsif ($value =~ /^Current Speed:\s*([0-9\.]+)\s*([MGK]Hz)?\b/i){ - $dmi_data{'speed'} = main::dmi_cleaner($1); - } - elsif ($value =~ /^Max Speed:\s*([0-9\.]+)\s*([MGK]Hz)?\b/i){ - $dmi_data{'max-speed'} = main::dmi_cleaner($1); - } - elsif ($value =~ /^External Clock:\s*([0-9\.]+\s*[MGK]Hz)\b/){ - $dmi_data{'ext-clock'} = main::dmi_cleaner($1); - } - } - } - } - # Seen older cases where Upgrade: Other value exists - if ($socket || $upgrade){ - if ($socket && $upgrade){ - $upgrade = undef if $socket eq $upgrade; - } - elsif ($upgrade){ - $socket = $upgrade; - $upgrade = undef; - } - $dmi_data{'socket'} = $socket; - $dmi_data{'upgrade'} = $upgrade; - } - main::log_data('dump','%dmi_data',\%dmi_data) if $b_log; - # print Data::Dumper::Dumper \%dmi_data; - eval $end if $b_log; - return %dmi_data; -} -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; - } - } - } - } - elsif ($cpu->{'type'} eq 'elbrus'){ - $b_elbrus = 1; - } - } - # 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 $_; - } - # 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 - my $arch = 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 && ($b_mips || $b_arm || $b_ppc)){ - $cpu->{'arch'} = $cpu_arch; - } - # print "$cpu{'type'},$cpu{'family'},$cpu{'model-id'},$cpu{'arch'}\n"; - 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]; - $cpu->{'arch'} = $elbrus[2]; - # print 'model id: ' . $cpu->{'model-id'} . ' arch: ' . $cpu->{'arch'} . " cpc: $cpu_cores phyc: $physical_count proc: $processors_count \n"; - } - $physical_count ||= 1; # assume 1 if no id found, as with ARM - foreach my $die_ref (@phys){ - next if ref $die_ref ne 'ARRAY'; - $core_count = 0; - $die_count = scalar @$die_ref; - #$cpu->{'dies'} = $die_count; - foreach my $core_ref (@$die_ref){ - next if ref $core_ref ne 'ARRAY'; - $core_count = 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 - foreach my $id (@$core_ref){ - $core_count++ if defined $id && !$b_arm; - } - # print 'cores: ' . $core_count, "\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; - # 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'}; - } - elsif ($core_count > $cpu->{'cores'}){ - $cpu_cores = $core_count; - } - } - # print "cpu-c:$cpu_cores\n"; - # $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 ($cpu->{'siblings'}/$cpu->{'cores'} == 1){ - $b_intel = 0; - $b_ht = 0; - } - else { - $cpu_cores = ($cpu->{'siblings'}/2); - $b_ht = 1; - } - } - } - # ryzen is made out of blocks of 8 core dies.. only it isn't that simple, sigh - elsif ($b_ryzen){ - $cpu_cores = $cpu->{'cores'}; - # note: posix ceil isn't present in Perl for some reason, deprecated? - my $working = $cpu_cores / 8; - my @temp = split('\.', $working); - $cpu->{'dies'} = ($temp[1] && $temp[1] > 0) ? $temp[0]++ : $temp[0]; - } - # these always have 4 dies - elsif ($b_epyc){ - $cpu_cores = $cpu->{'cores'}; - $cpu->{'dies'} = 4; - } -# elsif ($b_elbrus){ -# $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); - } - # 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; - } - # 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;; - } - my $count = $processors_count; - $count-- if $count > 0; - $cpu->{'processors'}[$count] = 0; - # no way to get per processor speeds yet, so assign 0 to each - # must be a numeric value. Could use raw speed from core 0, but - # that would just be a hack. - foreach (0 .. $count){ - $cpu->{'processors'}[$_] = 0; - } - } - # so far only OpenBSD has a way to detect MT cpus - if ($bsd_type){ - if ($cpu->{'siblings'}){ - $cores_x = $cpu_cores if $cpu_cores && $cpu_cores > 1; - } - # if no siblings we couldn't get MT status of cpu so can't trust cache else { - $cache_check = main::row_defaults('note-check'); + next if $cpuinfo_machine{lc($key)}; + $cpuinfo_machine{lc($key)} = $value; } } - # only elbrus shows L1 / L3 cache data in cpuinfo, getconf data should show - # for newer full linux. - else { - $cores_x = $cpu_cores if $cpu_cores && $cpu_cores > 1; + if ($b_log){ + main::log_data('dump','@cpuinfo',\@cpuinfo); + main::log_data('dump','%cpuinfo_machine',\%cpuinfo_machine); } - # 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; - $cpu->{'siblings'} = 1; + if ($dbg[41]){ + print Data::Dumper::Dumper \@cpuinfo; + print Data::Dumper::Dumper \%cpuinfo_machine; } - if ($extra > 1 || ($bsd_type && !$cpu->{'l2-cache'})){ - # note: dmidecode has one entry per cpu per cache type - my %cpu_dmi = dmidecode_data(); - # fix for bsds that do not show physical cpus, like openbsd - if ($physical_count == 1 && $cpu_dmi{'L2'} && - ($cpu_dmi{'L2-total'} / $cpu_dmi{'L2'} != 1)){ - $physical_count = sprintf("%.0f",$cpu_dmi{'L2-total'} / $cpu_dmi{'L2'}) + 0; - } - # this is the total per cpu, not per core when using dmidecode - if ($cpu_dmi{'L1'} && $cpu_dmi{'L1'} && - (!$cpu->{'l1-cache'} || $force{'dmidecode'})){ - $l1_cache = $cpu_dmi{'L1'}; - } - # 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. - if ($cpu_dmi{'L2'} && $cpu_dmi{'L2'} && - (!$cpu->{'l2-cache'} || $force{'dmidecode'})){ - $l2_cache = $cpu_dmi{'L2'}; - } - if ($cpu_dmi{'L3'} && (!$cpu->{'l3-cache'} || $force{'dmidecode'})){ - $l3_cache = $cpu_dmi{'L3'}; - } - $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; - - ## START CACHE ## - # dmidecode sourced cache is total per cpu as far as I know, will confirm. - # with getconf cache data, we can now get L1 and L3 cache without dmidecode - # and sudo root, so those will now usually be there for Linux. - # L1 Cache - if (!$l1_cache && $cpu->{'l1-cache'}){ - $l1_cache = $cpu->{'l1-cache'} * $cores_x; - } - # L2 Cache - if (!$cpu->{'l2-cache'} || $l2_cache){ - # do nothing, it's either not there, or already summed by dmidecode - } - # 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... - elsif ($bsd_type){ - $l2_cache = $cpu->{'l2-cache'} * $cores_x; - } - elsif ($cpu->{'caches'}){ - $l2_cache = $cpu->{'l2-cache'} * $cores_x; - } - # AMD SOS chips appear to report full L2 cache per cpu - elsif ($cpu->{'type'} eq 'amd' && !$cpu->{'caches'} && - ($cpu->{'family'} eq '14' || $cpu->{'family'} eq '15' || - $cpu->{'family'} eq '16')){ - $l2_cache = $cpu->{'l2-cache'}; - } - elsif ($cpu->{'type'} ne 'intel' || $cpu->{'caches'}){ - $l2_cache = $cpu->{'l2-cache'} * $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 { - $l2_cache = $cpu->{'l2-cache'}; - } - # L3 Cache - almost always per physical cpu, not per core. - # But may in future be > 1 L3 per phys cpu - if (!$l3_cache && $cpu->{'l3-cache'}){ - $l3_cache = $cpu->{'l3-cache'}; - } - $cache_check = '' if !$l1_cache && !$l2_cache && !$l3_cache; # nothing to check! - $l1_cache = process_cache($l1_cache,$physical_count) if $l1_cache; - $l2_cache = process_cache($l2_cache,$physical_count) if $l2_cache; - $l3_cache = process_cache($l3_cache,$physical_count) if $l3_cache; - ## END CACHE ## - - ## START SPEED/BITS ## - 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; - } - ## END SPEED/BITS ## - 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 if $dbg[38]; - # my $dc = scalar @dies; - # print 'phys: ' . $pc . ' dies: ' . $dc, "\n"; eval $end if $b_log; - return %cpu_properties; } -sub process_cache { - my ($cache,$count) = @_; - my $output; - if ($count > 1){ - $output = $count . 'x ' . main::get_size($cache,'string'); - $output .= ' (' . main::get_size($cache * $count,'string') . ')'; - } - else { - $output = main::get_size($cache,'string'); - } - # print "$cache :: $count :: $output\n"; - return $output; -} -sub cpu_data_sys { +sub cpu_sys_data { eval $start if $b_log; + my $sys_freq = $_[0]; my (%cpu_sys); - my $working = get_sys_data(); - return %cpu_sys if !%{$working}; + my $working = sys_data_grabber(); + return \%cpu_sys if !%{$working}; $cpu_sys{'data'} = $working->{'data'} if $working->{'data'}; - my ($core_id,$phys_id) = (0,0); - my (%cache_ids,@freq_max,@freq_min,@speeds); + 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 = $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 (defined $cpu->{'cpufreq'}{'scaling_cur_freq'}){ - # note: unassigned cpus don't have topology or core id data - if (defined $cpu->{'cpufreq'}{'affected_cpus'} && + if ($fake{'cpu'}){ + if (defined $cpu->{'cpufreq'}{'scaling_cur_freq'} && + $cpu->{'cpufreq'}{'affected_cpus'} && $cpu->{'cpufreq'}{'affected_cpus'} ne 'UNDEFINED'){ - $cpu->{'cpufreq'}{'scaling_cur_freq'} = speed_cleaner($cpu->{'cpufreq'}{'scaling_cur_freq'},'khz'); - push(@{$cpu_sys{$phys_id}->{'cores'}{$core_id}},$cpu->{'cpufreq'}{'scaling_cur_freq'}); - push(@speeds,$cpu->{'cpufreq'}{'scaling_cur_freq'}); + $speed = clean_speed($cpu->{'cpufreq'}{'scaling_cur_freq'},'khz'); } } + elsif (defined $sys_freq && defined $sys_freq->{$key}){ + $speed = $sys_freq->{$key}; + } + if (defined $speed){ + push(@{$cpu_sys{'cpus'}->{$phys_id}{'cores'}{$core_id}},$speed); + push(@{$cpu_sys{'data'}->{'speeds'}{'all'}},$speed); + } + 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'}; @@ -9622,31 +9225,24 @@ sub cpu_data_sys { if (defined $cpu->{'topology'}{'core_cpus_list'}){ $cpu->{'topology'}{'thread_siblings_list'} = $cpu->{'topology'}{'core_cpus_list'}; } - if (defined $cpu->{'cpufreq'}{'cpuinfo_max_freq'}){ - $cpu->{'cpufreq'}{'cpuinfo_max_freq'} = speed_cleaner($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 (defined $cpu->{'cpufreq'}{'cpuinfo_min_freq'}){ - $cpu->{'cpufreq'}{'cpuinfo_min_freq'} = speed_cleaner($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 (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'}){ - my $range = main::regex_range($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 ($cpu_id =~ /^($range)$/ && - !(grep {$_ eq $cache->{'shared_cpu_list'}} @{$cache_ids{$phys_id}->{$level}})){ + 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{$phys_id}->{'caches'}{$level}},$size); + push(@{$cpu_sys{'cpus'}->{$phys_id}{'caches'}{$level}},$size); } } } @@ -9656,11 +9252,20 @@ sub cpu_data_sys { 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{$phys_id}->{'dies'}}){ - push(@{$cpu_sys{$phys_id}->{'dies'}},$die); + if (!grep {$_ eq $die} @{$cpu_sys{'cpus'}->{$phys_id}{'dies'}}){ + push(@{$cpu_sys{'cpus'}->{$phys_id}{'dies'}},$die); } } } + 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'; + } + else { + $cpu_sys{'data'}->{'cpufreq-boost'} = 'disabled'; + } + } # cpuinfo_max_freq:["2000000"] cpuinfo_max_freq:["1500000"] # cpuinfo_min_freq:["200000"] if (@freq_max){ @@ -9669,11 +9274,6 @@ sub cpu_data_sys { if (@freq_min){ $cpu_sys{'data'}->{'speeds'}{'min-freq'} = join(':',@freq_min); } - if (@speeds){ - my $agg = 0; - $agg += $_ for @speeds; - $cpu_sys{'data'}->{'speeds'}{'avg-freq'} = int($agg/scalar @speeds); - } if ((scalar @freq_max < 2 && scalar @freq_min < 2) && (defined $cpu_sys{'data'}->{'speeds'}{'min-freq'} && defined $cpu_sys{'data'}->{'speeds'}{'max-freq'}) && @@ -9681,25 +9281,67 @@ sub cpu_data_sys { $cpu_sys{'data'}->{'speeds'}{'min-freq'} == $cpu_sys{'data'}->{'speeds'}{'max-freq'})){ $cpu_sys{'data'}->{'speeds'}{'min-freq'} = 0; } - # print Data::Dumper::Dumper \%cache_ids if $dbg[39]; main::log_data('dump','%cpu_sys',\%cpu_sys) if $b_log; - print Data::Dumper::Dumper \%cpu_sys if $dbg[39]; + print Data::Dumper::Dumper \%cpu_sys if $dbg[8]; eval $end if $b_log; return \%cpu_sys; } -sub get_sys_data { +sub sys_data_grabber { eval $start if $b_log; - my $glob = '/sys/devices/system/cpu/'; - $glob .= '{cpufreq,cpu*/topology,cpu*/cpufreq,cpu*/cache/index*,smt,'; - $glob .= 'vulnerabilities}/*'; - my @files = main::globber($glob); + 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 { + 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','@files',\@files) if $b_log; print Data::Dumper::Dumper \@files if $dbg[40]; - return if !@files; 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){ - next if -d $_; + if ($fake{'cpu'}){ + ($_,$item) = split(/::/,$_,2); + } + else { + next if -d $_ || ! -e $_; + undef $item; + } $key = $_; $key =~ m|/([^/]+)/([^/]+)$|; my ($key_1,$key_2) = ($1,$2); @@ -9751,13 +9393,25 @@ sub get_sys_data { $main_key = ''; $main_id = ''; } - if (-r $_) { - $item = main::reader($_,'strip',0); + 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; } - else { - $item = main::row_defaults('root-required'); - } - $item = main::row_defaults('undefined') if ! defined $item; + # print "$key_1 :: $key_2 :: $item\n"; if ($b_main){ $working{'data'}->{$id} = $item; } @@ -9778,266 +9432,1007 @@ sub get_sys_data { eval $end if $b_log; return \%working; } -sub get_boost_status { +sub sysctl_data { eval $start if $b_log; - my ($boost); - my $path = '/sys/devices/system/cpu/cpufreq/boost'; - # older amd used per cpu: /sys/devices/system/cpu/cpufreq/policy0/cpb - my $path2 = '/sys/devices/system/cpu/cpufreq/policy0/cpb'; - if (-r $path || -r $path2){ - $path = $path2 if ! -r $path; - $boost = main::reader($path,'',0); - if (defined $boost && $boost =~ /^[01]$/){ - $boost = ($boost) ? 'enabled' : 'disabled'; + my %cpu = set_cpu_data(); + 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! + foreach (@{$sysctl{'cpu'}}){ + @line = split(/\s*:\s*/, $_); + next if !$line[0]; + # darwin shows machine, like MacBook7,1, not cpu + # machdep.cpu.brand_string: Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz + if (($bsd_type ne 'darwin' && $line[0] eq 'hw.model') || + $line[0] eq 'machdep.cpu.brand_string'){ + # cut L2 cache/cpu max speed out of model string, if available + # 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::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; + } + if ($line[1] =~ /([^0-9\.][0-9\.]+)[\s-]*[MG]Hz/){ + $cpu{'max-freq'} = $1; + if ($cpu{'max-freq'} =~ /MHz/i){ + $cpu{'max-freq'} =~ s/[\s-]*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'} = clean_speed($cpu{'max-freq'},'mhz'); + } + } + if ($line[1] =~ /\)$/){ + $line[1] =~ s/\s*\(.*\)$//; + } + $cpu{'model_name'} = $line[1]; + $cpu{'type'} = cpu_vendor($line[1]); } - } - eval $end if $b_log; - return $boost; -} - -sub cpu_bugs_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: //; - $bugs{$_} = [$type,$value]; + # NOTE: hw.l1icachesize: hw.l1dcachesize: ; in bytes, apparently + elsif ($line[0] eq 'hw.l1dcachesize'){ + $cpu{'l1d-cache'} = $line[1]/1024; } - } - 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 ($b_skip,@temp,@speeds); - my @files = main::globber('/sys/devices/system/cpu/cpu*/cpufreq/{affected_cpus,scaling_cur_freq}'); - # print Data::Dumper::Dumper \@files; - foreach (sort @files){ - if (/affected_cpus$/){ - # some cases, eg vm with shared cpu/threads, have speed but undefined affected_cpus - $b_skip = (defined main::reader($_,'strip',0)) ? 0: 1; + elsif ($line[0] eq 'hw.l1icachesize'){ + $cpu{'l1i-cache'} = $line[1]/1024; } - elsif (!$b_skip) { - push(@temp,$_); + elsif ($line[0] eq 'hw.l2cachesize'){ + $cpu{'l2-cache'} = $line[1]/1024; } - } - @files = @temp if @temp; - foreach (@files){ - my $speed = main::reader($_,'',0); - if (defined $speed){ - $speed = sprintf("%.0f", $speed/1000); - push(@speeds, $speed); + elsif ($line[0] eq 'hw.l3cachesize'){ + $cpu{'l3-cache'} = $line[1]/1024; } - } - 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, $_); + # 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')){ + $cpu{'cur-freq'} = $line[1]; + } + # these are in hz: 2400000000 + elsif ($line[0] eq 'hw.cpufrequency'){ + $cpu{'cur-freq'} = $line[1]/1000000; + } + elsif ($line[0] eq 'hw.busfrequency_min'){ + $cpu{'min-freq'} = $line[1]/1000000; + } + elsif ($line[0] eq 'hw.busfrequency_max'){ + $cpu{'max-freq'} = $line[1]/1000000; + } + # 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 = clean_speed($line[1]); + # $cpu{'processors'}->[$1] = $speed; + # } + # weird FB thing, freq can be wrong, so just count the cores and call it + # done. + elsif ($line[0] =~ /^dev\.cpu\.([0-9]+)\./ && + (!$cpu{'processors'} || !defined $cpu{'processors'}->[$1])){ + $cpu{'processors'}->[$1] = undef; + } + elsif ($line[0] eq 'machdep.cpu.vendor'){ + $cpu{'type'} = cpu_vendor($line[1]); + } + # darwin only? + 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]; + } + # Freebsd does some voltage hacking to actually run at lowest listed + # frequencies. The cpu does not actually support all the speeds output + # here but works in freebsd. Disabled this, the freq appear to refer to + # something else, not cpu clock. Remove XXX to enable + elsif ($line[0] eq 'dev.cpu.0.freq_levelsXXX'){ + $line[1] =~ s/^\s+|\/[0-9]+|\s+$//g; + if ($line[1] =~ /[0-9]+\s+[0-9]+/){ + # get rid of -1 in FB: 2400/-1 2200/-1 2000/-1 1800/-1 + $line[1] =~ s|/-1||g; + my @temp = split(/\s+/, $line[1]); + $cpu{'max-freq'} = $temp[0]; + $cpu{'min-freq'} = $temp[-1]; + $cpu{'scalings'} = \@temp; } } - } - # 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'); + # Disabled w/XXX. this is almost certainly bad data, should not be used + elsif (!$cpu{'cur-freq'} && $line[0] eq 'dev.cpu.0.freqXXX'){ + $cpu{'cur-freq'} = $line[1]; } - 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; - } - } - 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; + # the following have only been seen in DragonflyBSD data but thumbs up! + elsif ($line[0] eq 'hw.cpu_topology.members'){ + my @temp = split(/\s+/, $line[1]); + my $count = scalar @temp; + $count-- if $count > 0; + # no way to get per processor speeds yet, so assign 0 to each + foreach (0 .. $count){ + $cpu{'processors'}->[$_] = 0; } } - # 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; + elsif ($line[0] eq 'hw.cpu_topology.cpu1.physical_siblings'){ + # string, like: cpu0 cpu1 + 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. + # 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]; + push(@{$cpu{'ids'}->[$phys_id][$die_id]},0); + } + } + elsif ($line[0] eq 'hw.cpu_topology.cpu0.core_id'){ + $cpu{'ids'}->[$phys_id][$line[1]] = $speed; } } - main::log_data('dump','%speeds',\%speeds) if $b_log; + if (!$cpu{'flags'} || !$cpu{'family'}){ + 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{'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 %speeds; + return \%cpu; } -# right now only using this for ARM cpus, this is not the same in intel/amd -sub cpu_dies_sys { +## DATA GENERATOR DATA SOURCES ## +sub dboot_data { 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 {$_ eq $siblings} @dies){ - push(@dies, $siblings); + my ($max_freq,$min_freq,@scalings,%values); + my ($family,$flags,$microcode,$model,$sep,$stepping,$type) = ('','','','','','',''); + my ($cores,$siblings) = (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'}){ + foreach (@{$dboot{'cpu'}}){ + # can be ~Features/Features2/AMD Features + if (/Features/ || ($bsd_type eq "openbsd" && + /^cpu0:\s*[a-z0-9]{2,3}(\s|,)[a-z0-9]{2,3}(\s|,)/i)){ + my @line = split(/:\s*/, lc($_)); + # free bsd has to have weird syntax: <....,> + # Features2=0x1e98220b + $line[1] =~ s/^[^<]*<|>[^>]*$//g; + # then get rid of stuff + $line[1] =~ s/<[^>]+>//g; + # handle corner case like ,EL3 32, + $line[1] =~ s/ (32|64)/_$1/g; + # and replace commas with spaces + $line[1] =~ s/,/ /g; + $flags .= $sep . $line[1]; + $sep = ' '; + } + # cpu0:AMD E1-1200 APU with Radeon(tm) HD Graphics, 1398.66 MHz, 14-02-00 + elsif (/^cpu0:\s*([^,]+),\s+([0-9\.]+\s*MHz),\s+([0-9a-f]+)-([0-9a-f]+)-([0-9a-f]+)/){ + $type = cpu_vendor($1); + $family = uc($3); + $model = uc($4); + $stepping = uc($5); + $family =~ s/^0//; + $model =~ s/^0//; + $stepping =~ s/^0//; # can be 00 + } + # note: cpu cache is in KiB MiB even though they call it KB and MB + # cpu31: 32KB 64b/line 8-way I-cache, 32KB 64b/line 8-way D-cache, 512KB 64b/line 8-way L2 cache + # 8-way means 1 per core, 16-way means 1/2 per core + 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\sD[\s-]?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); + } + if (/\b([0-9\.]+[KMG])i?B\s\S+\s([0-9]+)-way\sL3[\s-]?cache/){ + $l3 = main::translate_size($1); + } + } + elsif (/^~Origin:(.+?)[\s,]+(Id|Family|Model|Stepping)/){ + $type = cpu_vendor($1); + if (/\bId\s*=\s*(0x)?([0-9a-f]+)\b/){ + $microcode = ($1) ? uc($2) : $2; + } + if (/\bFamily\s*=\s*(0x)?([a-f0-9]+)\b/){ + $family = ($1) ? uc($2) : $2; + } + if (/\bModel\s*=\s*(0x)?([a-f0-9]+)\b/){ + $model = ($1) ? uc($2) : $2; + } + # 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; + } + } + elsif (/^cpu0:.*?[0-9\.]+\s?MHz:\sspeeds:\s(.*?)\s?MHz/){ + @scalings = split(/[,\s]+/,$1); + $min_freq = $scalings[-1]; + $max_freq = $scalings[0]; + } + # 2 core MT Intel Core/Rzyen similar, use smt 0 as trigger to count: + # cpu2:smt 0, core 1, package 0 + # cpu3:smt 1, core 1, package 0 + ## but: older AMD Athlon 2 core: + # cpu0:smt 0, core 0, package 0 + # cpu0:smt 0, core 0, package 1 + elsif (/cpu([0-9]+):smt\s([0-9]+),\score\s([0-9]+)(,\spackage\s([0-9]+))?/){ + $siblings = $1 + 1; + $cores += 1 if $2 == 0; + } + } + if ($flags){ + $flags =~ s/\s+/ /g; + $flags =~ s/^\s+|\s+$//g; } } - eval $end if $b_log; - return scalar @dies; -} -# 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 { - 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, + else { + if ($file && ! -r $file){ + $flags = main::message('dmesg-boot-permissions'); + } + } + %values = ( + 'cores' => $cores, + 'family' => $family, + 'flags' => $flags, + '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, + 'scalings' => \@scalings, + 'siblings' => $siblings, + 'stepping' => $stepping, + 'type' => $type, ); - $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]; - } + print Data::Dumper::Dumper \%values if $dbg[27]; eval $end if $b_log; - return @return; + return \%values; } - -# only elbrus ID is actually used live -sub cpu_vendor { +sub dmidecode_data { 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; -} -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; + return if !@dmi; + 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'; + next if ($item->[0] < 4 || $item->[0] == 5 || $item->[0] == 6); + 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 =~ /^~/; + # variants: L3 - Cache; L3 Cache; L3-cache; L2 CACHE; CPU Internal L1 + if ($value =~ /^Socket Designation:.*? (L[1-3])\b/){ + $id = lc($1); + } + # some cpus only show Socket Designation: Internal cache + elsif (!$id && $value =~ /^Configuration:.* Level.*?([1-3])\b/){ + 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; + 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 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,undef); + $dmi_data{'phys-cnt'}++; # try to catch bsds without physical cpu count + foreach my $value (@$item[3 .. $#$item]){ + 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::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::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::clean_dmi($1); + } + elsif ($value =~ /^Current Speed:\s*([0-9\.]+)\s*([MGK]Hz)?\b/i){ + $dmi_data{'speed'} = main::clean_dmi($1); + } + elsif ($value =~ /^Max Speed:\s*([0-9\.]+)\s*([MGK]Hz)?\b/i){ + $dmi_data{'max-speed'} = main::clean_dmi($1); + } + elsif ($value =~ /^External Clock:\s*([0-9\.]+\s*[MGK]Hz)\b/){ + $dmi_data{'ext-clock'} = main::clean_dmi($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; + # Seen older cases where Upgrade: Other value exists + if ($socket || $upgrade){ + if ($socket && $upgrade){ + $upgrade = undef if $socket eq $upgrade; } + elsif ($upgrade){ + $socket = $upgrade; + $upgrade = undef; + } + $dmi_data{'socket'} = $socket; + $dmi_data{'upgrade'} = $upgrade; } - main::log_data('dump','%cpus',\%cpus) if $b_log; + main::log_data('dump','%dmi_data',\%dmi_data) if $b_log; + print Data::Dumper::Dumper \%dmi_data if $dbg[27]; eval $end if $b_log; - return %cpus; + return \%dmi_data; } -sub cpu_arch { +## CPU PROPERTIES MAIN ## +sub cpu_properties { + my ($cpu) = @_; + 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'}); + } + 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); + } + # 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 + # print ref $cpu->{'processors'}, "\n"; + 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: $counts->{'cpu-cores'} phyc: $counts->{'physical'} proc: $counts->{'processors'} \n"; + } + $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'; + $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'; + $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 + # risc cpus do not actually show core id so ignore that counter + foreach my $id (@$core_ref){ + $counts->{'cores'}++ if defined $id && !%risc; + } + # print 'cores: ' . $counts->{'cores'}, "\n"; + } + } + # this covers potentially cases where ARM cpus have > 1 die + # 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 (!$counts->{'cpu-cores'}){ + if ($cpu->{'cores'} && !$counts->{'cores'} || + $cpu->{'cores'} >= $counts->{'cores'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; + } + elsif ($counts->{'cores'} > $cpu->{'cores'}){ + $counts->{'cpu-cores'} = $counts->{'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 ($tests->{'intel'}){ + if ($cpu->{'siblings'} && $cpu->{'siblings'} > 1 && + $cpu->{'cores'} && $cpu->{'cores'} > 1){ + if ($cpu->{'siblings'}/$cpu->{'cores'} == 1){ + $tests->{'intel'} = 0; + $tests->{'ht'} = 0; + } + else { + $counts->{'cpu-cores'} = ($cpu->{'siblings'}/2); + $tests->{'ht'} = 1; + } + } + } + # 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 = $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 ($tests->{'epyc'}){ + $counts->{'cpu-cores'} = $cpu->{'cores'}; + $counts->{'dies'} = $cpu->{'dies'} = 4; + } + # 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 ($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 ($counts->{'cpu-cores'} == 0 && $counts->{'processors'} > 0){ + $counts->{'cpu-cores'} = $counts->{'processors'}; + } + # this happens with BSDs which have very little cpu data available + 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 = $counts->{'processors'}; + $count-- if $count > 0; + $cpu->{'processors'}[$count] = 0; + # no way to get per processor speeds yet, so assign 0 to each + # must be a numeric value. Could use raw speed from core 0, but + # that would just be a hack. + foreach (0 .. $count){ + $cpu->{'processors'}[$_] = 0; + } + } + # so far only OpenBSD has a way to detect MT cpus, but Openbsd has disabled MT + if ($bsd_type){ + 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::message('note-check'); + } + } + # 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: $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; + } + eval $end if $b_log; +} +# all values passed by reference so no need for returns +sub cp_data_sys { + eval $start if $b_log; + 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',''); + } + if ($cpu_sys->{'data'}{'speeds'}{'all'}){ + $counts->{'processors'} = scalar @{$cpu_sys->{'data'}{'speeds'}{'all'}}; + } + 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'; + } + } + 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; + } + } + } + } + $i++; + } + } + $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); + } + # print Data::Dumper::Dumper $caches; + # print Data::Dumper::Dumper $counts; + eval $end if $b_log; +} +sub cp_sys_caches { + eval $start if $b_log; + 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; +} + +## 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 = ', '; + } + 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') . ')'; + } + else { + $output = main::get_size($cache,'string'); + } + # print "$cache :: $count :: $output\n"; + return $output; +} +sub cp_caches_fallback { + eval $start if $b_log; + my ($counts,$cpu,$caches,$cache_check) = @_; + # L1 Cache + if ($cpu->{'l1-cache'}){ + $caches->{'l1'} = $cpu->{'l1-cache'} * $counts->{'cores-multiplier'}; + } + 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'}; + } + # 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'}; + } + } + # 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; +} +sub cp_cpu_arch { eval $start if $b_log; my ($type,$family,$model,$stepping) = @_; - # 0: L1 cache; 1: L2 cache: 2: L3 cache; 3: Core math; 4: cores/die - # values: 0: per cpu; 1: per core; decimal: per cpu multiplier; math: cores - $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'){ @@ -10104,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 { @@ -10126,13 +10525,11 @@ sub cpu_arch { } elsif ($family eq '17'){ # can't find stepping/model for no ht 2x2 core/die models, only first ones - if ($model =~ /^(1|11)$/){ - $arch = 'Zen'; - } - elsif ($model =~ /^(18|20)$/){ + 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+'; @@ -10297,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)$/){ @@ -10403,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 { @@ -10423,24 +10826,342 @@ sub cpu_arch { eval $end if $b_log; 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' => '', @@ -10448,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; @@ -10469,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|'; @@ -10484,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'; @@ -10517,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,}); } @@ -10536,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); @@ -10663,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'}; @@ -10684,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 @@ -10962,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]; @@ -11037,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'}){ @@ -11088,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 = ({ @@ -11220,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; } @@ -11257,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'){ @@ -11473,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; } } @@ -11737,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]; @@ -11758,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 @@ -11775,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 @@ -11799,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 @@ -11810,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',''], @@ -11843,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 @@ -11867,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',''], @@ -11882,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',''], @@ -11899,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',''], @@ -11916,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 @@ -11953,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',''], @@ -11995,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',''], @@ -12022,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',''], @@ -12086,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',''], @@ -12131,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',''], @@ -12408,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; } } @@ -12429,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 { @@ -12445,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,''), },); } } @@ -12476,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, @@ -12524,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'; @@ -12553,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; @@ -12606,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, @@ -12634,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 { @@ -12946,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; @@ -13028,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; } @@ -13041,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){ # @@ -13051,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]); } @@ -13073,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){ @@ -13124,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'), }); } } @@ -13142,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; @@ -13394,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 { @@ -13404,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, },); @@ -13424,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'){ @@ -13761,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'}){ @@ -13777,7 +14542,7 @@ sub get { } elsif (!$key1){ $key1 = 'Message'; - $val1 = main::row_defaults('machine-data'); + $val1 = main::message('machine-data'); } } } @@ -13789,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 @@ -13863,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){ @@ -13890,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; @@ -13908,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; @@ -13929,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; @@ -13957,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'}; @@ -13970,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 @@ -13981,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; @@ -14019,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{$_} = ''; @@ -14037,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; @@ -14052,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'}; @@ -14099,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; } } @@ -14156,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'){ @@ -14180,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; @@ -14200,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; @@ -14218,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'){ @@ -14271,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 @@ -14318,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'}){ @@ -14493,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 } @@ -14503,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 { @@ -14517,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,''), },); } } @@ -14561,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, { @@ -14616,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; @@ -14637,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]; @@ -14660,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; @@ -14714,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; @@ -14727,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; } @@ -14735,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"; @@ -14745,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'; @@ -14820,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]; @@ -14887,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'){ @@ -14932,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; } } @@ -14995,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 = ({ @@ -15042,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(); @@ -15051,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,}); @@ -15069,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; @@ -15108,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; @@ -15300,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; @@ -15373,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 { @@ -15408,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'; @@ -15456,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'}; @@ -15687,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'; @@ -16111,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; @@ -16285,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 { @@ -16465,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'}: ''; @@ -16557,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; @@ -16914,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, @@ -17509,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, @@ -17523,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, @@ -17553,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){ @@ -17654,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'}; } } @@ -17680,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 @@ -17733,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 # @@ -17858,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 @@ -17947,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'}}){ @@ -18033,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 @@ -18206,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)"; } @@ -18438,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}); } @@ -18569,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'); @@ -18663,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 = (); } @@ -18746,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, @@ -18809,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, @@ -18844,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, @@ -18895,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, @@ -18941,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}, @@ -18953,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}, @@ -18968,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'; @@ -19020,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; @@ -19044,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, @@ -19088,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, @@ -19191,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 { @@ -19204,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}, @@ -19213,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) = @_; @@ -19250,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); @@ -19259,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); } @@ -19269,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); @@ -19279,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'}; @@ -19295,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); @@ -19307,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'; @@ -19361,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'; @@ -19678,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'} || @@ -19697,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; @@ -19851,6 +20623,7 @@ sub process_lm_sensors { # 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"; # 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 { @@ -20359,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'} = ''; @@ -20390,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'){ @@ -20460,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; @@ -20479,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; @@ -20513,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; @@ -20552,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'}; @@ -20586,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); @@ -20599,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]); } } } @@ -20608,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); @@ -20616,7 +21389,7 @@ sub get { } else { $key1 = 'Message'; - $val1 = main::row_defaults('unmounted-file'); + $val1 = main::message('unmounted-file'); } } if (!@rows && $key1){ @@ -20643,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; @@ -20667,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'}; @@ -20885,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'}; @@ -20904,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',''), },); } } @@ -20926,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]; @@ -20985,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); } } } @@ -21027,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'}"; @@ -21620,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; @@ -22081,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){ @@ -22674,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(); } } @@ -22731,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/){ @@ -22764,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 @@ -22791,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); @@ -22854,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"; } } @@ -22938,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; @@ -22996,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]+\)/){ @@ -23268,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() @@ -23505,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); @@ -23546,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 { @@ -23788,7 +24561,7 @@ sub get_bsd_os { @working = main::reader($distro_file); @working = grep {/(ProductName|ProductVersion)/} @working if @working; @working = grep {//} @working if @working; - @working = map {s/<[\/]?string>//g; } @working if @working; + @working = map {s/<[\/]?string>//g;} @working if @working; $distro = join(' ', @working); } } @@ -24635,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'; } @@ -24883,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; @@ -24912,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; } @@ -25081,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){ @@ -25303,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){ @@ -25409,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; @@ -25507,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){ @@ -25963,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; } @@ -26221,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!! @@ -26536,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; @@ -26651,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,'',''); @@ -26863,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"; @@ -27220,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; @@ -27281,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); @@ -27381,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){ @@ -27403,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'; @@ -27426,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"; } } @@ -27637,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}}); diff --git a/inxi.1 b/inxi.1 index 3022caf..ad6bfbb 100644 --- a/inxi.1 +++ b/inxi.1 @@ -15,7 +15,7 @@ .\" with this program; if not, write to the Free Software Foundation, Inc., .\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. .\" -.TH INXI 1 "2021\-11\-22" "inxi" "inxi manual" +.TH INXI 1 "2021\-12\-13" "inxi" "inxi manual" .SH NAME inxi \- Command line system information script for console and IRC @@ -23,7 +23,7 @@ inxi \- Command line system information script for console and IRC .SH SYNOPSIS \fBinxi\fR -\fBinxi\fR [\fB\-AbBCdDEfFGhiIjJlLmMnNopPrRsSuUVwzZ\fR] +\fBinxi\fR [\fB\-AbBCdDEfFGhiIjJlLmMnNopPrRsSuUVwyYzZ\fR] \fBinxi\fR [\fB\-c NUMBER\fR] [\fB\-\-sensors\-exclude SENSORS\fR] [\fB\-\-sensors\-use SENSORS\fR] @@ -78,19 +78,37 @@ Note that all the short form options have long form equivalents, which are listed below. However, usually the short form is used in examples in order to keep things simple. +These are avalable options sections: + +* \fBSTANDARD OPTIONS\fR Primary data types trigger items. + +* \fBFILTER OPTIONS\fR Apply a variety of output filters. + +* \fBOUTPUT CONTROL OPTIONS\fR Change default colors, widths, heights, output +types, etc. + +* \fBEXTRA DATA OPTIONS\fR What \fB\-x\fR, \fB\-xx\fR, \fB\-xxx\fR, and \fB\-a\fR +add to the output. + +* \fBADVANCED OPTIONS\fR Modify behavior or choice of data sources, and other +advanced switches. + +* \fBDEBUGGING OPTIONS\fR For development use mainly, or contributing datasets to +the project. + .SH STANDARD OPTIONS .TP -.B \-A\fR,\fB \-\-audio\fR +.B \-A \fR, \fB\-\-audio\fR Show Audio/sound device(s) information, including device driver. Show running sound server(s). See \fB\-xxA\fR to show all sound servers detected. .TP -.B \-b\fR,\fB \-\-basic\fR +.B \-b \fR, \fB\-\-basic\fR Show basic output, short form. Same as: \fBinxi \-v 2\fR .TP -.B \-B\fR,\fB \-\-battery\fR +.B \-B \fR, \fB\-\-battery\fR Show system battery (\fBID\-x\fR) data, charge, condition, plus extra information (if battery present). Uses \fB/sys\fR or, for BSDs without systctl battery data, use \fB\-\-dmidecode\fR to force its use. \fBdmidecode\fR does @@ -122,67 +140,35 @@ With \fB\-x\fR shows attached \fBDevice\-x\fR information (mouse, keyboard, etc.) if they are battery powered. .TP -.B \-\-bluetooth\fR \- See \fB\-E\fR +.B \-\-bluetooth\fR +.br +See \fB\-E\fR. .TP -.B \-c\fR,\fB \-\-color\fR \fR[\fB0\fR\-\fB42\fR] -Set color scheme. If no scheme number is supplied, 0 is assumed. +.B \-c \fR, \fB\-\-color\fR +.br +See \fBOUTPUT CONTROL OPTIONS\fR. .TP -.B \-c \fR[\fB94\fR\-\fB99\fR] +.B \-C \fR, \fB\-\-cpu\fR +Show full CPU output (if each item available): basic CPU topology, model, type, +L2 cache, average speed of all cores (if > 1 core, otherwise speed of the core), +min/max speeds for CPU, and per CPU clock speed. More data available with +\fB\-x\fR, \fB\-xxx\fR, and \fB\-a\fR options. -These color selectors run a color selector option prior to inxi starting -which lets you set the config file value for the selection. +Explanation of CPU type (\fBtype: MT MCP\fR) abbreviations: -NOTE: All configuration file set color values are removed when output is -piped or redirected. You must use the explicit runtime \fB\-c \fR -option if you want color codes to be present in the piped/redirected output. +* \fBAMCP\fR \- Asymmetric Multi Core Processor. More than 1 core per CPU, and +more than one core type (single and multithreaded cores in the same CPU). -Color selectors for each type display (NOTE: IRC and global only show safe -color set): +* \fBAMP\fR \- Asymmetric Multi Processing (more than 1 physical CPU, but not +identical in terms of core counts or min/max speeds). -.TP -.B \-c 94\fR -\- Console, out of X. +* \fBMT\fR \- Multi/Hyper Threaded CPU (more than 1 thread per core, previously +\fBHT\fR). -.TP -.B \-c 95\fR -\- Terminal, running in X \- like xTerm. - -.TP -.B \-c 96\fR -\- GUI IRC, running in X \- like XChat, Quassel, -Konversation etc. - -.TP -.B \-c 97\fR -\- Console IRC running in X \- like irssi in xTerm. - -.TP -.B \-c 98\fR -\- Console IRC not in X. - -.TP -.B \-c 99\fR -\- Global \- Overrides/removes all settings. - -Setting a specific color type removes the global color selection. - -.TP -.B \-C\fR,\fB \-\-cpu\fR -Show full CPU output, including per CPU clock speed and CPU max speed (if -available). If max speed data present, shows \fB(max)\fR in short output -formats (\fBinxi\fR, \fBinxi \-b\fR) if actual CPU speed matches max CPU -speed. If max CPU speed does not match actual CPU speed, shows both actual -and max speed information. See \fB\-x\fR for more options. - -For certain CPUs (some ARM, and AMD Zen family) shows CPU die count. - -The details for each CPU include a technical description e.g. \fBtype: MT -MCP\fR - -* \fBMT\fR \- Multi/Hyper Threaded CPU, more than 1 thread per core -(previously \fBHT\fR). +* \fBMST\fR \- Multi and Single Threaded CPU (a CPU with both Single and Multi +Threaded cores). * \fBMCM\fR \- Multi Chip Model (more than 1 die per CPU). @@ -194,10 +180,19 @@ MCP\fR Note that \fBmin/max:\fR speeds are not necessarily true in cases of overclocked CPUs or CPUs in turbo/boost mode. See \fB\-Ca\fR for alternate -\fBbase/boost:\fR speed data. +\fBbase/boost:\fR speed data, more granular cache data, and more. + +Sample: +.nf +\fBCPU: + Info: 2x 8\-core model: Intel Xeon E5\-2620 v4 bits: 64 type: MT MCP SMP + cache: L2: 2x 2 MiB (4 MiB) + Speed (MHz): avg: 1601 min/max: 1200/3000 cores: 1: 1280 2: 1595 3: 1416 + ... 32: 1634\fR +.fi .TP -.B \-d\fR,\fB \-\-disk\-full\fR,\fB\-\-optical\fR +.B \-d \fR, \fB\-\-disk\-full\fR,\fB\-\-optical\fR Show optical drive data as well as \fB\-D\fR hard drive data. With \fB\-x\fR, adds a feature line to the output. Also shows floppy disks if present. Note that there is no current way to get any information about the floppy device @@ -205,7 +200,7 @@ that we are aware of, so it will simply show the floppy ID without any extra data. \fB\-xx\fR adds a few more features. .TP -.B \-D\fR,\fB \-\-disk\fR +.B \-D \fR, \fB\-\-disk\fR Show Hard Disk info. Shows total disk space and used percentage. The disk used percentage includes space used by swap partition(s), since those are not usable for data storage. Also, unmounted partitions are not counted in disk use @@ -237,7 +232,7 @@ address per device (requires \fBbt\-adapter\fR or \fBhciconfig\fR), and if available (hciconfig only) bluetooth version (\fBbt\-v\fR). See \fBExtra Data Options\fR for more. -If bluetooth shows as \fBstatus: down\fR, shows \fBbt-service:\fR\fB state +If bluetooth shows as \fBstatus: down\fR, shows \fBbt\-service:\fR\fB state and rfkill\fR software and hardware blocked states, and rfkill ID. Note that \fBReport\-ID:\fR indicates that the HCI item was not able to be @@ -259,27 +254,17 @@ or \fBrfkill unblock bluetooth\fR .TP -.B \-\-filter\fR,\fB \-\-filter\-override\fR \- See \fB\-z\fR, \fB\-Z\fR. +.B \-\-filter\fR, \fB\-z\fR +.br +See \fBFILTER OPTIONS\fR. .TP -.B \-\-filter\-label\fR -Filter partition label names from \fB\-j\fR, \fB\-o\fR, \fB\-p\fR, -\fB\-P\fR, and \fB\-Sa\fR (root=LABEL=...). Generally only useful in -very specialized cases. - -.TP -.B \-\-filter\-uuid\fR -Filter partition UUIDs from \fB\-j\fR, \fB\-o\fR, \fB\-p\fR, -\fB\-P\fR, and \fB\-Sa\fR (root=UUID=...). Generally only useful in -very specialized cases. - -.TP -.B \-f\fR,\fB \-\-flags\fR +.B \-f \fR, \fB\-\-flags\fR Show all CPU flags used, not just the short list. Not shown with \fB\-F\fR in order to avoid spamming. ARM CPUs: show \fBfeatures\fR items. .TP -.B \-F\fR,\fB \-\-full\fR +.B \-F \fR, \fB\-\-full\fR Show Full output for inxi. Includes all Upper Case line letters (except \fB\-J\fR and \fB\-W\fR) plus \fB\-\-swap\fR, \fB\-s\fR and \fB\-n\fR. Does not show extra verbose options such as \fB\-d \-f \-i -J \-l \-m \-o \-p \-r @@ -287,7 +272,7 @@ not show extra verbose options such as \fB\-d \-f \-i -J \-l \-m \-o \-p \-r \fBinxi \-Frmxx\fR .TP -.B \-G\fR,\fB \-\-graphics\fR +.B \-G \fR, \fB\-\-graphics\fR Show Graphic device(s) information, including details of device and display drivers (\fBloaded:\fR, and, if applicable: \fBunloaded:\fR, \fBfailed:\fR), display protocol (if available), display server (and/or Wayland compositor), @@ -306,21 +291,21 @@ Compositor information will show if detected using \fB\-xx\fR option or always if detected and Wayland. .TP -.B \-h\fR,\fB \-\-help\fR +.B \-h \fR, \fB\-\-help\fR The help menu. Features dynamic sizing to fit into terminal window. Set script global \fBCOLS_MAX_CONSOLE\fR if you want a different default value, or use \fB\-y \fR to temporarily override the defaults or actual window width. .TP -.B \-i\fR,\fB \-\-ip\fR +.B \-i \fR, \fB\-\-ip\fR Show WAN IP address and local interfaces (latter requires \fBifconfig\fR or \fBip\fR network tool), as well as network output from \fB\-n\fR. Not shown with \fB\-F\fR for user security reasons. You shouldn't paste your local/WAN IP. Shows both IPv4 and IPv6 link IP addresses. .TP -.B \-I\fR,\fB \-\-info\fR +.B \-I \fR, \fB\-\-info\fR Show Information: processes, uptime, memory, IRC client (or shell type if run in shell, not IRC), inxi version. See \fB\-Ix\fR, \fB\-Ixx\fR, and \fB\-Ia\fR for extra information (init type/version, runlevel, packages). @@ -341,7 +326,7 @@ To show partition labels or UUIDs (when available and relevant), use with \fB\-l\fR or\fB \-u\fR. .TP -.B \-J\fR,\fB \-\-usb\fR +.B \-J \fR, \fB\-\-usb\fR Show USB data for attached Hubs and Devices. Hubs also show number of ports. Be aware that a port is not always external, some may be internal, and either used or unused (for example, a motherboard USB header connector that is not @@ -362,7 +347,7 @@ The \fBrev: 2.0\fR item refers to the USB revision number, like \fB1.0\fR or \fB3.1\fR. .TP -.B \-l\fR,\fB \-\-label\fR +.B \-l \fR, \fB\-\-label\fR Show partition labels. Use with \fB\-j\fR, \fB\-o\fR, \fB\-p\fR, and \fB\-P\fR to show partition labels. Does nothing without one of those options. @@ -375,7 +360,7 @@ size, free space (for LVM VG). For LVM, shows \fBDevice\-[xx]: VG:\fR (Volume Group) size/free, \fBLV\-[xx]\fR (Logical Volume). LV shows type, size, and components. Note that components are made up of either containers (aka, logical devices), or physical devices. The full report requires -doas[BSDs]/sudo/root. +doas/sudo/root. Logical block devices can be thought of as devices that are made up out of either other logical devices, or physical devices. inxi does its best @@ -398,14 +383,13 @@ component belongs to which. Sample: -\fBDevice\-10: mybackup type: LUKS dm: dm\-28 size: 6.36 GiB Components: -c\-1: md1 cc\-1: dm\-26 ppp\-1: sdj2 cc\-2: dm\-27 ppp\-1: sdk2\fR - .nf -\fBLV\-5: lvm_raid1 type: raid1 dm: dm\-16 size: 4.88 GiB -RAID: stripes: 2 sync: idle copied: 100% mismatches: 0 -Components: c\-1: dm\-10 pp\-1: sdd1 c\-2: dm\-11 pp\-1: sdd1 c\-3: dm\-13 -pp\-1: sde1 c\-4: dm\-15 pp\-1: sde1\fR +\fB Device\-10: mybackup type: LUKS dm: dm\-28 size: 6.36 GiB Components: + c\-1: md1 cc\-1: dm\-26 ppp\-1: sdj2 cc\-2: dm\-27 ppp\-1: sdk2\fR + \fBLV\-5: lvm_raid1 type: raid1 dm: dm\-16 size: 4.88 GiB + RAID: stripes: 2 sync: idle copied: 100% mismatches: 0 + Components: c\-1: dm\-10 pp\-1: sdd1 c\-2: dm\-11 pp\-1: sdd1 c\-3: dm\-13 + pp\-1: sde1 c\-4: dm\-15 pp\-1: sde1\fR .fi It is easier to follow the flow of components and devices using \fB\-y1\fR. In @@ -444,7 +428,7 @@ Other types of logical block handling like LUKS, bcache show as: \fBDevice\-[xx] [name/id] type: [LUKS|Crypto|bcache]:\fR .TP -.B \-m\fR,\fB \-\-memory\fR +.B \-m \fR, \fB\-\-memory\fR Memory (RAM) data. Does not display with \fB\-b\fR or \fB\-F\fR unless you use \fB\-m\fR explicitly. Ordered by system board physical system memory array(s) (\fBArray\-[number]\fR), and individual memory devices @@ -453,11 +437,11 @@ number of devices supported, and Error Correction information. Devices shows locator data (highly variable in syntax), size, speed, type (eg: \fBtype: DDR3\fR). -Note: \fB\-m\fR uses \fBdmidecode\fR, which must be run as root (or start -\fBinxi\fR with \fBsudo\fR), unless you figure out how to set up -doas[BSDs]/sudo to permit dmidecode to read \fB/dev/mem\fR as user. -\fBspeed\fR and \fBbus\-width\fR will not show if \fBNo Module Installed\fR -is found in \fBsize\fR. +Note: \fB\-m\fR uses \fBdmidecode\fR, which must be run as root (or start +\fBinxi\fR with \fBdoas/sudo\fR), unless you figure out how to set up doas/sudo +to permit dmidecode to read \fB/dev/mem\fR as user. \fBspeed\fR and +\fBbus\-width\fR will not show if \fBNo Module Installed\fR is found in +\fBsize\fR. Note: If \fB\-m\fR is triggered RAM total/used report will appear in this section, not in \fB\-I\fR or \fB\-tm\fR items. @@ -491,10 +475,10 @@ If the detected speed is logically absurd, like 1 MT/s or 69910 MT/s, adds: Array\-1: capacity: N/A slots: 4 note: check EC: N/A Device\-1: DIMM_A1 size: 8 GiB speed: 1600 MT/s (800 MHz) Device\-2: DIMM_A2 size: 8 GiB speed: spec: 1600 MT/s (800 MHz) - actual: 61910 MT/s (30955 MHz) note: check + actual: 61910 MT/s (30955 MHz) note: check Device\-3: DIMM_B1 size: 8 GiB speed: 1600 MT/s (800 MHz) Device\-4: DIMM_B2 size: 8 GiB speed: spec: 1600 MT/s (800 MHz) - actual: 2 MT/s (1 MHz) note: check\fR + actual: 2 MT/s (1 MHz) note: check\fR .fi See \fB\-\-memory\-modules\fR and \fB\-\-memory\-short\fR if you want a @@ -512,7 +496,7 @@ Memory (RAM) data. Show a one line RAM report in Memory. See \fB\-m\fR. Sample: \fBReport: arrays: 1 slots: 4 modules: 2 type: DDR4\fR .TP -.B \-M\fR,\fB \-\-machine\fR +.B \-M \fR, \fB\-\-machine\fR Show machine data. Device, Motherboard, BIOS, and if present, System Builder (Like Lenovo). Older systems/kernels without the required \fB/sys\fR data can use \fBdmidecode\fR instead, run as root. If using \fBdmidecode\fR, may also @@ -534,17 +518,17 @@ notebook, server, blade, plus some obscure stuff that inxi is unlikely to ever run on. .TP -.B \-n\fR,\fB \-\-network\-advanced\fR +.B \-n \fR, \fB\-\-network\-advanced\fR Show Advanced Network device information in addition to that produced by \fB\-N\fR. Shows interface, speed, MAC ID, state, etc. .TP -.B \-N\fR,\fB \-\-network\fR +.B \-N \fR, \fB\-\-network\fR Show Network device(s) information, including device driver. With \fB\-x\fR, shows Bus ID, Port number. .TP -.B \-o\fR,\fB \-\-unmounted\fR +.B \-o \fR, \fB\-\-unmounted\fR Show unmounted partition information (includes UUID and LABEL if available). Shows file system type if you have \fBlsblk\fR installed (Linux only). For BSD/GNU Linux: shows file system type if \fBfile\fR is installed, and if you @@ -552,7 +536,7 @@ are root or if you have added to \fB/etc/sudoers\fR (sudo v. 1.7 or newer): .B ALL = NOPASSWD: /usr/bin/file (sample) -BSD users: see \fBman doas.conf\fR for setup. +doas users: see \fBman doas.conf\fR for setup. Does not show components (partitions that create the md\-raid array) of md\-raid arrays. @@ -561,7 +545,7 @@ To show partition labels or UUIDs (when available and relevant), use with \fB\-l\fR or\fB \-u\fR. .TP -.B \-p\fR,\fB \-\-partitions\-full\fR +.B \-p \fR, \fB\-\-partitions\-full\fR Show full Partition information (\fB\-P\fR plus all other detected mounted partitions). @@ -569,7 +553,7 @@ To show partition labels or UUIDs (when available and relevant), use with \fB\-l\fR or\fB \-u\fR. .TP -.B \-P\fR,\fB \-\-partitions\fR +.B \-P \fR, \fB\-\-partitions\fR Show basic Partition information. Shows, if detected: \fB/ /boot /boot/efi /home /opt /tmp /usr /usr/home /var /var/tmp /var/log\fR (for android, shows \fB/cache /data /firmware /system\fR). @@ -580,10 +564,12 @@ To show partition labels or UUIDs (when available and relevant), use with \fB\-l\fR or\fB \-u\fR. .TP -.B \-\-processes\fR \- See \fB\-t\fR +.B \-\-processes\fR +.br +See \fB\-t\fR. .TP -.B \-r\fR,\fB \-\-repos\fR +.B \-r \fR, \fB\-\-repos\fR Show distro repository data. Currently supported repo types: \fBAPK\fR (Alpine Linux + derived versions) @@ -628,7 +614,7 @@ See \fB\-rx\fR, \fB\-rxx\fR, and \fB\-ra\fR for installed package count information. .TP -.B \-R\fR,\fB \-\-raid\fR +.B \-R \fR, \fB\-\-raid\fR Show RAID data. Shows RAID devices, states, levels, device/array size, and components. See extra data with \fB\-x\fR / \fB\-xx\fR. @@ -652,7 +638,7 @@ Checks inxi application dependencies and recommends, as well as directories, then shows what package(s) you need to install to add support for each feature. .TP -.B \-s\fR,\fB \-\-sensors\fR +.B \-s \fR, \fB\-\-sensors\fR Show output from sensors if sensors installed/configured: Motherboard/CPU/GPU temperatures; detected fan speeds. GPU temperature when available. Nvidia shows screen number for multiple screens. IPMI sensors are also used (root required) @@ -665,17 +651,19 @@ exclude one. Show PCI slots with type, speed, and status information. .TP -.B \-\-swap\fR \- See \fB\-j\fR +.B \-\-swap\fR +.br +See \fB\-j\fR .TP -.B \-S\fR,\fB \-\-system\fR +.B \-S \fR, \fB\-\-system\fR Show System information: host name, kernel, desktop environment (if in X), distro. With \fB\-xx\fR show dm \- or startx \- (only shows if present and running if out of X), and if in X, with \fB\-xxx\fR show more desktop info, e.g. taskbar or panel. .TP -.B \-t\fR,\fB \-\-processes\fR +.B \-t \fR, \fB\-\-processes\fR [\fBc\fR|\fBm\fR|\fBcm\fR|\fBmc NUMBER\fR] Show processes. If no arguments, defaults to \fBcm\fR. If followed by a number, shows that number of processes for each type (default: \fB5\fR; if in IRC, max: \fB5\fR) @@ -699,14 +687,14 @@ system RAM used/total information. same line. .TP -.B \-u\fR,\fB \-\-uuid\fR +.B \-u \fR, \fB\-\-uuid\fR Show partition UUIDs. Use with \fB\-j\fR, \fB\-o\fR, \fB\-p\fR, and \fB\-P\fR to show partition labels. Does nothing without one of those options. Sample: \fB\-opju\fR. .TP -.B \-U\fR,\fB \-\-update\fR +.B \-U \fR, \fB\-\-update\fR Note \- Maintainer may have disabled this function. If inxi \fB\-h\fR has no listing for \fB\-U\fR then it's disabled. @@ -720,14 +708,16 @@ to that directory. See \fB\-\-man\fR or \fB\-\-no\-man\fR to force or disable man install. .TP -.B \-\-usb\fR \- See \fB\-J\fR +.B \-\-usb\fR +.br +See \fB\-J\fR. .TP .B \-V\fR, \fB\-\-version\fR inxi version information. Prints information then exits. .TP -.B \-v\fR,\fB \-\-verbosity\fR +.B \-v \fR, \fB\-\-verbosity\fR Script verbosity levels. If no verbosity level number is given, 0 is assumed. Should not be used with \fB\-b\fR or \fB\-F\fR. @@ -739,8 +729,8 @@ Supported levels: \fB0\-8\fR Examples :\fB inxi \-v 4 \fR or \fB inxi \-v4\fR .TP .B \-v 1 -\- Basic verbose, \fB\-S\fR + basic CPU (cores, type, clock speed, and min/max -speeds, if available) + \fB\-G\fR + basic Disk + \fB\-I\fR. +\- Basic verbose, \fB\-S\fR + basic CPU (cores, type, average clock speed, and +min/max speeds, if available) + \fB\-G\fR + basic Disk + \fB\-I\fR. .TP .B \-v 2 @@ -754,22 +744,21 @@ speeds, if available) + \fB\-G\fR + basic Disk + \fB\-I\fR. .TP .B \-v 4 -\- Adds partition size/used data (\fB\-P\fR) for (if present): -\fB/ /home /var/ /boot\fR. Shows full disk data (\fB\-D\fR) +\- Adds partition size/used data (\fB\-P\fR) for (if present): \fB/ /home /var/ +/boot\fR. Shows full disk data (\fB\-D\fR) .TP .B \-v 5 -\- Adds audio device (\fB\-A\fR), memory/RAM (\fB\-m\fR), -bluetooth data (\fB\-E\fR) (if present), sensors (\fB\-s\fR), -RAID data (if present), partition label (\fB\-l\fR), -UUID (\fB\-u\fR), full swap data (\fB\-j\fR), and short form of -optical drives. +\- Adds audio device (\fB\-A\fR), memory/RAM (\fB\-m\fR), bluetooth data +(\fB\-E\fR) (if present), sensors (\fB\-s\fR), RAID data (if present), partition +label (\fB\-l\fR), UUID (\fB\-u\fR), full swap data (\fB\-j\fR), and short form +of optical drives. .TP .B \-v 6 -\- Adds full mounted partition data (\fB\-p\fR), -unmounted partition data (\fB\-o\fR), optical drive data (\fB\-d\fR), -USB (\fB\-J\fR); triggers \fB\-xx\fR extra data option. +\- Adds full mounted partition data (\fB\-p\fR), unmounted partition data +(\fB\-o\fR), optical drive data (\fB\-d\fR), USB (\fB\-J\fR); triggers +\fB\-xx\fR extra data option. .TP .B \-v 7 @@ -779,16 +768,15 @@ USB (\fB\-J\fR); triggers \fB\-xx\fR extra data option. .TP .B \-v 8 -\- All system data available. Adds Repos (\fB\-r\fR), -PCI slots (\fB\-\-slots\fR), processes (\fB\-tcm\fR), admin (\fB\-\-admin\fR). -Useful for testing output and to see what data you can get from your system. +\- All system data available. Adds Repos (\fB\-r\fR), PCI slots +(\fB\-\-slots\fR), processes (\fB\-tcm\fR), admin (\fB\-\-admin\fR). Useful for +testing output and to see what data you can get from your system. .TP -.B \-w\fR,\fB \-\-weather\fR -Adds weather line. To get weather for an alternate location, use -\fB\-W [location]\fR. See also \fB\-x\fR, \fB\-xx\fR, \fB\-xxx\fR options. -Please note that your distribution's maintainer may chose to disable this -feature. +.B \-w \fR, \fB\-\-weather\fR +Adds weather line. To get weather for an alternate location, use \fB\-W +[location]\fR. See also \fB\-x\fR, \fB\-xx\fR, \fB\-xxx\fR options. Please note +that your distribution's maintainer may chose to disable this feature. DO NOT USE THIS FEATURE FOR AUTOMATED WEATHER UPDATES! Automated or excessive use will lead to your being blocked from any further access. This feature is not @@ -841,30 +829,239 @@ source message, it means that number has not been implemented. imperial (\fBi\fR), metric (imperial) (\fBmi\fR, default), imperial (metric) (\fBim\fR). If metric or imperial not found,sets to default value, or \fBN/A\fR. -.TP -.B \-y\fR,\fB \-\-width [integer]\fR -This is an absolute width override which sets the output line width max. -Overrides \fBCOLS_MAX_IRC\fR / \fBCOLS_MAX_CONSOLE\fR globals, or the -actual widths of the terminal. \fB80\fR is the minimum width supported. -\fB\-1\fR removes width limits. 1 switches to a single indented key/value -pair per line, and removes all long line wrapping (similar to -\fBdmidecode\fR output). - -If no integer value is given, sets width to default of 80. - -Examples: \fBinxi \-Fxx\ \-y 130\fR or \fBinxi \-Fxxy\fR or \fBinxi \-bay1\fR +.SH FILTER OPTIONS +The following options allow for applying various types of filtering to the +output. .TP -.B \-z\fR,\fB \-\-filter\fR -Adds security filters for IP addresses, serial numbers, MAC, -location (\fB\-w\fR), and user home directory name. Removes Host:. -On by default for IRC clients. +.B \-\-filter \fR, \fB\-\-filter\-override\fR +.br +See \fB\-z\fR, \fB\-Z\fR. .TP -.B \-Z\fR,\fB \-\-filter\-override\fR,\fB \-\-no\-filter\fR +.B \-\-filter\-label\fR, \fB\-\-filter\-uuid\fR, \fB\-\-filter\-vulnerabilities\fR +.br +See \fB\-\-zl\fR, \fB\-\-zu\fR, \fB\-\-zv\fR. + +.TP +.B \-\-host\fR +Turns on hostname in System line. Overrides inxi config file value (if set): + +\fBSHOW_HOST='false'\fR \- Same as: \fBSHOW_HOST='true'\fR + +This is an absolute override, the host will always show no matter what +other switches you use. + +.TP +.B \-\-no\-host\fR +Turns off hostname in System line. This is default when using \fB\-z\fR, +for anonymizing inxi output for posting on forums or IRC. Overrides +configuration value (if set): + +\fBSHOW_HOST='true'\fR \- Same as: \fBSHOW_HOST='false'\fR + +This is an absolute override, the host will not show no matter what other +switches you use. + +.TP +.B \-z\fR, \fB\-\-filter\fR +Adds security filters for IP addresses, serial numbers, MAC, location +(\fB\-w\fR), and user home directory name. Removes Host:. On by default for IRC +clients. + +.TP +.B \-\-zl\fR, \fB\-\-filter\-label\fR +Filter partition label names from \fB\-j\fR, \fB\-o\fR, \fB\-p\fR, \fB\-P\fR, +and \fB\-Sa\fR (root=LABEL=...). Generally only useful in very specialized +cases. + +.TP +.B \-\-zu\fR, \fB\-\-filter\-uuid\fR +Filter partition UUIDs from \fB\-j\fR, \fB\-o\fR, \fB\-p\fR, \fB\-P\fR, and +\fB\-Sa\fR (root=UUID=...). Generally only useful in very specialized cases. + +.TP +.B \-\-zv\fR, \fB\-\-filter\-v\fR, \fB\-\-filter\-vulnerabilities\fR +Filter Vulnerabilities report from \fB\-Ca\fR. Generally only useful in very +specialized cases. + +.TP +.B \-Z \fR, \fB\-\-filter\-override \fR, \fB\-\-no\-filter\fR Absolute override for output filters. Useful for debugging networking issues in IRC for example. +.SH OUTPUT CONTROL OPTIONS +The following options allow for modifying the output in various ways. + +.TP +.B \-c \fR, \fB\-\-color\fR \fR[\fB0\fR\-\fB42\fR] +Set color scheme. If no scheme number is supplied, 0 is assumed. + +.TP +.B \-c \fR[\fB94\fR\-\fB99\fR] +These color selectors run a color selector option prior to inxi starting +which lets you set the config file value for the selection. + +NOTE: All configuration file set color values are removed when output is +piped or redirected. You must use the explicit runtime \fB\-c \fR +option if you want color codes to be present in the piped/redirected output. + +Color selectors for each type display (NOTE: IRC and global only show safe +color set): + +.TP +.B \-c 94\fR +\- Console, out of X. + +.TP +.B \-c 95\fR +\- Terminal, running in X \- like xTerm. + +.TP +.B \-c 96\fR +\- GUI IRC, running in X \- like XChat, Quassel, +Konversation etc. + +.TP +.B \-c 97\fR +\- Console IRC running in X \- like irssi in xTerm. + +.TP +.B \-c 98\fR +\- Console IRC not in X. + +.TP +.B \-c 99\fR +\- Global \- Overrides/removes all settings. + +Setting a specific color type removes the global color selection. + + +.TP +.B \-\-indent [11\-xx]\fR +Change primary wide indent width. Generally useless. Only applied if output +width is greater than max wrap width (see \fB\-\-max\-wrap\fR). Use +configuration item \fBINDENT\fR to make permanent. + +.TP +.B \-\-indents [0\-10]\fR +Change primary wrap mode, second, and -y1 level indents. First indent level only +applied if output width is less than max wrap width (see \fB\-\-max\-wrap\fR). 0 +disables all wrapped indents and all second level indents. Use configuration +item \fBINDENTS\fR to make permanent. + +.TP +.B \-\-limit [\-1 \- x]\fR +Raise or lower max output limit of IP addresses for \fB\-i\fR. \fB\-1\fR +removes limit. + +.TP +.B \-\-max\-wrap\fR, \fB\-\-wrap\-max [integer]\fR +Overrides default or configuration set line starter wrap width value. Wrap max +is the maximum width that inxi will wrap line starters (e.g. \fBInfo:\fR) to +their own lines, with data lines indented default 2 columns (use +\fB\-\-indents\fR to change). + +If terminal/console width or \fB\-\-width\fR is less than wrap width, wrapping +of line starter occurs. If \fB80\fR or less, no wrapping will occur. Overrides +internal default value (110) and user configuration value \fBMAX_WRAP\fR. + +.TP +.B \-\-output [json|screen|xml]\fR +Change data output type. Requires \-\-output\-file if not \fBscreen\fR. + +.TP +.B \-\-output\-file [full path to output file|print]\fR +The given directory path must exist. The directory path given must exist, +The \fBprint\fR options prints to stdout. +Required for non\-screen \fB\-\-output\fR formats (json|xml). + +.TP +.B \-\-partition\-sort [dev\-base|fs|id|label|percent\-used|size|uuid|used]\fR +Change default sort order of partition output. Corresponds to +\fBPARTITION_SORT\fR configuration item. These are the available sort options: + +\fBdev\-base\fR - \fB/dev\fR partition identifier, like \fB/dev/sda1\fR. +Note that it's an alphabetic sort, so \fBsda12\fR is before \fBsda2\fR. + +\fBfs\fR \- Partition filesystem. Note that sorts will be somewhat random if +all filesystems are the same. + +\fBid\fR \- Mount point of partition (default). + +\fBlabel\fR \- Label of partition. If partitions have no labels, +sort will be random. + +\fBpercent\-used\fR - Percentage of partition size used. + +\fBsize\fR \- KiB size of partition. + +\fBuuid\fR \- UUID of the partition. + +\fBused\fR \- KiB used of partition. + +.TP +.B \-\-wrap\-max [integer]\fR +.br +See \fB\-\-max-wrap\fR. + +.TP +.B \-y\fR, \fB\-\-width [integer]\fR +This is an absolute width override which sets the output line width max. +Overrides \fBCOLS_MAX_IRC\fR, \fBCOLS_MAX_NO_DISPLAY\fR, \fBCOLS_MAX_CONSOLE\fR +configuration items, or the actual widths of the terminal. + +* \fB\-y\fR \- sets default width of 80 columns. +.br +* \fB\-y [80-xxx]\fR \- sets width to given number. Must be 80 or more. +.br +* \fB\-y 1\fR \- switches to a single indented key/value pair per line, and +removes all long line wrapping (similar to \fBdmidecode\fR output). Not +recommended for use with \fB\-Y\fR; +.br +* \fB\-y \-1\fR \- removes width limits (if assigned by configuration items). + +Examples: +.br +\fBinxi \-Fxx \-y 130\fR +.br +\fBinxi \-Fxxy\fR +.br +\fBinxi \-bay1\fR + +.TP +.B \-Y\fR, \fB\-\-height\fR, \fB\-\-less [\-3\-[integer]\fR +Control output height. Useful when in console, and scrollback not available. +Breaks output flow based on values provided. + +* \fB\-Y 0\fR or \fB\-Y\fR \- Set default max height to terminal height. +.br +* \fB\-Y [1\-xxx]\fR \- set max output block height height in lines. +.br +* \fB\-Y \-1\fR \- Print out one primary data item block (like \fBCPU:\fR, +\fBSystem:\fR) at a time. Useful for very long outputs like \fB\-Fa\fR, +\fB\-v8\fR, etc. Not available for \fB\-h\fR. +.br +* \fB\-Y \-2\fR \- Do not disable output colors when redirected or piped to +another program. Useful if piping output to \fBless \-R\fR for example. This +does not limit the height otherwise since the expectation it is being piped to +another program like \fBless\fR which will handle that. +.br +* \fB\-Y \-3\fR \- Restore default unlimited output lines if \fBLINES_MAX\fR +configuration item set. + +Recommended to use the following for very clean up and down scrollable output +out of display, while retaining the color schemes, which are normally removed +with piping or redirect: + +\fBpinxi \-v8Y \-2 | less \-R\fR + +Note: since it's not possible for inxi to know how many actual terminal lines +are being used by terminal wrapped output, with \fB\-y 1\fR , it may be better +in general to use a fixed height like: + +\fB\-y 1 \-Y 20\fR instead of: \fB\-y 1 \-Y\fR + .SH EXTRA DATA OPTIONS These options can be triggered by one or more \fB\-x\fR. Alternatively, the \fB\-v\fR options trigger them in the following @@ -876,11 +1073,11 @@ data on various options. They can be added to any long form option list, e.g.: \fB\-bxx\fR or \fB\-Sxxx\fR There are 3 extra data levels: - +.br \fB\-x\fR, \fB\-xx\fR, \fB\-xxx\fR - +.br OR - +.br \fB\-\-extra 1\fR, \fB\-\-extra 2\fR, \fB\-\-extra 3\fR The following details show which lines / items display extra information for @@ -910,23 +1107,38 @@ without \fB\-x\fR. .TP .B \-x \-C\fR -\- Adds bogomips on CPU (if available) +\- Adds bogomips to CPU speed report (if available). + +\- Adds \fBL1:\fR and \fBL3:\fR cache types if either are present/available. For +BSD or legacy Linux, uses dmidecode + doas/sudo/root. Force use of dmidecode +cache values by adding \fB\-\-dmidecode\fR. This will override /sys based cache +data, which tends to be better, so in general don't do that. \- Adds \fBboost: [enabled|disabled]\fR if detected, aka \fBturbo\fR. Not all CPUs have this feature. \- Adds CPU Flags (short list). Use \fB\-f\fR to see full flag/feature list. -\- Adds CPU microarchitecture + revision (e.g. Sandy Bridge, K8, ARMv8, P6, -etc.). Only shows data if detected. Newer microarchitectures will have -to be added as they appear, and require the CPU family ID, model ID, -and stepping. +\- Adds CPU microarchitecture + revision (e.g. Sandy Bridge, K8, ARMv8, P6, +etc.). Only shows data if detected. Newer microarchitectures will have to be +added as they appear, and require the CPU family ID, model ID, and stepping. -Examples: \fBarch: Sandy Bridge rev: 2\fR, \fBarch: K8 rev.F+ rev: 2\fR +\- Adds, if smt (Simultaneous MultiThreading) is available but disabled, after +\fBtype:\fR data \fBsmt: disabled\fR. \fBtype: MT\fR means it's enabled. See +\fB\-Cxxx\fR. + +Examples: +.br +\fBarch: Sandy Bridge rev: 2\fR +.br +\fBarch: K8 rev.F+ rev: 2\fR If unable to non\-ambiguosly determine architecture, will show something like: \fBarch: Amber Lake note: check rev: 9\fR +\- Adds CPU highest speed after \fBavg: [speed] high: [speed]\fR if greater than +1 core and cores have different speeds. Linux only. + .TP .B \-x \-d\fR \- Adds more items to \fBFeatures\fR line of optical drive; @@ -949,18 +1161,18 @@ If your \fBdrivetemp\fR module is not enabled, enable it: Once enabled, add \fBdrivetemp\fR to \fB/etc/modules\fR or \fB/etc/modules\-load.d/***.conf\fR so it starts automatically. -If you see drive temps running as regular user and you did not configure -system to use doas[BSDs]/sudo hddtemp, then your system supports this feature. -If no /sys data is found, inxi will try to use hddtemp methods instead for -that drive. Hint: if temp is /sys sourced, the temp will be to 1 decimal, -like 34.8, if hddtemp sourced, they will be integers. +If you see drive temps running as regular user and you did not configure system +to use doas/sudo hddtemp, then your system supports this feature. If no /sys +data is found, inxi will try to use hddtemp methods instead for that drive. +Hint: if temp is /sys sourced, the temp will be to 1 decimal, like 34.8, if +hddtemp sourced, they will be integers. Method 2: if you have hddtemp installed, if you are root or if you have added to \fB/etc/sudoers\fR (sudo v. 1.7 or newer): .B ALL = NOPASSWD: /usr/sbin/hddtemp (sample) -BSD users: see \fBman doas.conf\fR for setup. +doas users: see \fBman doas.conf\fR for setup. You can force use of \fBhddtemp\fR for all drives using \fB\-\-hddtemp\fR. @@ -1108,7 +1320,7 @@ found for each distribution system base detection. (\fB\-xt m\fR). .TP -.B \-x \-w\fR,\fB \-W\fR +.B \-x \-w \fR, \fB\-W\fR \- Adds humidity and barometric pressure. \- Adds wind speed and direction. @@ -1121,12 +1333,6 @@ found for each distribution system base detection. .B \-xx \-B\fR \- Adds serial number. -.TP -.B \-xx \-C\fR -\- Adds \fBL1\-cache:\fR and \fBL3\-cache:\fR if either are present/available. -For Linux, uses \fBgetconf \-a\fR (if supported), otherwise uses dmidecode + -doas[BSDs]/sudo/root. Force use of dmidecode by adding \fB\-\-dmidecode\fR. - .TP .B \-xx \-D\fR \- Adds disk serial number. @@ -1272,7 +1478,7 @@ running. If none found, shows nothing. Uses a less accurate fallback tool \- Adds slot length. .TP -.B \-xx \-w\fR,\fB \-W\fR +.B \-xx \-w \fR, \fB\-W\fR \- Adds wind chill, heat index, and dew point, if available. \- Adds cloud cover, rain, snow, or precipitation (amount in previous hour @@ -1297,7 +1503,16 @@ data is simply not available as of 2018\-04\-03), location (only available from .TP .B \-xxx \-C\fR \- Adds CPU voltage and external clock speed (this is the motherboard speed). -Requires doas[BSDs]/sudo/root and \fBdmidecode\fR. +Requires doas/sudo/root and \fBdmidecode\fR. + +\- Adds, if smt (Simultaneous MultiThreading) data is available, after +\fBtype:\fR data \fBsmt: [status]\fR. +.br +\fBsmt: [status]\fR +.br +\fBMT\fR in \fBtype:\fR will show if smt is enabled in general. 3 values are +possible: [\fBenabled|disabled|\fR]. \fB\fR means the +CPU does not support SMT. .TP .B \-xxx \-D\fR @@ -1396,7 +1611,7 @@ These are the same as \fBctrl+alt+F[x]\fR numbers usually. Some systems have this, some don't, it varies. .TP -.B \-xxx \-w\fR,\fB \-W\fR +.B \-xxx \-w \fR, \fB\-W\fR \- Adds location (city state country), observation altitude (if available), weather observation time (if available), sunset/sunrise (if available). @@ -1421,34 +1636,51 @@ knows could possibly be used instead. \- Adds CPU family, model\-id, and stepping (replaces \fBrev\fR of \fB\-Cx\fR). Format is \fBhexadecimal (decimal)\fR if greater than 9, otherwise \fBhexadecimal\fR. + \- Adds CPU microcode. Format is \fBhexadecimal\fR. \- Adds socket type (for motherboard CPU socket, if available). If results doubtful will list two socket types and \fBnote: check\fR. Requires -doas[BSDs]/sudo/root and \fBdmidecode\fR. The item in parentheses may simply -be a different syntax for the same socket, but in general, check this before -trusting it. -.nf -Sample: \fBsocket: 775 (478) note: check\fR -Sample: \fBsocket: AM4\fR -.fi +doas/sudo/root and \fBdmidecode\fR. The item in parentheses may simply be a +different syntax for the same socket, but in general, check this before trusting +it. -\- Adds DMI CPU base and boost/turbo speeds. Requires doas[BSDs]/sudo/root and +Sample: \fBsocket: 775 (478) note: check\fR +.br +Sample: \fBsocket: AM4\fR + +\- Adds DMI CPU base and boost/turbo speeds. Requires doas/sudo/root and \fBdmidecode\fR. In some cases, like with overclocking or 'turbo' or 'boost' modes, voltage and external clock speeds may be increased, or short term limits -raised on max CPU speeds. These are often not reflected in /sys based -CPU \fBmin/max:\fR speed results, but often are using this source. +raised on max CPU speeds. These are often not reflected in /sys based CPU +\fBmin/max:\fR speed results, but often are using this source. Samples: -.nf +.br CPU not overclocked, with boost, like Ryzen: -\fBSpeed: 2861 MHz min/max: 1550/3400 MHz boost: enabled base/boost: 3400/3900\fR - +.nf +\fBSpeed (MHz): + avg: 2861 + high: 3250 + min/max: 1550/3400 + boost: enabled + base/boost: 3400/3900\fR +.fi Overclocked 2900 MHz CPU, with no boost available: -\fBSpeed: 2900 MHz min/max: 800/2900 MHz base/boost: 3350/3000\fR - +.nf +\fBSpeed (MHz): + avg: 2345 + high: 2900 + min/max: 800/2900 + base/boost: 3350/3000\fR +.fi Overclocked 3000 MHz CPU, with boosted max speed: -\fBSpeed: 4190 MHz min/max: 1200/3001 MHz base/boost: 3000/4000\fR +.nf +\fBSpeed (MHz): + avg: 3260 + high: 4190 + min/max: 1200/3001 + base/boost: 3000/4000\fR .fi Note that these numbers can be confusing, but basically, the \fBbase\fR @@ -1465,6 +1697,65 @@ boost/turbo mode speeds, and appear to be hard\-coded values, not dynamic real values. The \fBbase/boost:\fR values are sometimes real, and sometimes not. \fBbase\fR appears in general to be real. +\- Adds frequency \fBscaling: governor:.. driver:..\fR if found/available. + +\- Adds description of cache topology per cpu. Linux only. + +\- Creates new \fBTopology:\fR line after the \fBInfo:\fR line. Moves cache data +to this line from \fBInfo:\fR line. + +Topology line contains, if available and/or relevant: physical CPU count +(\fBcpus:\fR); per physical cpu core count (cores:\fR); threads per core, if > 1 +(\fBtpc:\fR); how many \fBthreads:\fR (if more threads than cores); \fBdies:\fR +(rarely detected, but if so, if > 1); smt status (if no smt status found, shows +\fBN/A\fR). + +If complex CPU type, like Alder lake, cores; will have a more granular breakdown +of how many mt (multi\-threaded) and how many st (single\-threaded) cores there +in the physical cpu ( \fBmt\-cores:\fR, \fBst\-cores:\fR); For complex CPU +types like ARM SoC devices with 2 CPU types, with different core counts and/or +\fBmin/max:\fR) frequencies, \fBvariant:\fR per type found, with relevant +differences shown, like \fBcores:, \fBmin/max:\fR, etc. + +.nf +\fBCPU: + Info: + model: AMD EPYC 7281 + bits: 64 + type: MT MCP MCM SMP + arch: Zen + family:0x17 (23) + model\-id:1 + stepping: 2 + microcode: 0x8001250 + Topology: + cpus: 2 + cores: 16 + tpc: 2 + threads: 32 + dies: 4 + cache: + L1: 2x 1.5 MiB (3 MiB) + desc: d\-16x32 KiB; i\-16x64 KiB + L2: 2x 8 MiB (16 MiB) + desc: 16x512 KiB + L3: 2x 32 MiB (64 MiB) + desc: 8x4 MiB + Speed (MHz): + avg: 1195 + high: 1197 + min/max: 1200/2100 + boost: enabled + scaling: + driver: acpi-cpufreq + governor: ondemand + cores: + 1: 1195 + 2: 1196 + .... + bogomips: 267823 +.fi + \- Adds CPU Vulnerabilities (bugs) as known by your current kernel. Lists by \fBType: ... (status|mitigation): ....\fR for systems that support this feature (Linux kernel 4.14 or newer, or patched older kernels). @@ -1473,7 +1764,7 @@ values. The \fBbase/boost:\fR values are sometimes real, and sometimes not. .B \-a \-d\fR,\fB\-a \-D\fR \- Adds logical and physical block size in bytes. -Using \fBsmartctl\fR (requires doas[BSDs]/sudo/root privileges). +Using \fBsmartctl\fR (requires doas/sudo/root privileges). \- Adds device model family, like \fBCaviar Black\fR, if available. @@ -1560,15 +1851,15 @@ Sample (with both \fBxdpyinfo\fR and \fBxrandr\fR data available): .nf \fBinxi \-aG Graphics: - .... -Display: x11 server: X.Org 1.20.6 driver: loaded: modesetting -display ID: :0.0 screens: 1 -Screen\-1: 0 s\-res: 2560x1024 s\-dpi: 96 s\-size: 677x271mm (26.7x10.7") -s\-diag: 729mm (28.7") -Monitor\-1: DVI\-I\-0 res: 1280x1024 hz: 60 dpi: 96 -size: 338x270mm (13.3x10.6") diag: 433mm (17") -Monitor\-2: VGA\-0 res: 1280x1024 hz: 60 dpi: 86 -size: 376x301mm (14.8x11.9") diag: 482mm (19") + .... + Display: x11 server: X.Org 1.20.6 driver: loaded: modesetting + display ID: :0.0 screens: 1 + Screen\-1: 0 s\-res: 2560x1024 s\-dpi: 96 s\-size: 677x271mm (26.7x10.7") + s\-diag: 729mm (28.7") + Monitor\-1: DVI\-I\-0 res: 1280x1024 hz: 60 dpi: 96 + size: 338x270mm (13.3x10.6") diag: 433mm (17") + Monitor\-2: VGA\-0 res: 1280x1024 hz: 60 dpi: 86 + size: 376x301mm (14.8x11.9") diag: 482mm (19") ....\fR .fi \- Adds, if present, possible \fBalternate:\fR kernel modules capable of @@ -1586,15 +1877,15 @@ with 0 packages listed. Moves to \fBRepos\fR if \fB\-ra\fR. .nf \fBinxi \-aI Info: - .... - Init: systemd v: 245 runlevel: 5 Compilers: gcc: 9.3.0 alt: 5/6/7/8/9 - Packages: apt: 3681 lib: 2096 rpm: 0 Shell: ksh v: A_2020.0.0 default: Bash - v: 5.0.16 running\-in: kate inxi: 3.1.04\fR + .... + Init: systemd v: 245 runlevel: 5 Compilers: gcc: 9.3.0 alt: 5/6/7/8/9 + Packages: apt: 3681 lib: 2096 rpm: 0 Shell: ksh v: A_2020.0.0 default: Bash + v: 5.0.16 running\-in: kate inxi: 3.1.04\fR .fi \- Adds service control tool, tested for in the following order: \fBsystemctl -rc-service rcctl service sv /etc/rc.d /etc/init.d\fR - useful to know which -you need when using an unfamiliar machine. +rc\-service rcctl service sv /etc/rc.d /etc/init.d\fR. Can be useful to know +which you need when using an unfamiliar machine. .TP .B \-a \-j\fR, \fB\-a \-P\fR [swap], \fB\-a \-P\fR [swap] @@ -1730,12 +2021,15 @@ Shortcut, legacy. See \fB\-\-force dmidecode\fR. Force inxi to use Curl, Fetch, Perl, or Wget for downloads. .TP -.B \-\-force [dmidecode|hddtemp|lsusb|pkg|usb-sys|vmstat|wmctrl]\fR +.B \-\-force [colors|dmidecode|hddtemp|lsusb|pkg|usb-sys|vmstat|wmctrl]\fR Various force options to allow users to override defaults. Values be given as a comma separated list: \fBinxi \-MJ --force dmidecode,lsusb\fR +\- \fBcolors\fR \- Same as \fB\-Y \-2\fR . Do not remove colors from piped or +redirected output. + \- \fBdmidecode\fR \- Force use of \fBdmidecode\fR. This will override \fB/sys\fR data in some lines, e.g. \fB\-M\fR or \fB\-B\fR. @@ -1767,26 +2061,12 @@ as data source, override default \fBps\fR source. .B \-\-hddtemp\fR Shortcut, legacy. See \fB\-\-force hddtemp\fR. -.TP -.B \-\-host\fR -Turns on hostname in System line. Overrides inxi config file value (if set): - -\fBSHOW_HOST='false'\fR \- Same as: \fBSHOW_HOST='true'\fR - -This is an absolute override, the host will always show no matter what -other switches you use. - .TP .B \-\-html\-wan\fR Temporary override of \fBNO_HTML_WAN\fR configuration item. Only use to test w/wo HTML downloaders for WAN IP. Restores default behavior for WAN IP, which is use HTML downloader if present and if dig failed. -.TP -.B \-\-limit [\-1 \- x]\fR -Raise or lower max output limit of IP addresses for \fB\-i\fR. \fB\-1\fR -removes limit. - .TP .B \-\-man\fR Updates / installs man page with \fB\-U\fR if \fBpinxi\fR or using \fB\-U 3\fR @@ -1797,6 +2077,7 @@ dev branch. (Only active if \fB\-U\fR is is not disabled by maintainers). Overrides default use of \fBdig\fR to get WAN IP address. Allows use of normal downloader tool to get IP addresses. Only use if dig is failing, since dig is much faster and more reliable in general than other methods. + .TP .B \-\-no\-doas\fR Skips the use of doas to run certain internal features (like \fBhddtemp\fR, @@ -1807,18 +2088,6 @@ emails in such cases, so if you want to disable regular user use of doas this option, or \fBNO_DOAS\fR configuration item. See \fB\-\-no\-sudo\fR if you need to disable both types. -.TP -.B \-\-no\-host\fR -Turns off hostname in System line. This is default when using \fB\-z\fR, -for anonymizing inxi output for posting on forums or IRC. Overrides -configuration value (if set): -indent\-min - -\fBSHOW_HOST='true'\fR \- Same as: \fBSHOW_HOST='false'\fR - -This is an absolute override, the host will not show no matter what other -switches you use. - .TP .B \-\-no\-html-wan\fR Overrides use of HTML downloaders to get WAN IP address. Use either only dig, @@ -1853,40 +2122,6 @@ emails in such cases, so if you want to disable regular user use of sudo (which requires configuration to setup anyway for these options) just use this option, or \fBNO_SUDO\fR configuration item. -.TP -.B \-\-output [json|screen|xml]\fR -Change data output type. Requires \-\-output\-file if not \fBscreen\fR. - -.TP -.B \-\-output\-file [full path to output file|print]\fR -The given directory path must exist. The directory path given must exist, -The \fBprint\fR options prints to stdout. -Required for non\-screen \fB\-\-output\fR formats (json|xml). - -.TP -.B \-\-partition\-sort [dev\-base|fs|id|label|percent\-used|size|uuid|used]\fR -Change default sort order of partition output. Corresponds to -\fBPARTITION_SORT\fR configuration item. These are the available sort options: - -\fBdev\-base\fR - \fB/dev\fR partition identifier, like \fB/dev/sda1\fR. -Note that it's an alphabetic sort, so \fBsda12\fR is before \fBsda2\fR. - -\fBfs\fR \- Partition filesystem. Note that sorts will be somewhat random if -all filesystems are the same. - -\fBid\fR \- Mount point of partition (default). - -\fBlabel\fR \- Label of partition. If partitions have no labels, -sort will be random. - -\fBpercent\-used\fR - Percentage of partition size used. - -\fBsize\fR \- KiB size of partition. - -\fBuuid\fR \- UUID of the partition. - -\fBused\fR \- KiB used of partition. - .TP .B \-\-pkg\fR Shortcut. See \fB\-\-force pkg\fR. @@ -1995,21 +2230,7 @@ Same as configuration value (example): .B \-\-wm\fR Shortcut, legacy. See \fB\-\-force wmctl\fR. -.TP -.B \-\-wrap\-max [integer]\fR -Overrides default or configuration set line starter wrap width value. Wrap -max is the maximum width that inxi will wrap line starters (e.g. \fBInfo:\fR) -to their own lines, with data lines indented only 2 columns. If -terminal/console width or \fB\-\-width\fR is less than wrap width, wrapping -of line starter occurs. If \fB80\fR or less, no wrapping will occur. Overrides -internal default value (90) and user configuration value: - -\fBWRAP_MAX=85\fR (previously \fBINDENT_MIN\fR) - -Previously called: \fB\-\-indent\-min\fR. - .SH DEBUGGING OPTIONS - .TP .B \-\-dbg 1\fR \- Debug downloader failures. Turns off silent/quiet mode for curl, wget, and @@ -2065,7 +2286,6 @@ For alternate ftp upload locations: Example: \fBinxi \-\-ftp \fIftp.yourserver.com/incoming\fB \-\-debug 21\fR .SH DEBUGGING OPTIONS TO DEBUG DEBUGGER FAILURES - Only use the following in conjunction with \fB\-\-debug 2[012]\fR, and only use if you experienced a failure or hang, or were instructed to do so. @@ -2092,7 +2312,7 @@ Skip /sys debugging in case of a hang. .TP .B \-\-debug\-sys\fR -Force PowerPC debugger parsing of /sys as doas[BSDs]/sudo/root. +Force PowerPC debugger parsing of /sys as doas/sudo/root. .TP .B \-\-debug\-sys\-print\fR @@ -2184,13 +2404,14 @@ these up, and for a complete list of options: .B Basic Options Here's a brief overview of the basic options you are likely to want to use: -\fBCOLS_MAX_CONSOLE\fR The max display column width on terminal. -If terminal/console width or \fB\-\-width\fR is less than wrap width, -wrapping of line starter occurs +\fBCOLS_MAX_CONSOLE\fR The max display column width on terminal. If +terminal/console width or \fB\-\-width\fR is less than wrap width, wrapping of +line starter occurs + \fBCOLS_MAX_IRC\fR The max display column width on IRC clients. -\fBCOLS_MAX_NO_DISPLAY\fR The max display column width in console, out of GUI -desktop. +\fBCOLS_MAX_NO_DISPLAY\fR The max display column width in out of X / Wayland / +desktop / window manager. \fBCPU_SLEEP\fR Decimal value \fB0\fR or more. Default is usually around \fB0.35\fR seconds. Time that inxi will 'sleep' before getting CPU speed data, @@ -2203,9 +2424,25 @@ downloaders. \fBFILTER_STRING\fR Default \fB\fR. Any string you prefer to see instead for filtered values. +\fBINDENT\fR Change primary indent width of wide mode output. See +\fB\-\-indent\fR. + +\fBINDENTS\fR Change primary indents of narrow wrapped mode output, and second +level indents. See \fB\-\-indents\fR. + \fBLIMIT\fR Overrides default of \fB10\fR IP addresses per IF. This is only of interest to sys admins running servers with many IP addresses. +\fBLINES_MAX\fR Values: [\-2\-xxx]. See \fB\-Y\fR for explanation and values. +Use \fB\-Y \-3\fR to restore default unlimited output lines. Avoid using this in +general unless the machine is a headless system and you want the output to be +always controlled. + +\fBMAX_WRAP\fR (or \fBWRAP_MAX\fR) The maximum width where the line starter +wraps to its own line. If terminal/console width or \fB\-\-width\fR is less than +wrap width, wrapping of line starter occurs. Overrides default. See +\fB\-\-max\-wrap\fR. If \fB80\fR or less, wrap will never happen. + \fBNO_DIG\fR Set to \fB1\fR or \fBtrue\fR to disable WAN IP use of \fBdig\fR and force use of alternate downloaders. @@ -2256,11 +2493,6 @@ Values 4\-9 are not currently supported, but this can change at any time. \fBWEATHER_UNIT\fR Values: [\fBm\fR|\fBi\fR|\fBmi\fR|\fBim\fR]. Same as \fB\-\-weather\-unit\fR. -\fBWRAP_MAX\fR (previously \fBINDENT_MIN\fR) The maximum width where the line -starter wraps to its own line. If terminal/console width or \fB\-\-width\fR is -less than wrap width, wrapping of line starter occurs. Overrides default. -See \fB\-\-wrap\-max\fR. If \fB80\fR or less, wrap will never happen. - .TP .B Color Options It's best to use the \fB\-c [94\-99]\fR color selector tool to set the @@ -2343,10 +2575,14 @@ Jarett.Stevens \- \fBdmidecode \-M\fR patch for older systems with no .SH SPECIAL THANKS TO THE FOLLOWING -The nice people at irc.oftc.net channels #linux\-smokers\-club and #smxi, -who all really have to be considered to be co\-developers because of their -non\-stop enthusiasm and willingness to provide real\-time testing and -debugging of inxi development. +The nice people at irc.oftc.net channels #linux\-smokers\-club and #smxi, who +all really have to be considered to be co\-developers because of their non\-stop +enthusiasm and willingness to provide real\-time testing and debugging of inxi +development over the years. + +LinuxQuestions.org Slackware forum members, for major help with development and +debugging new or refactored features, particularly the redone CPU logic of +2021\-12. Siduction forum members, who have helped get some features working by providing a large number of datasets that have revealed possible variations, particularly diff --git a/inxi.changelog b/inxi.changelog index 358d6da..f4f8f5b 100644 --- a/inxi.changelog +++ b/inxi.changelog @@ -1,3 +1,436 @@ +================================================================================ +Version: 3.3.10 +Patch: 01 +Date: 2021-12-13 +-------------------------------------------------------------------------------- +RELEASE NOTES: +-------------------------------------------------------------------------------- + +Huge refactor of CPU physical/core/cache logic. That was some very old logic +with a lot of hacks and patches, but it had never been actually rewritten to +take advantage of Perl's far more powerful and robust data structures and logic. +This caused a continuous stream of error cases in subtle ways, or not so subtle, +and fixes were just changing how the errors manifested. + +Tnanks very much to linuxquestions.org Slackware forum people for massive help, +and also to linux.org forum members for ongoing help and data and debugging. + +Note Changes 5, change of default widths in display to 80 columns, and out (aka, +console, or ssh into remote system), 100. You can still use other widths if you +like something wider using the configuration options shown. Also upped max +columns wrapping line starters to own rows to 110 columns from 90, again the +idea being to make output more readable to other users when posted in public. + +I've been thinking of this change for a long time, but was hoping -y would +register with users, but it hasn't gained enough traction, so the result is way +too many super hard to read issue reports, forum posts, linux kernel issues, +etc, it's honestly gotten sort of embarrassing because they make it look like +inxi has bad output. Sidescrolling code blocks in forums in particular are +absurdly hard to read and scan rapidly for data. + +Going along with the width and indentation changes, for most main row types, if +they wrap to a second row, they are further indented 2 column2, to make it +easier to see what they belong to. The two levels of indentation contain more +useful visual cues as to what belongs to what. + +There was a temptation to release this as either 3.4.00 or 4.0.00 but in the +end, I decided to follow the numbering rules, and to just roll it to 3.3.10 +since there aren't really any primary new features even though CPU was basically +rewritten in large part, and big parts of inxi were also changed, upgraded, and +enhanced. But no truly new features, just some display control items like -Y, +--indent, --indents. + +I hope this refactor meets its primary goals, and that the new defaults for +display help resolve public posting issues which have grown increasingly +annoying for anyone trying to read those pasted in too long outputs. + +-------------------------------------------------------------------------------- +KNOWN ISSUES: + +1. Android seems to have CPU cache data, but does not show any 'size' item. But +it does have the other data for each cache type internally, which is odd. + +2. In some instances, the parent key:value pairs with '' as value, those are +parents of children key:value pairs, are left hanging at end of line, with the +children on the following line. This can look awkward, but in other cases, +actually looks very good, it depends if it's at the start or end of the line. + +I won't say this is not correctable, but it would be very difficult, and outside +the scope of this release, but that is something that I may look at for a future +release now that the output generator logic was reworked slightly for Change 5b. + +It's tricky though, because in cases where it's the first item on the line, you +want that behavior, but when it's last, you don't. But this may be worth +revisiting in the future. + +3. In some cases, -Y + -y1 may lead to the start of the block scrolling off the +top of the visible screen. This isn't really correctable, so if that's an issue +for you, just don't use -y1 with -Y and all the output will wrap nicely. + +4. There is an unaccountable ~10-20ms delay reading cpufreq/scaling_cur_freq, +per thread/core, which really adds up on high thread count CPUs. There is a +workaround in inxi to use cpufreq_cur_freq if it is readable, ie, if you are +root or use sudo, but to fallback to scaling_cur_freq if can't read cpuinfo_... + +This is a drag, and really looks like a kernel bug, or a frequency driver bug. + +-------------------------------------------------------------------------------- +BUGS: + +1. 3.3.09 and 3.3.10 CPU bug fixes: +* Failed to filter out certain virtual machine CPU core speeds, and showed more +speeds than the instance actually has. Noticed this with KVM running on Xeon +CPUs. +* For many cases, L2 cache, particularly for Intel, was completely wrong, it was +showing L3 caches, or L3+L2. Failed to handle cases where L2 cache belongs to +more than 1 core, except for using a crude hack for AMD Bulldozer microarch. +Older Intel Core 4 core CPUs would sometimes be 1 L2 per die, and the 4 cores +were actually 2 core duo cpu dies, with one L2 cache per die. +* Shows wrong core count for complex core complexes like those found in Intel +Alder Lake, now shows correct count of actual cores, regardless of the MT or ST +state of each core. +* Showed invalid L3 cache values in some legacy cpus that had no L3 cache, that +is due to a bug in the dmidecode data itself. Solution is to never use dmidecode +cache data if any other valid L1, L2, or L3 cache data found for Linux, and to +only use dmidecode data for bsds if no L1, or L2, or L3 data found. Or if forced +with --dmidecode. + +2. An unfortunately long standing bug found and fixed, thanks slackware users! +cp_cpu_arch was, and has been for a while, failing to convert hex stepping to +decimal, or test if the string it gets is even a possible hex value, this +resulted in all Intel CPUs with stepping > 9 failing to ID correctly for cpu +arch. + +3. In a related bug, hex to decimal tool used to create --admin hex/decimal +output for family/model/stepping was also not testing if the string was an +actual valid hex number. Case in particular, power pc with revision field +contained a long string, which was of course not a valid hex number, and that +tripped a Perl error when it was asked to convert a non hex string to decimal. + +4. Long standing bug found while doing Change 5: inxi actually never applied +separate in/out of dispay to widths because using a legacy boolean that was not +updated, so it was always using out of display widths. + +-------------------------------------------------------------------------------- +FIXES: + +1. Incorrectly calling PowerPC 'revision' 'stepping' for -Ca, that is now stored +as $cpu{'revision'} to avoid mixing up the logics there. For PowerPC shows as +rev: [string]. + +2. Microarch: +* AMD family 15, model 2 as bulldozer, actually piledriver. +* AMD family 17, model 18, was supposed to be zen/zen+, since I can't tell those +apart, seen stepping 1 is zen+, but had incorrect match. +* Intel family 6, model 25, stepping 2 as nehalem, should have been westmere. +* Changed Penryn to Core Penryn, intel family 6, model 17 +* misc other micro arch fine tunings. + +3. Code fix 8, switched to global %risc for arm, mips, ppc, riscv, sparc. This +corrects many sloppy handlers, and makes all risc processing the same, and calls +device tree readers for all risc systems, not just arm or arm and mips. + +4. In cases where bogomips were 0 due to false values in risc results, show N/A. + +5. Removed all attempts to guess at what /proc/cpuinfo cache size: refers to, +it can literally be anything, a per core L1, a per core or cpu L2, or an L3. +So applying any math to it is just a random guess at that point. If any L1,2,3 +cache data is found, don't use the cache: value at all, but that will only be +present if no /sys data was found anyway, and if cpuinfo had no specific cache +type fields, only generic cache. + +6. Added failsafe tests for stepping and model id before doing conversion to +hex. Make sure integer! + +7. Added L1 D cache, was only using I cache for BSDs. Output will show total for +L1 A + L1 D. No idea why I didn't use L1 D, makes little sense, but that's how +it goes. + +8. Made bogomips tests more granular, now only rejects low sub 50 bogomips +values if %risc cpu type. Legacy ancient cpus like 486 could and did have +bogomip counts below 50. +https://tldp.org/HOWTO/BogoMips/bogo-list.html + +9. See Enhancement 12 as well. If OpenBSD, which has no per core data or +physical cpu data, is running on MT capable cpu, but for security OpenBSD has +disabled MT, will now force MT to be not shown via the hw.smt value. This +removes a small glitch that would have bothered OpenBSD users who know that +OpenBSD has disabled MT for security purposes. + +10. Changed BSD hack to use L2 cache totals to deduce > 1 physical cpus, that +was flat out dumb, since we can just use dmidecode type 4 to iterate physical +cpu counts and skip the pointless logic. Thus, if dmidecode, and if > 1 +dmidecode type 4 found, and if physical cpu counts equal 1, then replace the +found counts with the dmidecode physical cpu counts. + +11. Corrected bad assumption that threads would always be 2 per core for MT +tests. Still no way to reliably determine threads per core for non x86 cpus like +powerpc however, but those are very fringe and should rarely be an issue since +that data is only missing on very old linux now I think. + +12. Fixed 'parameters:' going to its own line with -Sa, that wasn't supposed to. +-S is two lines, the kernel / host stuff, and the desktop/console/distro stuff. + +13. Fixed case when key: value first word plus other parts of line longer than +max width, failed to wrap as expected. + +14. Added start/end ' and " start / end \s to main filters. + +-------------------------------------------------------------------------------- +ENHANCEMENTS: + +1. CPU: most Linux will now show L1 and L3 cache with -Cx without needing +sudo/root, and it will be more accurate than ever before. + +2. CPU: shows per CPU L1/L2/L3 totals, and shows actual full system physical +processor count * L1/L2/L3 total in parentheses, like: L2: 1.5 MiB (3 MiB). + +3. CPU: A long standing annoyance, previously for main CPU 'Speed:' item, showed +the fastest core speed found, now shows avg: [speed] and with -Cx, shows the +'high:' as well if > 1 cores, and if 1 or more cores have a higher speed than +the other(s). + +4. CPU: Handles advanced cases of new architectures, like Alder Lake with +Performance and Efficiency cores, future Zen, and existing ARM CPUs with 2 or +more different core sets, with different max/min frequencies. Previously a hack +was used to handle only ARM CPUs with this type of architecture. Will show +correct CPU core counts, which previous inxi versions would fail to do for Alder +Lake type scenarios of 8 single threaded CPUs and 4-8 multithreaded )MT) +perforance cores. + +This should also in theory show different the different min/max speeds if they +were detected. Those did not seem to be set correctly in Alder Lake sample data +I saw however, P and E cores were set to the same min/max speeds. + +5. Added CPU types MST (Multi+Single Thread), AMP (Asymmetric Multi Processing), +and AMCP (Asymmetrical Multi Core Processor). This will be applied to any CPU +that has this type of complex topology that has been dynamically detected, like +Alder Lake or different core count or min/max speed RISC CPUs. + +6. CPU: shows with -Ca for cases where different L1/L2/L3 caches found per +physical CPU, as with Alder Lake, but also many other variants that were poorly +or not at all handled before, how many of each cache type (L1 Data, instruction) +were found, otherwise will show how many of each cache were found. + +7. CPU: shows with -Ca in Topology: report, for cases like Alder Lake with +different core types in one physical CPU (type: MST AMCP), the number that are +single threaded (st) and number that are multi-threaded (mt). + +8. Basic support for rsyc-v systems, going along with code fix 8, fix 3, now +it's easy to add this type of support. + +9. Added shortcut options for --filter-label (--zl), --filter-uuid (--zu), and +andded new filter option, --filter-vulnerabilities (--zv). The latter is added +by request, a decent idea to have option to not show cpu vulnerabilities. + +10. Going with fix 7, switched to a sort of pseudo L1 d/i with desc report for +any BSD with L1 I/D cache found, or elbrus cache0 (icache) / cache1 (d cache). +Elbrus should hopefully be handled by the /sys tool. Guesses on the L1 are ok, +since those are almost always per core, so it's fine. Didn't expect to enhance +any BSD cpu data this time around, but there you go!! If they have the data, +then it will be used. Not going to go overboard though in that, quite useless +overall since usually can't see how many CPUs are present, at least not usually. + +11. For -Ca, full CPU topology report if any complex topogy is detected, +otherwise shows the same basic Info: 2x 6-core or Info: dual core as before, no +point in wasting a line for something with no more data than the short string. +Complex types include MT CPUs since they will have different thread counts etc, +and will have 2 or more threads per core, which will also be listed. + +12. If smt status is defined (0/1), shows smt: enabled|disabled in Topology +section, can be useful for systems with disabled MT, but supporting it. If no +topology data found (OpenBSD for example), for -C shows 'smt: disabled' after +'type:' section, and enabled if -Cxxx (since MT really already tells you that). + +13. For -Ca Speed: report, added 'governor:' item, if found. Can show 1 or more +active governors. + +14. Output height (in lines) control: -Y [-2|-1|0|1-xxx]]. This lets you break +up any of the output into whatever number of lines you want. Also useful out of +DISPLAY for reading -h options menu items etc. + +It came tp my attention that the long standing shift+pgup/pgdown (aka +'softscrollback) behavior had stopped working, and in fact has been removed from +the current Linux kernel, at least until it is rewritten to be more clean and +understandable. Read more about it in these kernel post/commit messages: + +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=50145474f6ef4a9c19205b173da6264a644c7489 +https://lwn.net/ml/linux-kernel/CAHk-=whe4ZdTdCebneWqC4gSQZwsVJ5-Emg0BucOGCwPhOAJpw@mail.gmail.com/ + +Options for -Y are: +* -Y 0 or -Y: Set maximum block height to terminal line height. +* -Y [1-xxx]: Set maximum block line height to given integer. +* -Y -1: Print out one primary data block item at a time, with -F for example. +* -Y -2: Restore default unlimited height if LINES_MAX configuration item used. + +15. And finally, more disk vendors/vendor ids. As usual. As expected. + +-------------------------------------------------------------------------------- +CHANGES: + +1. If /sys or /proc/cpuinfo speed data available: +* For -b CPU item: + speed: [speed MHz] min/max: [min]/[max] MHz + becomes: + speed (MHz): avg: [speed] min/max: [min]/[max] +* For -C, Speed item + Speed: [speed MHz] min/max: [min]/[max] MHz Cores (MHz): ... + becomes: + Speed (MHz): avg: [speed] min/max: [min]/[max] cores: ... +* For short form, shows speed/min/max but uses average speed if available. + +For -b and -C, only shows one MHz in Speed line starter, which slightly shortens +the line even with the added 'avg:' item since 3 MHz are replaced with 1. + +2. Going with change 1, now the 'avg:' item shows not the fastest cpu speed +found, which was the case before, but shows an average of all cpu speeds found. +Showing the fastest made some sense back in the days of single core, or even +dual core CPUs, but makes little sense today with many core/threaded cpus. + +With -x, it will show the high: [speed] item as well, after 'avg:'. + +3. By suggestion, wrapped first Type item in Vulnerabilities to its own line, +that's a verbose --admin option after all, no need to save lines! + +4. Going along with Fix 5, give up on trying to pretend we can guess at L2 +cache, now if only 'cache' data was available from cpuinfo, will just say: +cache: [cache size] + note: check + +and call it a day. + +5a. Change default width to 80 columns, in and out of display. Too many users +are posting horribly wrapping inxi output in forums, issue trackers, etc, and it +frankly makes inxi look really bad, creates awful side scrolling code boxes, +etc. So now default widths in and out of console are 80 (since often data is +generated in SSH or out of X/Wayland) for issues. + +This essentially makes -y 80/-y the default width. This is what I've been using +for a few years now, and after seeing far too many side scrolling or badly +wrapping inxi outputs online, I think it's probably time to just force 80 column +widths as default and call it a day. + +You can change these new defaults using configuration options (these are the +previous options, though due to a bug, COLS_MAX_CONSOLE was never being used): + + COLS_MAX_CONSOLE=115 # in display, terminal client max width + COLS_MAX_IRC=100 + COLS_MAX_NO_DISPLAY=130 # not in display, no X/Wayland running + +5b. Changed output wrapped indent to 1 column from 2, and make second and +greater rows of a line indent +1 to make it more clear that it is a child row of +its parent row. Note that because no arg short form, -S, and -I are special +types of rows, this behavior is not used, they just print out as usual. This 1 +column indent also applies to -y1, making for a little more data per line but +more readable and easy to follow. + +6. If > 1 physical cpu detected, no longer uses single/dual/triple/quad core +strings, rather uses: 2x 2-core. Also uses lower case -core, not -Core. + +7. Only show die counts for CPU (on rare occasions > 1 found) with -xx. Not +particularly important bit of data afterall. + +8. Make L1, L3 cache data show with -Cx, not -Cxx, now that it's working well. + +9. Removed CPU die for -Cxx, that's only going to show with -Ca now. + +10. If -Ca, and if certain complexity conditions are met, shows a separate +Topology line rather than the Info: 6-core type item. For -b, short, -Cx, -Cxxx +shows the Info: topology short form. + +11. Bogomips always shows before flags data, whether -f or just -Cx trips flag +output. + +12. Flags/Features now shows in the same place, under Speeds: always, whether +-Cx shortlist, or -Cf full list. Makes more sense that way, and code is much +cleaner too. + +13. Bogomips, being essentially bogus units of speed for cpu, are moved into +Speed: report. + +-------------------------------------------------------------------------------- +DOCUMENTATION: + +1. Updated man/help for new CPU extra data options and output changes. + +2. Cleaned up and added sample outputs for man CPU items. + +3. Now that doas is getting into Linux distros, removed all mentions of doas as +a BSD option, and made it a general doas/sudo item. Glad to see doas making it +into linux distros, it's a good tool, much easier to configure and use than +sudo. Good job OpenBSD guys. Note that inxi already has had full doas support +for a while now, but this finalizes it, and makes it fully agnostic. Internally +doas is actually preferred over sudo, by the way. + +4. Added documention items for INDENT (--indent), INDENT_MIN (--inident-min). + +5. Re-ordered help menu and man page, created new Filters and Output Controls +sections to make stuff easier to find. In man page, also added on top a list of +OPTIONS sections to make finding stuff easier. + +-------------------------------------------------------------------------------- +CODE: + +1. Removed legacy /sys cpu functions: cpu_bugs_sys(); get_boost_status(); +set_cpu_speeds_sys(). cpu_speeds() is deprecated and now will only be used for +legacy Linux and BSDs if they had any per core speeds found; get_caches() was +only a placeholder for the full featured cpu_sys data source, and was removed; +cpu_speeds() no longer needed, integrated into other logic; cpu_dies_sys() +removed, integrated into other logic. + +This logic is now integrated into cpu_data_sys() data generator. + +2. Changed the main CpuItems functions to use array/hash references, not passing +full hashes or arrays in most cases now. + +3. For machine_data_soc(), switched to CpuItem::cpuinfo_grabber() which then +sets the global @cpuinfo and %cpuinfo_machine items, which will be used again +in Cpu if cpu data is requested. This gets rid of a full parsing of cpuinfo +just to get the machine data section, and also makes it so cpuinfo in cpu does +not need to worry about the machine data block, which is not related to the +processor blocks anyway, that was always a hack done by the kernel guys to toss +that SOC data somewhere as far as I can tell. + +4. New tools: +* either_or() - takes a list, and returns the first defined element of list. +* regex_range() - generate ranges from comma, space, or ranges like 2-29, or any +combination of those, like 3,6,12-29 + +5. Added --force cpuinfo to bypass all /sys based cpu logic, useful for testing +to see what would have happened using old logic. + +6. Added --dbg switches 39, 40, 41, for the new cpu sys data features, also made +more consistent --dbg 8 and --dbg 38 switches. + +7. Added sys/cpuinfo pair debugger to support debugging complex sys/cpuinfo +issues. + +8. Got rid of $b_arm,$b_mips,$b_ppc,$b_sparc, replaced with global %risc, also +added $risc{'riscv'} type. this makes general risc type feature testing a lot +easier since inxi can either test for %risc defined, or for a specific type of +risc cpu. This is much cleaner, and use $risc{'id'} for print purposes, which +got rid of a lot of tests. Also made all risc tests consistent, some were ARM +only, or arm/mips, but were supposed to be for all risc cpus. + +9. Set help menu code to roughly 80 columns width assuming 2 space tab +indentation. + +10. Changed all xxx_cleaner subs to clean_xxx, all filter subs to filter_xxx, +and row_defaults() to message(). + +11. Dumped redundant fallback logic in get_kernel_bits, if first getconf method +fails, use $sys_bits, and call it good, it was repeating the 32/64 bit tests +pointlessly. + +12. Cleaned up print_data() to allow for more fine tuned indentation for the new +2 indent levels. + +13. Made help menu code more or less wrap to 80 columns, or close. Ongoing to +bring to 80 columns where practical, but never at expense of clarity or logic. + +-------------------------------------------------------------------------------- +-- Harald Hope - Tue, 13 Dec 2021 10:25:49 -0800 + ================================================================================ Version: 3.3.09 Patch: 01