aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitattributes1
-rw-r--r--README.txt186
-rw-r--r--debian/changelog70
-rw-r--r--debian/control2
-rw-r--r--debian/copyright6
-rwxr-xr-xdebian/rules2
-rw-r--r--debian/watch2
-rwxr-xr-xinxi13414
-rw-r--r--inxi.1841
-rw-r--r--inxi.changelog2825
10 files changed, 12820 insertions, 4529 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..b2cd01b
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+inxi linguist-language=Perl
diff --git a/README.txt b/README.txt
index 7b2a529..27e35e4 100644
--- a/README.txt
+++ b/README.txt
@@ -1,12 +1,57 @@
+================================================================================
README for inxi - a command line system information tool
+================================================================================
+FILE: README.txt
+VERSION: 6.0
+DATE: 2024-01-14
The new faster, more powerful Perl inxi is here! File all issue reports with the
-master branch. All support for versions prior to 3.0 is now ended, sorry.
+master branch. All support for versions prior to 3.0 is ended.
Make sure to update to the current inxi from the master branch before filing any
-issue reports. The code in pre 2.9 versions literally no longer exists in inxi
-3. Bugs from earlier versions cannot usually be solved in the new version since
-the pre 2.9 and the 2.9 and later versions are completely different internally.
+issue reports. Bugs from earlier versions cannot usually be solved in the new
+version since too much changes intnernally release to release.
+
+--------------------------------------------------------------------------------
+CODEBERG SOURCE REPO
+--------------------------------------------------------------------------------
+
+Packagers: Make sure to change your package URLs and repos to use codeberg.org.
+
+The previous inxi-perl, tarballs, and docs branches are now standalone repos
+on codeberg.org:
+
+docs > https://codeberg.org/smxi/inxi-docs master
+inxi-perl > https://codeberg.org/smxi/pinxi master
+master > https://codeberg.org/smxi/inxi master
+tarballs > https://codeberg.org/smxi/inxi-tarballs master
+
+inxi-perl branch has been rebuilt and now only contains the pinxi, pinxi.1
+files, plus a minimal README.txt for github users. docs and tarballs have been
+deleted. The inxi-perl branch should not be used, and exists only so that
+current pinxi users can update from there to get the new version with new URLs.
+
+inxi master will be mirrored to github until most packagers have switched to
+using codeberg. inxi-perl/pinxi no longer gets updates, and exists only to let
+users update to a version with the new self updater codeberg URLs.
+
+The inxi repo only contains master, plus the one, two branches, which are
+obsolete.
+
+--------------------------------------------------------------------------------
+
+Please file issue reports or feature requests at:
+
+https://codeberg.org/smxi/inxi
+
+Please take the time to read this helpful article from the Software Freedom
+Conservancy:
+
+https://sfconservancy.org/GiveUpGitHub/
+
+Any use of this project's code by GitHub Copilot, past or present, is done
+without my permission. I do not consent to GitHub's use of this project's code
+in Copilot.
--------------------------------------------------------------------------------
DONATE
@@ -16,7 +61,7 @@ Help support the project with a one time or a sustaining donation.
Paypal: https://www.paypal.com/donate/?hosted_button_id=77DQVM6A4L5E2
-Open Collective: https://opencollective.com/inxi
+LiberaPay (sustaining donations): https://liberapay.com/smxi/
================================================================================
DEVELOPMENT AND ISSUES
@@ -68,32 +113,41 @@ See BSD/UNIX below for qualifications re BSDs, and OSX in particular.
SOURCE VERSION CONTROL
--------------------------------------------------------------------------------
-https://github.com/smxi/inxi
+inxi:
+REPO: https://codeberg.org/smxi/inxi
+MAIN BRANCH: master
+DEVELOPMENT BRANCHES [not used]: one, two
+
+pinxi [development version of inxi]:
+REPO: https://codeberg.org/smxi/pinxi
MAIN BRANCH: master
-DEVELOPMENT BRANCHES: inxi-perl, one, two
-inxi-perl is the dev branch, the others are rarely if ever used. inxi itself has
-the built in feature to be able to update itself from anywhere, including these
-branches, which is very useful for development and debugging on various user
-systems.
+pinxi is the standalone development version of inxi. inxi branches one, two are
+rarely if ever used. inxi has the built in feature to be able to update itself
+from anywhere, including these branches, which is very useful for development
+and debugging on various user systems.
+
+Please: NEVER even think about looking at or using previous inxi commits,
+previous to the current master version, as a base for a patch. If you do, your
+patch / pull request will probably be rejected.
PULL REQUESTS: Please talk to me before starting to work on patches of any
reasonable complexity. inxi is hard to work on, and you have to understand how
-it works before submitting patches, unless it's a trivial bug fix. Please: NEVER
-even think about looking at or using previous inxi commits, previous to the
-current master version, as a base for a patch. If you do, your patch / pull
-request will probably be rejected. Developers, get your version from the
-inxi-perl branch, pinxi, otherwise you may not be current to actual development
-versions. inxi-perl pinxi is always equal to or ahead of master branch inxi.
-
-Man page updates, doc page updates, etc, of course, are easy and will probably
+it works before submitting patches, unless it's a trivial bug fix. Never work
+with inxi master, always work with pinxi master, since it can be quite far ahead
+of inxi. inxi master has only one purpose, to get updated to next inxi when
+pinxi is ready to be copied over to inxi. pinxi is always equal to or ahead of
+master branch inxi.
+
+Man page updates, doc pages updates, etc, of course, are easy and will probably
be accepted, as long as they are properly formatted and logically coherent.
-When under active development, inxi releases early, and releases often.
+When under active development, pinxi releases early, and releases often. inxi
+is stable and is generally only updated when a new tagged version is completed.
-PACKAGERS: inxi has one and only one 'release', and that is the current
-commit/version in the master branch (plus pinxi inxi-perl branch, of course, but
-those should never be packaged).
+PACKAGERS: inxi has one and only one 'release', and that is the current tagged
+version in the master branch (plus pinxi repo, of course, but pinxi should in
+general not be packaged). No non-current versions of inxi are supported.
--------------------------------------------------------------------------------
MASTER BRANCH
@@ -103,48 +157,66 @@ This is the only supported branch, and the current latest commit/version is the
only supported 'release'. There are no 'releases' of inxi beyond the current
commit/version in master. All past versions are not supported.
-git clone https://github.com/smxi/inxi --branch master --single-branch
+git clone https://codeberg.org/smxi/inxi --branch master --single-branch
OR direct fast and easy install:
-wget -O inxi https://github.com/smxi/inxi/raw/master/inxi
+wget -O inxi https://codeberg.org/smxi/inxi/raw/master/inxi
-OR easy to remember shortcut (which redirects to github):
+OR easy to remember shortcut (which redirects to codeberg.org):
wget -O inxi https://smxi.org/inxi
wget -O inxi smxi.org/inxi
-NOTE: Just because github calls tagged commits 'Releases' does not mean they are
-releases! I can't change the words on the tag page. They are tagged commits,
-period. A tag is a pointer to a commit, and has no further meaning.
+NOTE: There are no 'Releases' per se. There are only tagged commits, period. A
+tag is a pointer to a commit, and has no further meaning. A tagged commit
+however is the target for packagers.
If your distribution has blocked -U self updater and you want a newer version:
Open /etc/inxi.conf and change false to true: B_ALLOW_UPDATE=true
--------------------------------------------------------------------------------
-DEVELOPMENT BRANCH
+
+SPECIAL NOTE FOR LEGACY OPERATING SYSTEMS WITH NO TLS 1.2 OR GREATER: Modern web
+servers are dropping support for TLS 1.0, 1.1, and so has smxi.org, this means
+to install inxi onto an older system with only TLS 1.0 or 1.1 available, you
+will need to do this to install inxi onto the old system:
+
+wget -O /usr/local/bin/inxi ftp://ftp.smxi.org/outgoing/inxi
+
+then update inxi/man pages after that with inxi -U 4, which uses FTP, not HTTP,
+to download the file.
+
+For pinxi, just change inxi to pinxi above (add --man to get the man page), and
+it will work the same.
+
+--------------------------------------------------------------------------------
+DEVELOPMENT VERSION (in pinxi repo)
--------------------------------------------------------------------------------
-All active development is now done on the inxi-perl branch (pinxi):
+All active development is done in the pinxi repo master branch.:
-git clone https://github.com/smxi/inxi --branch inxi-perl --single-branch
+git clone https://codeberg.org/smxi/pinxi
OR direct fast and easy install:
-wget -O pinxi https://github.com/smxi/inxi/raw/inxi-perl/pinxi
+wget -O pinxi https://codeberg.org/smxi/pinxi/raw/master/pinxi
-OR easy to remember shortcut (which redirects to github):
+OR easy to remember shortcut (which redirects to codeberg.org):
wget -O pinxi https://smxi.org/pinxi
wget -O pinxi smxi.org/pinxi
Once new features have been debugged, tested, and are reasonably stable, pinxi
-is copied to inxi in the master branch.
+is copied to inxi in the inxi master branch.
It's a good idea to check with pinxi if you want to make sure your issue has not
been corrected, since pinxi is always equal to or ahead of inxi.
+See SPECIAL NOTE FOR LEGACY OPERATING SYSTEMS above to install pinxi on very old
+operating systems with out of date TLS version.
+
--------------------------------------------------------------------------------
LEGACY INXI (in inxi-legacy repo)
--------------------------------------------------------------------------------
@@ -154,15 +226,16 @@ inxi-legacy repo, as binxi in the /inxi-legacy directory:
Direct fast and easy install:
-wget -O binxi https://github.com/smxi/inxi-legacy/raw/master/inxi-legacy/binxi
+wget -O binxi https://codeberg.org/smxi/inxi-legacy/raw/master/binxi
-OR easy to remember shortcut (which redirects to github):
+OR easy to remember shortcut (which redirects to codeberg.org):
wget -O binxi https://smxi.org/binxi
This version will not be maintained, and it's unlikely that any time will be
spent on it in the future, but it is there in case it's of use or interest to
-anyone.
+anyone. Please don't ask for any help with that, the reason inxi was rewritten
+to Perl was to avoid ever needing to battle with bash/gawk again.
This was kept for a long time as the inxi-legacy branch of inxi, but was moved
to the inxi-legacy repo 2021-09-24.
@@ -174,7 +247,8 @@ SUPPORT INFO
Do not ask for basic help that reading the inxi -h / --help menus, or man page
would show you, and do not ask for features to be added that inxi already has.
Also do not ask for support if your distro won't update its inxi version, some
-are bad about that.
+are bad about that. Yes, these are long, but inxi does a lot of stuff, not all
+of it particularly ihtuitive.
--------------------------------------------------------------------------------
DOCUMENTATION
@@ -182,9 +256,9 @@ DOCUMENTATION
https://smxi.org/docs/inxi.htm
(smxi.org/docs/ is easier to remember, and is one click away from inxi.htm). The
-one page wiki on github is only a pointer to the real resources.
+one page wiki on codeberg.org is only a pointer to the real resources.
-https://github.com/smxi/inxi/tree/inxi-perl/docs
+https://codeberg.org/smxi/pinxi/src/branch/master/docs
Contains specific Perl inxi documentation, of interest mostly to developers.
Includes internal inxi tools, values, configuration items. Also has useful
@@ -200,20 +274,30 @@ NOTE: Check the inxi version number on each doc page to see which version will
support the options listed. The man and options page also link to a legacy
version, pre 2.9.
+https://codeberg.org/smxi/inxi/wiki
+
+This is simply a page with links to actual inxi resources, which can be useful
+for developers and people with technical questions. No attempt will be made to
+reproduce those external resources on codeberg.org. You'll find stuff like
+how to export to json/xml there, and basic core philosophies, etc.
+
--------------------------------------------------------------------------------
IRC
--------------------------------------------------------------------------------
-You can go to: irc.oftc.net or irc.libera.chat channel #smxi
+You can go to:
+
+irc.oftc.net or irc.libera.chat channel #smxi
but be prepared to wait around for a while to get a response. Generally it's
-better to use github issues.
+better to use codeberg.org issues.
--------------------------------------------------------------------------------
ISSUES
--------------------------------------------------------------------------------
-https://github.com/smxi/inxi/issues
+https://codeberg.org/smxi/inxi/issues
+
No issues accepted for non current inxi versions. See below for more on that.
Unfortunately as of 2.9, no support or issues can be accepted for older inxi's
because inxi 2.9 (Perl) and newer is a full rewrite, and legacy inxi is not
@@ -310,10 +394,14 @@ SUPPORTED VERSIONS / DISTRO VERSIONS
Important: the only version of inxi that is supported is the latest current
master branch version/commit. No issue reports or bug reports will be accepted
for anything other than current master branch. No merges, attempts to patch old
-code from old versions, will be considered or accepted. If you are not updated
-to the latest inxi, do not file a bug report since it's probably been fixed ages
-ago. If your distro isn't packaging a current inxi, then file a bug report with
-your packager, not here.
+code from old versions, will be considered or accepted on the master branch of
+inxi. If you are not updated to the latest inxi, do not file a bug report since
+it's probably been fixed ages ago. If your distro isn't packaging a current
+inxi, then file a bug report with your packager, not here.
+
+The development branch inxi-perl/pinxi has been moved to its own standalone
+repo, pinxi, at https://codeberg.org/smxi/pinxi - this is the only place
+development happens.
inxi is 'rolling release' software, just like Debian Sid, Gentoo, or Arch Linux
are rolling release GNU/Linux distributions, with no 'release points'.
@@ -371,7 +459,7 @@ The fourth number, when used, will be alpha-numeric, a common version would be,
in say, branch one: 2.2.28-b1-02, in other words: branch 1 patch version 2.
In the past, now and then the 4th, or 'patch', number, was used in trunk/master
-branches of inxi, but I've pretty much stopped doing that because it's
+branches of inxi, but that practice has pretty much stopped because it's
confusing.
inxi does not use the fiction of date based versioning because that imparts no
diff --git a/debian/changelog b/debian/changelog
index 0165b8d..7aea51e 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,73 @@
+inxi (3.3.33-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.33-1.
+
+ -- Unit 193 <unit193@debian.org> Thu, 08 Feb 2024 03:18:01 -0500
+
+inxi (3.3.32-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.32-1.
+
+ -- Unit 193 <unit193@debian.org> Wed, 31 Jan 2024 01:38:54 -0500
+
+inxi (3.3.31-2-1) unstable; urgency=medium
+
+ * New upstream version 3.3.31-2.
+
+ -- Unit 193 <unit193@debian.org> Sat, 04 Nov 2023 18:19:20 -0400
+
+inxi (3.3.30-1-1) unstable; urgency=medium
+
+ * d/copyright, d/watch: Follow upstream's VCS move.
+ * New upstream version 3.3.30-1.
+
+ -- Unit 193 <unit193@debian.org> Mon, 25 Sep 2023 23:46:39 -0400
+
+inxi (3.3.29-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.29-1.
+
+ -- Unit 193 <unit193@debian.org> Wed, 16 Aug 2023 20:32:04 -0400
+
+inxi (3.3.28-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.28-1.
+
+ -- Unit 193 <unit193@debian.org> Mon, 10 Jul 2023 18:44:12 -0400
+
+inxi (3.3.27-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.27-1.
+
+ -- Unit 193 <unit193@debian.org> Mon, 22 May 2023 01:11:03 -0400
+
+inxi (3.3.26-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.26-1.
+
+ -- Unit 193 <unit193@debian.org> Fri, 31 Mar 2023 23:14:14 -0400
+
+inxi (3.3.25-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.25-1.
+ * d/copyright: Bump years.
+ * Update Standards-Version to 4.6.2.
+
+ -- Unit 193 <unit193@debian.org> Wed, 08 Feb 2023 02:10:16 -0500
+
+inxi (3.3.24-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.24-1.
+ * d/rules: Opt-out of trimmed changelogs.
+
+ -- Unit 193 <unit193@debian.org> Wed, 14 Dec 2022 23:06:48 -0500
+
+inxi (3.3.23-1-1) unstable; urgency=medium
+
+ * New upstream version 3.3.23-1.
+
+ -- Unit 193 <unit193@debian.org> Tue, 01 Nov 2022 05:51:02 -0400
+
inxi (3.3.22-1-1) unstable; urgency=medium
* New upstream version 3.3.22-1.
diff --git a/debian/control b/debian/control
index 93c714a..e3c4277 100644
--- a/debian/control
+++ b/debian/control
@@ -4,7 +4,7 @@ Priority: optional
Maintainer: Unit 193 <unit193@debian.org>
Build-Depends: debhelper-compat (= 13)
Rules-Requires-Root: no
-Standards-Version: 4.6.1
+Standards-Version: 4.6.2
Homepage: https://smxi.org/docs/inxi.htm
Vcs-Browser: https://git.unit193.net/cgit/users/unit193/inxi.git
Vcs-Git: https://git.unit193.net/cgit/users/unit193/inxi.git
diff --git a/debian/copyright b/debian/copyright
index 1928c06..1389918 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,11 +1,11 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: inxi
-Source: https://github.com/smxi/inxi/
+Source: https://codeberg.org/smxi/inxi/
Files: *
Copyright: 2005-2007, Michiel de Boer <infobash@rebelhomicide.demon.nl>
2008-2017, Scott Rogers <trash80.v2.0@gmail.com>
- 2008-2022, Harold Hope <inxi-svn@techpatterns.com>
+ 2008-2023, Harold Hope <inxi-svn@techpatterns.com>
License: GPL-3+
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -25,7 +25,7 @@ License: GPL-3+
Files: debian/*
-Copyright: 2013-2022, Unit 193 <unit193@debian.org>
+Copyright: 2013-2023, Unit 193 <unit193@debian.org>
License: BSD-3-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
diff --git a/debian/rules b/debian/rules
index 04eacd5..6b4ed51 100755
--- a/debian/rules
+++ b/debian/rules
@@ -4,4 +4,4 @@
dh $@
override_dh_installchangelogs:
- dh_installchangelogs inxi.changelog
+ DEB_BUILD_OPTIONS=notrimdch dh_installchangelogs inxi.changelog
diff --git a/debian/watch b/debian/watch
index 5b7a58b..6eb113a 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,2 +1,2 @@
version=4
-https://github.com/smxi/inxi/tags .*/([\d\.-]+)\.tar\.(?:gz|bzip2|xz|zst)
+https://codeberg.org/smxi/inxi/tags .*/([\d\.-]+)\.tar\.(?:gz|bzip2|xz|zst)
diff --git a/inxi b/inxi
index aa128a5..5edb0d2 100755
--- a/inxi
+++ b/inxi
@@ -1,6 +1,6 @@
#!/usr/bin/env perl
## infobash: Copyright (C) 2005-2007 Michiel de Boer aka locsmif
-## inxi: Copyright (C) 2008-2022 Harald Hope
+## inxi: Copyright (C) 2008-2024 Harald Hope
## Additional features (C) Scott Rogers - kde, cpu info
## Parse::EDID (C): 2005-2010 by Mandriva SA, Pascal Rigaux, Anssi Hannula
## Further fixes (listed as known): Horst Tritremmel <hjt at sidux.com>
@@ -40,6 +40,7 @@ use Getopt::Long qw(GetOptions);
Getopt::Long::Configure ('bundling', 'no_ignore_case',
'no_getopt_compat', 'no_auto_abbrev','pass_through');
use POSIX qw(ceil uname strftime ttyname);
+# use bigint qw/hex/; # to handle large hex number warnings, but Perl 5.010 and later.
# use Benchmark qw(:all);_
# use Devel::Size qw(size total_size);
# use feature qw(say state); # 5.10 or newer Perl
@@ -48,8 +49,8 @@ use POSIX qw(ceil uname strftime ttyname);
## INXI INFO ##
my $self_name='inxi';
-my $self_version='3.3.23';
-my $self_date='2022-10-31';
+my $self_version='3.3.33';
+my $self_date='2024-02-06';
my $self_patch='00';
## END INXI INFO ##
@@ -72,12 +73,12 @@ if (eval {require OpenBSD::Pledge}){
my ($fake_data_dir,$self_path,$user_config_dir,$user_config_file,$user_data_dir);
## Hashes
-my (%alerts,%build_prop,%client,%colors,,%cpuinfo_machine,%disks_bsd,
-%dboot,%devices,%dl,%dmmapper,%force,%loaded,%mapper,%program_values,%risc,
-%service_tool,%show,%sysctl,%system_files,%usb,%windows);
+my (%alerts,%build_prop,%client,%colors,,%cpuinfo_machine,%comps,%disks_bsd,
+%dboot,%devices,%dl,%dmmapper,%force,%loaded,%mapper,%program_values,%ps_data,
+%risc,%service_tool,%show,%sysctl,%system_files,%usb,%windows);
## System Arrays
-my (@app,@cpuinfo,@dmi,@ifs,@ifs_bsd,@paths,@ps_aux,@ps_cmd,@ps_gui,
+my (@cpuinfo,@dmi,@ifs,@ifs_bsd,@paths,@ps_aux,@ps_cmd,
@sensors_exclude,@sensors_use,@uname);
## Disk/Logical/Partition/RAID arrays
@@ -102,18 +103,18 @@ 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_busybox_ps,$b_display,$b_irc,$b_root);
+my ($b_admin,$b_android,$b_display,$b_irc,$b_root);
## System
my ($bsd_type,$device_vm,$language,$os,$pci_tool) = ('','','','','');
-my ($wan_url,$wl_compositors) = ('','');
+my ($wan_url) = ('');
my ($bits_sys,$cpu_arch,$ppid);
-my ($cpu_sleep,$dl_timeout,$limit,$ps_cols,$ps_count) = (0.35,4,10,0,5);
+my ($cpu_sleep,$dl_timeout,$limit,$ps_count) = (0.35,4,10,5);
my $sensors_cpu_nu = 0;
-my ($dl_ua,$weather_source,$weather_unit) = ('s-tools/' . $self_name . '-',100,'mi');
+my ($weather_source,$weather_unit) = (100,'mi');
## Tools
-my ($bt_tool,$display,$ftp_alt);
+my ($display,$ftp_alt);
my ($display_opt,$sudoas) = ('','');
## Output
@@ -145,6 +146,7 @@ my %size = (
'irc' => 100, # shorter because IRC clients have nick lists etc
'lines' => 1, # for active output line counter for -Y
'max-cols' => 0,
+'max-join-list' => 30, # used in make_list_value() to add space after sep or not.
'max-lines' => 0,
'max-wrap' => 110,
'no-display' => 100, # No Display, orig: 130
@@ -196,11 +198,11 @@ sub main {
#### -------------------------------------------------------------------
sub initialize {
- set_os();
set_path();
set_user_paths();
set_basics();
set_system_files();
+ set_os();
Configs::set();
# set_downloader();
set_display_size();
@@ -210,6 +212,7 @@ sub initialize {
{
package CheckTools;
my (%commands);
+
sub set {
eval $start if $b_log;
set_commands();
@@ -261,9 +264,9 @@ sub set {
}
print Data::Dumper::Dumper \%alerts if $dbg[25];
set_fake_bsd_tools() if $fake{'bsd'};
- set_forced_tools();
eval $end if $b_log;
}
+
sub set_dmidecode {
my ($data) = @_;
my $action = 'use';
@@ -308,6 +311,7 @@ sub set_dmidecode {
}
return $action;
}
+
sub set_commands {
# note: gnu/linux has sysctl so it may be used that for something if present
# there is lspci for bsds so doesn't hurt to check it
@@ -318,6 +322,9 @@ sub set_commands {
if ($use{'logical'}){
$commands{'lvs'} = ['exec-sys','',''];
}
+ if ($use{'udevadm'}){
+ $commands{'udevadm'} = ['missing','',''];
+ }
}
else {
if ($use{'pci'}){
@@ -350,6 +357,8 @@ sub set_commands {
$commands{'bluetoothctl'} = ['missing','linux','',''];
# bt-adapter hangs when bluetooth service is disabled
$commands{'bt-adapter'} = ['missing','linux','',''];
+ # btmgmt enters its own shell with no options given
+ $commands{'btmgmt'} = ['missing','linux','',''];
$commands{'hciconfig'} = ['missing','linux','',''];
}
if ($show{'sensor'}){
@@ -377,19 +386,7 @@ sub set_commands {
$commands{'disklabel'} = ['missing','bsd','xx'];
}
}
-sub set_forced_tools {
- if ($bt_tool){
- if ($bt_tool ne 'bluetootctl' && $alerts{'bluetoothctl'}->{'action'} eq 'use'){
- $alerts{'bluetoothctl'}->{'action'} = 'missing';
- }
- if ($bt_tool ne 'bt-adapter' && $alerts{'bt-adapter'}->{'action'} eq 'use'){
- $alerts{'bt-adapter'}->{'action'} = 'missing';
- }
- if ($bt_tool ne 'hciconfig' && $alerts{'hciconfig'}->{'action'} eq 'use'){
- $alerts{'hciconfig'}->{'action'} = 'missing';
- }
- }
-}
+
# only for dev/debugging BSD
sub set_fake_bsd_tools {
$system_files{'dmesg-boot'} = '/var/run/dmesg.boot' if $fake{'dboot'};
@@ -417,9 +414,6 @@ sub set_fake_bsd_tools {
}
}
-# args: 1 - desktop/app command for --version; 2 - search string;
-# 3 - space print number; 4 - [optional] version arg: -v, version, etc
-# 5 - [optional] exit first find 0/1; 6 - [optional] 0/1 stderr output
sub set_basics {
### LOCALIZATION - DO NOT CHANGE! ###
# set to default LANG to avoid locales errors with , or .
@@ -434,9 +428,9 @@ sub set_basics {
$b_root = $< == 0; # root UID 0, all others > 0
$dl{'dl'} = 'curl';
$dl{'curl'} = 1;
+ $dl{'fetch'} = 1;
$dl{'tiny'} = 1; # note: two modules needed, tested for in set_downloader
$dl{'wget'} = 1;
- $dl{'fetch'} = 1;
$client{'console-irc'} = 0;
$client{'dcop'} = (check_program('dcop')) ? 1 : 0;
$client{'qdbus'} = (check_program('qdbus')) ? 1 : 0;
@@ -450,6 +444,18 @@ sub set_basics {
$show{'partition-sort'} = 'id'; # sort order for partitions
@raw_logical = (0,0,0);
$ppid = getppid();
+ # seen case where $HOME not set
+ if (!$ENV{'HOME'}){
+ if (my $who = qx(whoami)){
+ if (-d "/$who"){
+ $ENV{'HOME'} = "/$who";} # root
+ elsif (-d "/home/$who"){
+ $ENV{'HOME'} = "/home/$who";}
+ elsif (-d "/usr/home/$who"){
+ $ENV{'HOME'} = "/usr/home/$who";}
+ # else give up, we're not going to have any luck here
+ }
+ }
}
sub set_display_size {
@@ -514,7 +520,7 @@ sub set_os {
elsif ($cpu_arch =~ /(sparc|sun4[uv])/){
$risc{'sparc'} = 1;
$risc{'id'} = 'sparc';}
- # aarch32 mips32 intel/amd handled in cpu, i386
+ # aarch32 mips32, i386. centaur/via/intel/amd handled in cpu
if ($cpu_arch =~ /(armv[1-7]|32|[23456]86)/){
$bits_sys = 32;
}
@@ -603,7 +609,7 @@ sub set_sudo {
$sudoas = "$path -n ";
}
elsif (!$force{'no-sudo'} && ($path = check_program('sudo'))){
- my @data = program_data('sudo');
+ my @data = ProgramData::full('sudo');
$data[1] =~ s/^([0-9]+\.[0-9]+).*/$1/;
# print "sudo v: $data[1]\n";
$sudoas = "$path -n " if is_numeric($data[1]) && $data[1] >= 1.7;
@@ -640,7 +646,8 @@ sub set_user_paths {
$self_path = $0;
$self_path =~ s/[^\/]+$//;
# print "0: $0 sp: $self_path\n";
- if (defined $ENV{'XDG_CONFIG_HOME'} && $ENV{'XDG_CONFIG_HOME'}){
+ # seen case where $HOME not set
+ if ($ENV{'XDG_CONFIG_HOME'}){
$user_config_dir=$ENV{'XDG_CONFIG_HOME'};
$b_conf=1;
}
@@ -651,7 +658,7 @@ sub set_user_paths {
else {
$user_config_dir="$ENV{'HOME'}/.$self_name";
}
- if (defined $ENV{'XDG_DATA_HOME'} && $ENV{'XDG_DATA_HOME'}){
+ if ($ENV{'XDG_DATA_HOME'}){
$user_data_dir="$ENV{'XDG_DATA_HOME'}/$self_name";
$b_data=1;
}
@@ -689,8 +696,8 @@ sub set_xorg_log {
my ($file_holder,$time_holder,$x_mtime) = ('',0,0);
# NOTE: other variations may be /var/run/gdm3/... but not confirmed
# worry about we are just going to get all the Xorg logs we can find,
- # and not which is 'right'.
- @temp = globber('/var/log/Xorg.*.log');
+ # and not which is 'right'. Xorg was XFree86 earlier, only in /var/log.
+ @temp = globber('/var/log/{Xorg,XFree86}.*.log');
push(@x_logs, @temp) if @temp;
@temp = globber('/var/lib/gdm/.local/share/xorg/Xorg.*.log');
push(@x_logs, @temp) if @temp;
@@ -739,7 +746,7 @@ sub set_xorg_log {
#### COLORS
#### -------------------------------------------------------------------
-## arg: 1 - the type of action, either integer, count, or full
+## args: 0: the type of action, either integer, count, or full
sub get_color_scheme {
eval $start if $b_log;
my ($type) = @_;
@@ -897,13 +904,15 @@ my (@data,%configs,%status);
my ($type,$w_fh);
my $safe_color_count = 12; # null/normal + default color group
my $count = 0;
-# args: 1 - type
+
+# args: 0: type
sub new {
my $class = shift;
($type) = @_;
my $self = {};
return bless $self, $class;
}
+
sub select_schema {
eval $start if $b_log;
assign_selectors();
@@ -956,6 +965,7 @@ sub assign_selectors {
$configs{'selection'} = 'global';
}
}
+
sub start_selector {
my $whoami = getpwuid($<) || "unknown???";
if (!$b_irc){
@@ -986,6 +996,7 @@ sub start_selector {
main::print_basic(\@data);
@data = ();
}
+
sub create_color_selections {
my $spacer = '^^'; # printer removes double spaces, but replaces ^ with ' '
$count = (main::get_color_scheme('count') - 1);
@@ -1006,6 +1017,7 @@ sub create_color_selections {
@data = ();
main::set_color_scheme(0);
}
+
sub get_selection {
my $number = $count + 1;
@data = (
@@ -1050,6 +1062,7 @@ sub get_selection {
OpenBSD::Pledge::pledge(@pledges);
}
}
+
sub process_selection {
my $response = shift;
if ($response == ($count + 3)){
@@ -1100,6 +1113,7 @@ sub process_selection {
set_config_color_scheme($response);
}
}
+
sub delete_all_colors {
my @file_lines = main::reader($user_config_file);
open($w_fh, '>', $user_config_file) or main::error_handler('open', $user_config_file, $!);
@@ -1110,6 +1124,7 @@ sub delete_all_colors {
}
close $w_fh;
}
+
sub delete_global_color {
my @file_lines = main::reader($user_config_file);
open($w_fh, '>', $user_config_file) or main::error_handler('open', $user_config_file, $!);
@@ -1120,6 +1135,7 @@ sub delete_global_color {
}
close $w_fh;
}
+
sub set_config_color_scheme {
my $value = shift;
my @file_lines = main::reader($user_config_file);
@@ -1154,7 +1170,6 @@ sub print_irc_message {
main::print_basic(\@data);
exit 0;
}
-
}
#### -------------------------------------------------------------------
@@ -1165,45 +1180,76 @@ sub print_irc_message {
# public: set() check_file()
{
package Configs;
+
sub set {
- my ($configs) = @_;
- my ($key, $val,@config_files);
- if (!$configs){
- @config_files = (
- qq(/etc/$self_name.conf),
- qq(/etc/$self_name.d/$self_name.conf),
- qq($user_config_dir/$self_name.conf)
- );
- }
- else {
- @config_files = @$configs;
- }
+ my ($b_show) = @_;
+ my ($b_files,$key, $val,@config_files);
+ # removed legacy kde @$configs test which never worked
+ @config_files = (
+ qq(/etc/$self_name.conf),
+ qq(/etc/$self_name.d/$self_name.conf), # this was wrong path, but check in case
+ qq(/etc/$self_name.conf.d/$self_name.conf),
+ qq(/usr/etc/$self_name.conf),
+ qq(/usr/etc/$self_name.conf.d/$self_name.conf),
+ qq(/usr/local/etc/$self_name.conf),
+ qq(/usr/local/etc/$self_name.conf.d/$self_name.conf),
+ qq($user_config_dir/$self_name.conf)
+ );
# Config files should be passed in an array as a param to this function.
# Default intended use: global @CONFIGS;
foreach (@config_files){
- next unless open(my $fh, '<', "$_");
+ next unless -e $_ && open(my $fh, '<', "$_");
+ my $b_configs;
+ $b_files = 1;
+ print "${line1}Configuration file: $_\n" if $b_show;
while (<$fh>){
chomp;
s/#.*//;
s/^\s+//;
s/\s+$//;
s/'|"//g;
- s/true/1/i; # switch to 1/0 perl boolean
- s/false/0/i; # switch to 1/0 perl boolean
next unless length;
($key, $val) = split(/\s*=\s*/, $_, 2);
next unless length($val);
- process_item($key,$val);
+ $val =~ s/true/1/i; # switch to 1/0 perl boolean
+ $val =~ s/false/0/i; # switch to 1/0 perl boolean
+ if (!$b_show){
+ process_item($key,$val);
+ }
+ else {
+ print $line3 if !$b_configs;
+ print "$key=$val\n";
+ $b_configs = 1;
+ }
# print "f: $file key: $key val: $val\n";
}
close $fh;
+ if ($b_show && !$b_configs){
+ print "No configuration items found in file.\n";
+ }
+ }
+ return $b_files if $b_show;
+}
+
+sub show {
+ print "Showing current active/set configurations, by file. Last overrides previous.\n";
+ my $b_files = set(1);
+ print $line1;
+ if ($b_files){
+ print "All done! Everything look good? If not, fix it.\n";
}
+ else {
+ print "No configuration files found. Is that what you expected?\n";
+ }
+ exit 0;
}
+
# note: someone managed to make a config file with corrupted values, so check
# int explicitly, don't assume it was done correctly.
# 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)}
@@ -1274,6 +1320,7 @@ sub process_item {
$weather_unit = $val;
}
}
+
## COLORS/SEP ##
elsif ($key eq 'CONSOLE_COLOR_SCHEME'){
$colors{'console'} = $val if main::is_int($val)}
@@ -1296,6 +1343,7 @@ sub process_item {
$sep{'s2-irc'} = $val}
elsif ($key eq 'SEP2_CONSOLE'){
$sep{'s2-console'} = $val}
+
## SIZES ##
elsif ($key eq 'COLS_MAX_CONSOLE'){
$size{'console'} = $val if main::is_int($val)}
@@ -1321,6 +1369,7 @@ sub process_item {
# print "mc: key: $key val: $val\n";
# print Dumper (keys %size) . "\n";
}
+
sub check_file {
$user_config_file = "$user_config_dir/$self_name.conf";
if (! -f $user_config_file){
@@ -1339,11 +1388,11 @@ sub check_file {
# inxi.2.log
sub begin_logging {
return 1 if $fh_l; # if we want to start logging for testing before options
- my $log_file_2="$user_data_dir/$self_name.1.log";
- my $log_file_3="$user_data_dir/$self_name.2.log";
+ my $log_file_2 = "$user_data_dir/$self_name.1.log";
+ my $log_file_3 = "$user_data_dir/$self_name.2.log";
my $data = '';
- $end='main::log_data("fe", (caller(1))[3], "");';
- $start='main::log_data("fs", (caller(1))[3], \@_);';
+ $end = 'main::log_data("fe", (caller(1))[3], "");';
+ $start = 'main::log_data("fs", (caller(1))[3], \@_);';
#$t3 = tv_interval ($t0, [gettimeofday]);
$t3 = eval 'Time::HiRes::tv_interval (\@t0, [Time::HiRes::gettimeofday()]);' if $b_hires;
# print Dumper $@;
@@ -1377,10 +1426,8 @@ sub begin_logging {
# NOTE: no logging available until get_parameters is run, since that's what
# sets logging # in order to trigger earlier logging manually set $b_log
# to true in top variables.
-# args: $1 - type [fs|fe|cat|dump|raw] OR data to log
-# arg: $2 -
-# arg: $one type (fs/fe/cat/dump/raw) or logged data;
-# [$two is function name; [$three - function args]]
+# args: 0: type [fs|fe|cat|dump|raw]; 1: function name OR data to log;
+# [2: function args OR hash/array ref]
sub log_data {
return if !$b_log;
my ($one, $two, $three) = @_;
@@ -1503,8 +1550,8 @@ my ($data_dir,$debug_dir,$debug_gz,$parse_src,$upload) = ('','','','','');
my @content;
my $b_debug = 0;
my $b_delete_dir = 1;
-# args: 1 - type
-# args: 2 - upload
+
+# args: 0: type; 1: upload
sub new {
my $class = shift;
($option) = @_;
@@ -1560,6 +1607,7 @@ sub run_debugger {
print $line3;
compress_dir();
}
+
sub check_required_items {
print "Loading required debugger Perl File:: modules... \n";
# Fedora/Redhat doesn't include File::Find File::Copy in
@@ -1598,6 +1646,7 @@ sub check_required_items {
}
}
}
+
sub create_debug_directory {
my $host = main::get_hostname();
$host =~ s/ /-/g;
@@ -1636,6 +1685,7 @@ sub create_debug_directory {
}
print "Debugger data going into:\n$data_dir\n";
}
+
sub compress_dir {
print "Creating tar.gz compressed file of this material...\n";
print "File: $debug_gz\n";
@@ -1650,6 +1700,7 @@ sub compress_dir {
print "Directory removed.\n";
}
}
+
# NOTE: incomplete, don't know how to ever find out
# what sound server is actually running, and is in control
sub audio_data {
@@ -1657,9 +1708,22 @@ sub audio_data {
print "Collecting audio data...\n";
my @cmds = (
['aplay', '--version'], # alsa
- ['aplay', '-l'], # alsa
+ ['aplay', '-l'], # alsa devices
+ ['aplay', '-L'], # alsa list of features, can detect active sound server
+ ['artsd', '-v'], # aRts
+ ['esd', '-v'], # EsounD, to stderr
+ ['nasd', '-V'], # NAS
+ ['jackd', '--version'], # JACK
['pactl', '--version'], # pulseaudio
+ ['pactl', 'info'], # pulseaudio, check if running as server: Server Name:
['pactl', 'list'], # pulseaudio
+ ['pipewire', '--version'], # pipewire
+ ['pipewire-alsa', '--version'], # pipewire-alsa - just config files
+ ['pipewire-pulse', '--version'], # pipewire-pulse
+ ['pulseaudio', '--version'], # PulseAudio
+ ['pw-jack', '--version'], # pipewire-jack
+ ['pw-cli', 'ls'], # pipewire, check if running as server
+ ['pw-cli', 'info all'],
);
run_commands(\@cmds,'audio');
@files = main::globber('/proc/asound/card*/codec*');
@@ -1679,10 +1743,12 @@ sub audio_data {
push(@files,@files2) if @files2;
copy_files(\@files,'audio');
}
+
sub bluetooth_data {
print "Collecting bluetooth data...\n";
-# no warnings 'uninitialized';
+ # no warnings 'uninitialized';
my @cmds = (
+ ['btmgmt','info'],
['hciconfig','-a'], # no version
#['hcidump',''], # hangs sometimes
['hcitool','dev'],
@@ -1694,8 +1760,8 @@ sub bluetooth_data {
['bt-adapter','--list'], # no version
['bt-adapter','--info'],
['bluetoothctl','--version'],
- ['bluetoothctl','-- list'],
- ['bluetoothctl','-- show']
+ ['bluetoothctl','--list'],
+ ['bluetoothctl','--show']
);
}
run_commands(\@cmds,'bluetooth');
@@ -1850,6 +1916,7 @@ sub disk_data {
);
run_commands(\@cmds,'disk-bsd');
}
+
sub display_data {
my (%data,@files,@files2);
my $working = '';
@@ -1875,6 +1942,7 @@ sub display_data {
push(@files, '/var/lib/gdm/.local/share/xorg/Xorg.0.log');
push(@files, $ENV{'HOME'} . '/.local/share/xorg/Xorg.0.log');
push(@files, $system_files{'xorg-log'}) if $system_files{'xorg-log'};
+ push(@files, '/etc/X11/XFCconfig-4'); # very old format for xorg.conf
push(@files, '/etc/X11/xorg.conf');
copy_files(\@files,'display-xorg');
print "Collecting X, xprop, glxinfo, xrandr, xdpyinfo data, Wayland info...\n";
@@ -1907,6 +1975,12 @@ sub display_data {
# kde 5/plasma desktop 5, this is maybe an extra package and won't be used
['about-distro',''],
['aticonfig','--adapter=all --od-gettemperature'],
+ ['clinfo',''],
+ ['clinfo','--list'],
+ ['clinfo','--raw'], # machine friendly
+ ['eglinfo',''],
+ ['eglinfo','-B'],
+ ['es2_info',''],
['glxinfo',''],
['glxinfo','-B'],
['kded','--version'],
@@ -1941,25 +2015,31 @@ sub display_data {
['vainfo',''],
['vdpauinfo',''],
['vulkaninfo',''],
- ['wayland-info',''], # not packaged as far as I know yet
+ ['vulkaninfo','--summary'],
+ # ['vulkaninfo','--json'], # outputs to file, not sure how to output to stdout
+ ['wayland-info',''], # wayland-utils
['weston-info',''],
['wmctrl','-m'],
['weston','--version'],
['wlr-randr',''],
['xdpyinfo',''],
['xdriinfo',''],
+ ['Xfbdev','-version'],
['Xorg','-version'],
['xprop','-root'],
['xrandr',''],
+ ['xrandr','--prop'],
+ ['xrandr','--verbose'],
['Xvesa','-version'],
['Xvesa','-listmodes'],
['Xwayland','-version'],
);
run_commands(\@cmds,'display');
}
+
sub network_data {
print "Collecting networking data...\n";
-# no warnings 'uninitialized';
+ # no warnings 'uninitialized';
my @cmds = (
['ifconfig',''], # no version maybe in bsd, --version in linux
['ip','-Version'],
@@ -1968,6 +2048,7 @@ sub network_data {
);
run_commands(\@cmds,'network');
}
+
sub perl_modules {
print "Collecting Perl module data (this can take a while)...\n";
my @modules;
@@ -2010,6 +2091,7 @@ sub perl_modules {
print $fh $mods;
close $fh;
}
+
sub system_data {
print "Collecting system data...\n";
# has to run here because if null, error, list constructor throws fatal error
@@ -2079,6 +2161,7 @@ sub system_data {
['dmidecode','--version'],
['dmidecode',''],
['dmesg',''],
+ ['fruid_print',''], # elbrus
['gcc','--version'],
['getconf','-a'],
['getconf','-l'], # openbsd
@@ -2089,6 +2172,8 @@ sub system_data {
['ipmitool','-V'],# version
['ipmitool','sensor'],
['lscpu',''],# part of util-linux
+ ['lsmem',''],
+ ['lsmem','--all'],
['lspci','--version'],
['lspci',''],
['lspci','-k'],
@@ -2107,7 +2192,9 @@ sub system_data {
['lsusb',''],
['lsusb','-t'],
['lsusb','-v'],
+ ['ps',''],
['ps','aux'],
+ ['ps','auxww'],
['ps','-e'],
['ps','-p 1'],
['runlevel',''],
@@ -2129,6 +2216,11 @@ sub system_data {
['systemctl','list-units'],
['systemctl','list-units --type=target'],
['systemd-detect-virt',''],
+ ['tlp-stat',''], # no arg outputs all data
+ ['tlp-stat','-s'],
+ ['udevadm','info -e'],
+ ['udevadm','info -p /devices/virtual/dmi/id'],
+ ['udevadm','--version'],
['uname','-a'],
['upower','-e'],
['uptime',''],
@@ -2164,8 +2256,10 @@ sub system_files {
@files = (
'/etc/systemd/system/default.target',
'/proc/1/comm',
+ '/proc/bootdata', # elbrus
'/proc/cmdline',
'/proc/cpuinfo',
+ '/proc/iomem',
'/proc/meminfo',
'/proc/modules',
'/proc/net/arp',
@@ -2188,18 +2282,23 @@ sub system_files {
@files = main::globber('/sys/devices/system/cpu/vulnerabilities/*');
copy_files(\@files,'security');
}
+
## SELF EXECUTE FOR LOG/OUTPUT
sub run_self {
print "Creating $self_name output file now. This can take a few seconds...\n";
print "Starting $self_name from: $self_path\n";
+ my $args = '-FERfJLrploudma --slots --pkg --edid';
my $a = ($debugger{'arg'}) ? ' ' . $debugger{'arg'} : '';
my $i = ($option eq 'main-full')? ' -i' : '';
my $z = ($debugger{'filter'}) ? ' -z' : '';
my $w = ($debugger{'width'}) ? $debugger{'width'} : 120;
- my $aiz = "$i$z";
- $aiz =~ s/[\s-]//g;
- my $self_file = "$data_dir/$self_name-FERfJLrploudma$aiz-slots-pkg-edid-gpu-y$w.txt";
- my $cmd = "$self_path/$self_name -FERfJLrploudma$i$z$a --slots --pkg --edid --gpu --debug 10 -y $w > $self_file 2>&1";
+ $args = $debugger{'arg-use'} if $debugger{'arg-use'};
+ $args = "$args$a$i$z --debug 10 -y $w";
+ my $arg_string = $args;
+ $arg_string =~ s/\s//g;
+ my $self_file = "$data_dir/$self_name$arg_string.txt";
+ my $cmd = "$self_path/$self_name $args > $self_file 2>&1";
+ # print "Args: $args\nArg String: $arg_string\n";exit;
system($cmd);
copy($log_file, "$data_dir") or main::error_handler('copy-failed', "$log_file", "$!");
system("$self_path/$self_name --recommends -y 120 > $data_dir/$self_name-recommends-120.txt 2>&1");
@@ -2236,6 +2335,7 @@ sub copy_files {
}
}
}
+
sub run_commands {
my ($cmds,$type) = @_;
my $holder = '';
@@ -2266,6 +2366,7 @@ sub run_commands {
}
}
}
+
sub get_glob {
my ($type,$id,$glob) = @_;
my @files = main::globber($glob);
@@ -2285,6 +2386,7 @@ sub get_glob {
# print Data::Dumper::Dumper \@result;
main::writer("$data_dir/$type-data-$id-glob.txt",\@result);
}
+
sub write_data {
my ($data_ref, $type) = @_;
my ($empty,$error,$fh,$good,$name,$undefined,$value);
@@ -2309,6 +2411,7 @@ sub write_data {
}
}
}
+
## TOOLS FOR DIRECTORY TREE/LS/TRAVERSE; UPLOADER
sub build_tree {
my ($which) = @_;
@@ -2397,6 +2500,7 @@ sub directory_ls {
close $fh;
# print "$output\n";
}
+
sub proc_traverse_data {
print "Building /proc file list...\n";
# get rid pointless error:Can't cd to (/sys/kernel/) debug: Permission denied
@@ -2407,6 +2511,7 @@ sub proc_traverse_data {
process_proc_traverse();
@content = ();
}
+
sub process_proc_traverse {
my ($data,$fh,$result,$row,$sep);
my $proc_dir = "$data_dir/proc";
@@ -2414,7 +2519,7 @@ sub process_proc_traverse {
mkdir $proc_dir or main::error_handler('mkdir', "$proc_dir", "$!");
# @content = sort @content;
copy_files(\@content,'proc',$proc_dir);
-# foreach (@content){print "$_\n";}
+ # foreach (@content){print "$_\n";}
}
sub sys_traverse_data {
@@ -2427,6 +2532,7 @@ sub sys_traverse_data {
process_sys_traverse();
@content = ();
}
+
sub process_sys_traverse {
my ($data,$fh,$result,$row,$sep);
my $filename = "sys-data-parse.txt";
@@ -2459,6 +2565,7 @@ sub process_sys_traverse {
close $fh;
# print $fh "$result";
}
+
# perl compiler complains on start if prune = 1 used only once, so either
# do $File::Find::prune = 1 if !$File::Find::prune; OR use no warnings 'once'
sub wanted {
@@ -2512,8 +2619,8 @@ sub wanted {
push(@content, $File::Find::name);
return;
}
-# args: 1 - path to file to be uploaded
-# args: 2 - optional: alternate ftp upload url
+
+# args: 0: path to file to be uploaded; 1: optional: alternate ftp upload url
# NOTE: must be in format: ftp.site.com/incoming
sub upload_file {
my ($self, $ftp_url) = @_;
@@ -2528,12 +2635,10 @@ sub upload_file {
$domain =~ s/^ftp\.//;
$user = "anonymous";
$pass = "anonymous\@$domain";
-
print $line3;
print "Uploading to: $ftp_url\n";
# print "$host $domain $dir $user $pass\n";
print "File to be uploaded:\n$file_path\n";
-
if ($host && ($file_path && -e $file_path)){
# NOTE: important: must explicitly set to passive true/1
$ftp = Net::FTP->new($host, Debug => 0, Passive => 1) || main::error_handler('ftp-connect', $ftp->message);
@@ -2558,6 +2663,36 @@ sub upload_file {
}
}
+# see docs/optimization.txt
+sub ram_use {
+ my ($name, $ref) = @_;
+ printf "%-25s %5d %5d\n", $name, size($ref), total_size($ref);
+}
+
+# Used to create user visible debuugging output for complicated scenarios
+# args: 0: $type; 1: data (scalar or array/hash ref); 2: 0/1 dbg item;
+sub feature_debugger {
+ my ($type,$data,$b_switch) = @_;
+ my @result;
+ push(@result,'sub: ' . (caller(1))[3],'type: ' . $type);
+ if (ref $data eq 'ARRAY' || ref $data eq 'HASH'){
+ $data = Data::Dumper::Dumper $data;
+ }
+ else {
+ $data .= "\n" if !$b_log;
+ }
+ push(@result,'data: ' . $data);
+ # note, if --debug 3 and eg. --dbg 63 used, we want this to print out
+ if (!$b_log || ($b_switch && $debugger{'level'} < 10)){
+ unshift(@result,'------------------');
+ push(@result,"------------------\n") if $b_log;
+ print join("\n",@result);
+ }
+ else {
+ main::log_data('dump','feature dbg @result',\@result);
+ }
+}
+
# random tests for various issues
sub user_debug_test_1 {
# open(my $duped, '>&', STDOUT);
@@ -2573,16 +2708,11 @@ sub user_debug_test_1 {
# close $duped;
}
-# see docs/optimization.txt
-sub ram_use {
- my ($name, $ref) = @_;
- printf "%-25s %5d %5d\n", $name, size($ref), total_size($ref);
-}
-
#### -------------------------------------------------------------------
#### DOWNLOADER
#### -------------------------------------------------------------------
+# args: 0: download type; 1: url; 2: file; 3: [ua type string]
sub download_file {
my ($type, $url, $file,$ua) = @_;
my ($cmd,$args,$timeout) = ('','','');
@@ -2604,7 +2734,7 @@ sub download_file {
## NOTE: 1 is success, 0 false for Perl
if ($dl{'dl'} eq 'tiny'){
$cmd = "Using tiny: type: $type \nurl: $url \nfile: $file";
- $result = get_file($type, $url, $file);
+ $result = get_file_http_tiny($type,$url,$file,$ua);
$debug_data = ($type ne 'stdout') ? $result : 'Success: stdout data not null.';
}
# But: 0 is success, and 1 is false for these
@@ -2636,9 +2766,11 @@ sub download_file {
return $result;
}
-sub get_file {
- my ($type, $url, $file) = @_;
- my $tiny = HTTP::Tiny->new;
+sub get_file_http_tiny {
+ my ($type,$url,$file,$ua) = @_;
+ $ua = ($ua && $dl{'ua'}) ? $dl{'ua'} . $ua: '';
+ my %headers = ($ua) ? ('agent' => $ua) : ();
+ my $tiny = HTTP::Tiny->new(%headers);
# note: default is no verify, so default here actually is to verify unless overridden
$tiny->verify_SSL => 1 if !$use{'no-ssl'};
my $response = $tiny->get($url);
@@ -2685,6 +2817,7 @@ sub get_file {
sub set_downloader {
eval $start if $b_log;
my $quiet = '';
+ my $ua_raw = 's-tools/' . $self_name . '-';
$dl{'no-ssl'} = '';
$dl{'null'} = '';
$dl{'spider'} = '';
@@ -2692,7 +2825,11 @@ sub set_downloader {
# It is NOT part of core modules. IO::Socket::SSL is also required
# For some https connections so only use tiny as option if both present
if ($dl{'tiny'}){
- if (check_perl_module('HTTP::Tiny') && check_perl_module('IO::Socket::SSL')){
+ # this only for -U 4, grab file with ftp to avoid unsupported SSL issues
+ if ($use{'ftp-download'}){
+ $dl{'tiny'} = 0;
+ }
+ elsif (check_perl_module('HTTP::Tiny') && check_perl_module('IO::Socket::SSL')){
HTTP::Tiny->import;
IO::Socket::SSL->import;
$dl{'tiny'} = 1;
@@ -2707,6 +2844,7 @@ sub set_downloader {
$dl{'file'} = '';
$dl{'stdout'} = '';
$dl{'timeout'} = '';
+ $dl{'ua'} = $ua_raw;
}
elsif ($dl{'curl'} && check_program('curl')){
$quiet = '-s ' if !$dbg[1];
@@ -2715,7 +2853,7 @@ sub set_downloader {
$dl{'no-ssl'} = ' --insecure';
$dl{'stdout'} = " -L ${quiet}";
$dl{'timeout'} = ' -y ';
- $dl{'ua'} = ' -A ' . $dl_ua;
+ $dl{'ua'} = ' -A ' . $ua_raw;
}
elsif ($dl{'wget'} && check_program('wget')){
$quiet = '-q ' if !$dbg[1];
@@ -2725,7 +2863,7 @@ sub set_downloader {
$dl{'spider'} = " ${quiet}--spider";
$dl{'stdout'} = " $quiet -O -";
$dl{'timeout'} = ' -T ';
- $dl{'ua'} = ' -U ' . $dl_ua;
+ $dl{'ua'} = ' -U ' . $ua_raw;
}
elsif ($dl{'fetch'} && check_program('fetch')){
$quiet = '-q ' if !$dbg[1];
@@ -2734,6 +2872,7 @@ sub set_downloader {
$dl{'no-ssl'} = ' --no-verify-peer';
$dl{'stdout'} = " ${quiet}-o -";
$dl{'timeout'} = ' -T ';
+ $dl{'ua'} = ' --user-agent=' . $ua_raw;
}
# at least openbsd/netbsd
elsif ($bsd_type && check_program('ftp')){
@@ -2742,6 +2881,7 @@ sub set_downloader {
$dl{'null'} = ' 2>/dev/null';
$dl{'stdout'} = ' -o - ';
$dl{'timeout'} = '';
+ $dl{'ua'} = ' -U ' . $ua_raw;
}
else {
$dl{'dl'} = '';
@@ -2776,12 +2916,19 @@ sub error_handler {
$errno=10; $b_help=1; "Unsupported value: $two for option: $one" }
elsif ($err eq 'bad-arg-int'){
$errno=11; "Bad internal argument: $one" }
+ elsif ($err eq 'arg-modifier'){
+ $errno=10; $b_help=1; "Missing option: $one must be used with: $two" }
elsif ($err eq 'distro-block'){
$errno=20; "Option: $one has been disabled by the $self_name distribution maintainer." }
elsif ($err eq 'option-feature-incomplete'){
$errno=21; "Option: '$one' feature: '$two' has not been implemented yet." }
elsif ($err eq 'unknown-option'){
$errno=22; $b_help=1; "Unsupported option: $one" }
+ elsif ($err eq 'option-deprecated'){
+ $errno=23; $b_exit=0;
+ "The option: $one has been deprecated. Please use $two instead." }
+ elsif ($err eq 'option-removed'){
+ $errno=24; $b_help=1; "The option: $one has been remnoved. Please use $two instead." }
## Data
elsif ($err eq 'open-data'){
$errno=32; "Error opening data for reading: $one \nError: $two" }
@@ -2842,7 +2989,7 @@ sub error_handler {
};
print_line("Error $errno: $message\n");
if ($b_help){
- print_line("Check -h for correct parameters.\n");
+ print_line("Check -h for correct useage.\n");
}
if ($b_recommends){
print_line("See --recommends for more information.\n");
@@ -2867,30 +3014,32 @@ sub error_defaults {
## CheckRecommends
{
package CheckRecommends;
-my (@modules);
+my ($item_data,@modules,@pms);
+
sub run {
main::error_handler('not-in-irc', 'recommends') if $b_irc;
my (@data,@rows);
my $rows = [];
my $line = main::make_line();
- my $pm = get_pm();
- basic_data($rows,$line,$pm);
+ @pms = get_pms();
+ set_item_data();
+ basic_data($rows,$line);
if (!$bsd_type){
- check_items($rows,'required system directories',$line,$pm);
+ check_items($rows,'required system directories',$line);
}
- check_items($rows,'recommended system programs',$line,$pm);
- check_items($rows,'recommended display information programs',$line,$pm);
- check_items($rows,'recommended downloader programs',$line,$pm);
+ check_items($rows,'recommended system programs',$line);
+ check_items($rows,'recommended display information programs',$line);
+ check_items($rows,'recommended downloader programs',$line);
if (!$bsd_type){
- check_items($rows,'recommended kernel modules',$line,$pm);
+ check_items($rows,'recommended kernel modules',$line);
}
- check_items($rows,'recommended Perl modules',$line,$pm);
- check_items($rows,'recommended directories',$line,'');
- check_items($rows,'recommended files',$line,'');
+ check_items($rows,'recommended Perl modules',$line);
+ check_items($rows,'recommended directories',$line);
+ check_items($rows,'recommended files',$line);
push(@$rows,
['0', '', '', "$line"],
['0', '', '', "Ok, all done with the checks. Have a nice day."],
- ['0', '', '', " "],
+ ['0', '', '', ''],
);
# print Data::Dumper::Dumper $rows;
main::print_basic($rows);
@@ -2898,10 +3047,11 @@ sub run {
}
sub basic_data {
- my ($rows,$line,$pm_local) = @_;
+ my ($rows,$line) = @_;
my (@data,@rows);
+ $extra = 1; # needed for shell version
+ ShellData::set();
my $client = $client{'name-print'};
- $pm_local ||= 'N/A';
$client .= ' ' . $client{'version'} if $client{'version'};
my $default_shell = 'N/A';
if ($ENV{'SHELL'}){
@@ -2913,24 +3063,36 @@ sub basic_data {
push(@$rows,
['0', '', '', "$self_name will now begin checking for the programs it needs
to operate."],
- ['0', '', '', "" ],
+ ['0', '', '', ""],
['0', '', '', "Check $self_name --help or the man page (man $self_name)
- to see what options are available." ],
- ['0', '', '', "$line" ],
- ['0', '', '', "Test: core tools:" ],
- ['0', '', '', "" ],
- ['0', '', '', "Perl version: ^$]" ],
- ['0', '', '', "Current shell: " . $client ],
- ['0', '', '', "Default shell: " . $default_shell ],
- ['0', '', '', "sh links to: $sh_real" ],
- ['0', '', '', "Package manager: $pm_local" ],
+ to see what options are available."],
+ ['0', '', '', "$line"],
+ ['0', '', '', "Test: core tools:"],
+ ['0', '', '', ""],
+ ['0', '', '', "Perl version: ^$]"],
+ ['0', '', '', "Current shell: " . $client],
+ ['0', '', '', "Default shell: " . $default_shell],
+ ['0', '', '', "sh links to: $sh_real"],
);
+ if (scalar @pms == 0){
+ push(@$rows,['0', '', '', "Package manager(s): No supported PM(s) detected"]);
+ }
+ elsif (scalar @pms == 1){
+ push(@$rows,['0', '', '', "Package manager: $pms[0]"]);
+ }
+ else {
+ push(@$rows,['0', '', '', "Package managers detected:"]);
+ foreach my $pm (@pms){
+ push(@$rows,['0', '', '', " pm: $pm"]);
+ }
+ }
}
+
sub check_items {
- my ($rows,$type,$line,$pm) = @_;
+ my ($rows,$type,$line) = @_;
my (@data,@missing,$row,$result,@unreadable);
my ($b_dir,$b_file,$b_kernel_module,$b_perl_module,$b_program,$item);
- my ($about,$extra,$extra2,$extra3,$extra4,$info_os,$install) = ('','','','','','info','');
+ my ($about,$extra,$extra2,$extra3,$extra4,$info_os) = ('','','','','','info');
if ($type eq 'required system directories'){
@data = qw(/proc /sys);
$b_dir = 1;
@@ -2944,9 +3106,10 @@ sub check_items {
$info_os = 'info-bsd';
}
else {
- @data = qw(blockdev bt-adapter dig dmidecode doas fdisk file fruid_print
- hciconfig hddtemp ifconfig ip ipmitool ipmi-sensors lsblk lsusb lvs
- mdadm modinfo runlevel sensors smartctl strings sudo tree upower uptime);
+ @data = qw(blockdev bt-adapter btmgmt dig dmidecode doas fdisk file
+ fruid_print hciconfig hddtemp ifconfig ip ipmitool ipmi-sensors lsblk
+ lsusb lvs mdadm modinfo runlevel sensors smartctl strings sudo tree
+ udevadm upower uptime);
}
$b_program = 1;
$item = 'Program';
@@ -2955,11 +3118,13 @@ sub check_items {
}
elsif ($type eq 'recommended display information programs'){
if ($bsd_type){
- @data = qw(glxinfo wmctrl xdpyinfo xprop xdriinfo xrandr);
+ @data = qw(eglinfo glxinfo vulkaninfo wayland-info wmctrl xdpyinfo xprop
+ xdriinfo xrandr);
$info_os = 'info-bsd';
}
else {
- @data = qw(glxinfo wmctrl xdpyinfo xprop xdriinfo xrandr);
+ @data = qw(eglinfo glxinfo vulkaninfo wayland-info wmctrl xdpyinfo xprop
+ xdriinfo xrandr);
}
$b_program = 1;
$item = 'Program';
@@ -3001,7 +3166,7 @@ sub check_items {
";
}
elsif ($type eq 'recommended kernel modules'){
- @data = qw(amdgpu drivetemp nouveau);
+ @data = qw(amdgpu drivetemp nouveau radeon);
@modules = main::lister('/sys/module/');
$b_kernel_module = 1;
$extra2 = "GPU modules are only needed if applicable. NVMe drives do not need drivetemp
@@ -3039,22 +3204,21 @@ sub check_items {
push(@$rows,
['0', '', '', "$line" ],
['0', '', '', "Test: $type$extra:" ],
- ['0', '', '', " " ],
+ ['0', '', '', ''],
);
if ($extra2){
push(@$rows,
['0', '', '', $extra2],
- ['0', '', '', ' ']);
+ ['0', '', '', '']);
}
if ($extra3){
push(@$rows,
['0', '', '', $extra3],
- ['0', '', '', ' ']);
+ ['0', '', '', '']);
}
foreach my $item (@data){
- $install = '';
- $about = '';
- my $info = item_data($item);
+ undef $about;
+ my $info = $item_data->{$item};
$about = $info->{$info_os};
if (($b_dir && -d $item) || ($b_file && -r $item) ||
($b_program && main::check_program($item)) ||
@@ -3068,20 +3232,24 @@ sub check_items {
}
else {
$result = 'Missing';
- if (($b_program || $b_perl_module) && $pm){
- $info->{$pm} ||= 'N/A';
- $install = " ~ Install package: $info->{$pm}";
+ push(@missing,"$item");
+ if (($b_program || $b_perl_module) && @pms){
+ my @install;
+ foreach my $pm (@pms){
+ $info->{$pm} ||= 'N/A';
+ push(@install," $pm: $info->{$pm}");
+ }
+ push(@missing,@install);
}
- push(@missing, "$item$install");
}
$row = make_row($item,$about,$result);
push(@$rows, ['0', '', '', $row]);
}
- push(@$rows, ['0', '', '', " "]);
+ push(@$rows, ['0', '', '', '']);
if (@missing){
push(@$rows, ['0', '', '', "The following $type are missing$extra4:"]);
foreach (@missing){
- push(@$rows, ['0', '', '', "$item: $_"]);
+ push(@$rows, ['0', '', '', $_]);
}
}
if (@unreadable){
@@ -3095,10 +3263,9 @@ sub check_items {
}
}
-sub item_data {
- my ($type) = @_;
- my $data = {
- # Directory Data
+sub set_item_data {
+ $item_data = {
+ ## Directory Data ##
'/dev' => {
'info' => '-l,-u,-o,-p,-P,-D disk partition data',
},
@@ -3126,7 +3293,7 @@ sub item_data {
'/sys/class/hwmon' => {
'info' => '-s sensor data (fallback if no lm-sensors)',
},
- # File Data
+ ## File Data ##
'/etc/lsb-release' => {
'info' => '-S distro version data (older version)',
},
@@ -3163,9 +3330,9 @@ sub item_data {
'/var/run/dmesg.boot' => {
'info' => '-D,-d disk data',
},
- ## Kernel Module Data
+ ## Kernel Module Data ##
'amdgpu' => {
- 'info' => '-s AMD GPU sensor data (newer AMD GPUs)',
+ 'info' => '-s, -G AMD GPU sensor data (newer GPUs)',
'info-bsd' => '',
},
'drivetemp' => {
@@ -3173,59 +3340,72 @@ sub item_data {
'info-bsd' => '',
},
'nouveau' => {
- 'info' => '-s Nvidia GPU sensor data (if using free driver)',
+ 'info' => '-s, -G Nvidia GPU sensor data (if using free driver)',
+ 'info-bsd' => '',
+ },
+ 'radeon' => {
+ 'info' => '-s, -G AMD GPU sensor data (older GPUs)',
'info-bsd' => '',
},
## START PACKAGE MANAGER BLOCK ##
- # Note: see inxi-perl branch for details: docs/recommends-package-manager.txt
+ # BSD only tools do not list package manager install names
+ ## Programs-System ##
+ # Note: see inxi-perl branch for details: docs/inxi-custom-recommends.txt
# System Tools
'blockdev' => {
'info' => '--admin -p/-P (filesystem blocksize)',
'info-bsd' => '',
'apt' => 'util-linux',
'pacman' => 'util-linux',
+ 'pkgtool' => 'util-linux',
'rpm' => 'util-linux',
},
'bt-adapter' => {
- 'info' => '-E bluetooth data (if no hciconfig)',
+ 'info' => '-E bluetooth data (if no hciconfig, btmgmt)',
'info-bsd' => '',
'apt' => 'bluez-tools',
'pacman' => 'bluez-tools',
+ 'pkgtool' => '', # needs to be built by user
'rpm' => 'bluez-tools',
},
+ 'btmgmt' => {
+ 'info' => '-E bluetooth data (if no hciconfig)',
+ 'info-bsd' => '',
+ 'apt' => 'bluez',
+ 'pacman' => 'bluez-utils',
+ 'pkgtool' => '', # needs to be built by user
+ 'rpm' => 'bluez',
+ },
'curl' => {
'info' => '-i (if no dig); -w,-W; -U',
'info-bsd' => '-i (if no dig); -w,-W; -U',
'apt' => 'curl',
'pacman' => 'curl',
+ 'pkgtool' => 'curl',
'rpm' => 'curl',
},
'camcontrol' => {
'info' => '',
'info-bsd' => '-R; -D; -P. Get actual gptid /dev path',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'dig' => {
'info' => '-i wlan IP',
'info-bsd' => '-i wlan IP',
'apt' => 'dnsutils',
'pacman' => 'dnsutils',
+ 'pkgtool' => 'bind',
'rpm' => 'bind-utils',
},
'disklabel' => {
'info' => '',
'info-bsd' => '-j, -p, -P; -R; -o (Open/NetBSD+derived)',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'dmidecode' => {
'info' => '-M if no sys machine data; -m',
'info-bsd' => '-M if null sysctl; -m; -B if null sysctl',
'apt' => 'dmidecode',
'pacman' => 'dmidecode',
+ 'pkgtool' => 'dmidecode',
'rpm' => 'dmidecode',
},
'doas' => {
@@ -3233,6 +3413,7 @@ sub item_data {
'info-bsd' => '-Dx hddtemp-user; -o file-user',
'apt' => 'doas',
'pacman' => 'doas',
+ 'pkgtool' => ' opendoas',
'rpm' => 'doas',
},
'fdisk' => {
@@ -3240,55 +3421,47 @@ sub item_data {
'info-bsd' => '-D partition scheme',
'apt' => 'fdisk',
'pacman' => 'util-linux',
+ 'pkgtool' => 'util-linux',
'rpm' => 'util-linux',
},
'fetch' => {
'info' => '',
'info-bsd' => '-i (if no dig); -w,-W; -U',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'file' => {
'info' => '-o unmounted file system (if no lsblk)',
'info-bsd' => '-o unmounted file system',
'apt' => 'file',
'pacman' => 'file',
+ 'pkgtool' => 'file',
'rpm' => 'file',
},
'ftp' => {
'info' => '',
'info-bsd' => '-i (if no dig); -w,-W; -U',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'fruid_print' => {
'info' => '-M machine data, Elbrus only',
'info-bsd' => '',
'apt' => '',
'pacman' => '',
+ 'pkgtool' => '',
'rpm' => '',
},
'glabel' => {
'info' => '',
'info-bsd' => '-R; -D; -P. Get actual gptid /dev path',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'gpart' => {
'info' => '',
'info-bsd' => '-p,-P; -R; -o (FreeBSD+derived)',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'hciconfig' => {
'info' => '-E bluetooth data (deprecated, good report)',
'info-bsd' => '',
'apt' => 'bluez',
'pacman' => 'bluez-utils-compat (frugalware: bluez-utils)',
+ 'pkgtool' => 'bluez',
'rpm' => 'bluez-utils',
},
'hddtemp' => {
@@ -3296,6 +3469,7 @@ sub item_data {
'info-bsd' => '-Dx show hdd temp',
'apt' => 'hddtemp',
'pacman' => 'hddtemp',
+ 'pkgtool' => 'hddtemp',
'rpm' => 'hddtemp',
},
'ifconfig' => {
@@ -3303,6 +3477,7 @@ sub item_data {
'info-bsd' => '-i ip LAN',
'apt' => 'net-tools',
'pacman' => 'net-tools',
+ 'pkgtool' => 'net-tools',
'rpm' => 'net-tools',
},
'ip' => {
@@ -3310,6 +3485,7 @@ sub item_data {
'info-bsd' => '',
'apt' => 'iproute',
'pacman' => 'iproute2',
+ 'pkgtool' => 'iproute2',
'rpm' => 'iproute',
},
'ipmi-sensors' => {
@@ -3317,6 +3493,7 @@ sub item_data {
'info-bsd' => '',
'apt' => 'freeipmi-tools',
'pacman' => 'freeipmi',
+ 'pkgtool' => 'freeipmi',
'rpm' => 'freeipmi',
},
'ipmitool' => {
@@ -3324,6 +3501,7 @@ sub item_data {
'info-bsd' => '-s IPMI sensors (servers)',
'apt' => 'ipmitool',
'pacman' => 'ipmitool',
+ 'pkgtool' => 'ipmitool',
'rpm' => 'ipmitool',
},
'lsblk' => {
@@ -3331,6 +3509,7 @@ sub item_data {
'info-bsd' => '-o unmounted file system',
'apt' => 'util-linux',
'pacman' => 'util-linux',
+ 'pkgtool' => 'util-linux',
'rpm' => 'util-linux-ng',
},
'lvs' => {
@@ -3338,6 +3517,7 @@ sub item_data {
'info-bsd' => '',
'apt' => 'lvm2',
'pacman' => 'lvm2',
+ 'pkgtool' => 'lvm2',
'rpm' => 'lvm2',
},
'lsusb' => {
@@ -3345,6 +3525,7 @@ sub item_data {
'info-bsd' => '',
'apt' => 'usbutils',
'pacman' => 'usbutils',
+ 'pkgtool' => 'usbutils',
'rpm' => 'usbutils',
},
'mdadm' => {
@@ -3352,6 +3533,7 @@ sub item_data {
'info-bsd' => '',
'apt' => 'mdadm',
'pacman' => 'mdadm',
+ 'pkgtool' => 'mdadm',
'rpm' => 'mdadm',
},
'modinfo' => {
@@ -3359,34 +3541,27 @@ sub item_data {
'info-bsd' => '',
'apt' => 'module-init-tools',
'pacman' => 'module-init-tools',
+ 'pkgtool' => 'kmod (earlier: module-init-tools)',
'rpm' => 'module-init-tools',
},
'pciconfig' => {
'info' => '',
'info-bsd' => '-A,-E,-G,-N pci devices (FreeBSD+derived)',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'pcictl' => {
'info' => '',
'info-bsd' => '-A,-E,-G,-N pci devices (NetBSD+derived)',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'pcidump' => {
'info' => '',
'info-bsd' => '-A,-E,-G,-N pci devices (OpenBSD+derived, doas/su)',
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'runlevel' => {
'info' => '-I fallback to Perl',
'info-bsd' => '',
'apt' => 'systemd or sysvinit',
'pacman' => 'systemd',
+ 'pkgtool' => 'sysvinit',
'rpm' => 'systemd or sysvinit',
},
'sensors' => {
@@ -3394,6 +3569,7 @@ sub item_data {
'info-bsd' => '',
'apt' => 'lm-sensors',
'pacman' => 'lm-sensors',
+ 'pkgtool' => 'lm_sensors',
'rpm' => 'lm-sensors',
},
'smartctl' => {
@@ -3401,41 +3577,50 @@ sub item_data {
'info-bsd' => '-Da advanced data',
'apt' => 'smartmontools',
'pacman' => 'smartmontools',
+ 'pkgtool' => 'smartmontools',
'rpm' => 'smartmontools',
},
'strings' => {
'info' => '-I sysvinit version',
'info-bsd' => '',
'apt' => 'binutils',
- 'pacman' => '?',
- 'rpm' => '?',
+ 'pacman' => 'binutils',
+ 'pkgtool' => 'binutils',
+ 'rpm' => 'binutils',
},
'sudo' => {
'info' => '-Dx hddtemp-user; -o file-user (try doas!)',
'info-bsd' => '-Dx hddtemp-user; -o file-user (alt for doas)',
'apt' => 'sudo',
'pacman' => 'sudo',
+ 'pkgtool' => 'sudo',
'rpm' => 'sudo',
},
'sysctl' => {
'info' => '',
'info-bsd' => '-C; -I; -m; -tm',
- 'apt' => '?',
- 'pacman' => '?',
- 'rpm' => '?',
},
'tree' => {
'info' => '--debugger 20,21 /sys tree',
'info-bsd' => '--debugger 20,21 /sys tree',
'apt' => 'tree',
'pacman' => 'tree',
+ 'pkgtool' => 'tree',
'rpm' => 'tree',
},
+ 'udevadm' => {
+ 'info' => '-m ram data for non-root, or no dmidecode',
+ 'apt' => 'udev (non-systemd: eudev)',
+ 'pacman' => 'systemd',
+ 'pkgtool' => 'eudev',
+ 'rpm' => 'udev (fedora: systemd-udev)',
+ },
'upower' => {
'info' => '-sx attached device battery info',
'info-bsd' => '-sx attached device battery info',
'apt' => 'upower',
'pacman' => 'upower',
+ 'pkgtool' => 'upower',
'rpm' => 'upower',
},
'uptime' => {
@@ -3443,42 +3628,64 @@ sub item_data {
'info-bsd' => '-I uptime',
'apt' => 'procps',
'pacman' => 'procps',
+ 'pkgtool' => 'procps',
'rpm' => 'procps',
},
'usbconfig' => {
'info' => '',
'info-bsd' => '-A; -E; -G; -J; -N; (FreeBSD+derived, doas/su)',
- 'apt' => 'usbutils',
- 'pacman' => 'usbutils',
- 'rpm' => 'usbutils',
},
'usbdevs' => {
'info' => '',
'info-bsd' => '-A; -E; -G; -J; -N; (Open/NetBSD+derived)',
- 'apt' => 'usbutils',
- 'pacman' => 'usbutils',
- 'rpm' => 'usbutils',
},
'wget' => {
'info' => '-i (if no dig); -w,-W; -U',
'info-bsd' => '-i (if no dig); -w,-W; -U',
'apt' => 'wget',
'pacman' => 'wget',
+ 'pkgtool' => 'wget',
'rpm' => 'wget',
},
- # Display Tools
+ ## Programs-Display ##
+ 'eglinfo' => {
+ 'info' => '-G X11/Wayland EGL info',
+ 'info-bsd' => '-G X11/Wayland EGL info',
+ 'apt' => 'mesa-utils (or: mesa-utils-extra)',
+ 'pacman' => 'mesa-utils',
+ 'pkgtool' => 'mesa',
+ 'rpm' => 'egl-utils (SUSE: Mesa-demo-egl)',
+ },
'glxinfo' => {
- 'info' => '-G (X) glx info',
- 'info-bsd' => '-G (X) glx info',
+ 'info' => '-G X11 GLX info',
+ 'info-bsd' => '-G X11 GLX info',
'apt' => 'mesa-utils',
- 'pacman' => 'mesa-demos',
- 'rpm' => 'glx-utils (SUSE: Mesa-demo-x)',
+ 'pacman' => 'mesa-utils',
+ 'pkgtool' => 'mesa',
+ 'rpm' => 'glx-utils (Fedora: glx-utils; SUSE: Mesa-demo-x)',
+ },
+ 'vulkaninfo' => {
+ 'info' => '-G Vulkan API info',
+ 'info-bsd' => '-G Vulkan API info',
+ 'apt' => 'vulkan-tools',
+ 'pacman' => 'vulkan-tools',
+ 'pkgtool' => 'vulkan-tools',
+ 'rpm' => 'vulkan-demos (Fedora: vulkan-tools; SUSE: vulkan-demos)',
+ },
+ 'wayland-info' => {
+ 'info' => '-G Wayland data (not for X)',
+ 'info-bsd' => '-G Wayland data (not for X)',
+ 'apt' => 'wayland-utils',
+ 'pacman' => 'wayland-utils',
+ 'pkgtool' => 'wayland-utils',
+ 'rpm' => 'wayland-utils',
},
'wmctrl' => {
'info' => '-S active window manager (fallback)',
- 'info-bsd' => '-S active window managerr (fallback)',
+ 'info-bsd' => '-S active window manager (fallback)',
'apt' => 'wmctrl',
'pacman' => 'wmctrl',
+ 'pkgtool' => 'wmctrl',
'rpm' => 'wmctrl',
},
'xdpyinfo' => {
@@ -3486,63 +3693,72 @@ sub item_data {
'info-bsd' => '-G (X) Screen resolution, dpi; -Ga Screen size',
'apt' => 'X11-utils',
'pacman' => 'xorg-xdpyinfo',
- 'rpm' => 'xorg-x11-utils (SUSE/Fedora?: xdpyinfo)',
+ 'pkgtool' => 'xdpyinfo',
+ 'rpm' => 'xorg-x11-utils (SUSE/Fedora: xdpyinfo)',
},
'xdriinfo' => {
'info' => '-G (X) DRI driver (if missing, fallback to Xorg log)',
'info-bsd' => '-G (X) DRI driver (if missing, fallback to Xorg log',
'apt' => 'X11-utils',
'pacman' => 'xorg-xdriinfo',
- 'rpm' => 'xorg-x11-utils (SUSE/Fedora?: xdriinfo)',
+ 'pkgtool' => 'xdriinfo',
+ 'rpm' => 'xorg-x11-utils (SUSE/Fedora: xdriinfo)',
},
'xprop' => {
'info' => '-S (X) desktop data',
'info-bsd' => '-S (X) desktop data',
'apt' => 'X11-utils',
'pacman' => 'xorg-xprop',
- 'rpm' => 'x11-utils',
+ 'pkgtool' => 'xprop',
+ 'rpm' => 'x11-utils (Fedora/SUSE: xprop)',
},
'xrandr' => {
'info' => '-G (X) monitors(s) resolution; -Ga monitor data',
'info-bsd' => '-G (X) monitors(s) resolution; -Ga monitor data',
'apt' => 'x11-xserver-utils',
'pacman' => 'xrandr',
- 'rpm' => 'x11-server-utils (Fedora: xrandr)',
+ 'pkgtool' => 'xrandr',
+ 'rpm' => 'x11-server-utils (SUSE/Fedora: xrandr)',
},
- # Perl Modules
+ ## Perl Modules ##
'Cpanel::JSON::XS' => {
- 'info' => '--output json (faster than JSON::PP).',
- 'info-bsd' => '--output json (faster than JSON::PP).',
+ 'info' => '-G wayland, --output json (faster).',
+ 'info-bsd' => '-G wayland, --output json (faster).',
'apt' => 'libcpanel-json-xs-perl',
'pacman' => 'perl-cpanel-json-xs',
+ 'pkgtool' => 'perl-Cpanel-JSON-XS',
'rpm' => 'perl-Cpanel-JSON-XS',
},
'File::Copy' => {
- 'info' => '--debug 20-22 - required to run debugger.',
- 'info-bsd' => '--debug 20-22 - required to run debugger.',
+ 'info' => '--debug 20-22 - required for debugger.',
+ 'info-bsd' => '--debug 20-22 - required for debugger.',
'apt' => 'Core Modules',
'pacman' => 'Core Modules',
+ 'pkgtool' => 'Core Modules',
'rpm' => 'perl-File-Copy',
},
'File::Find' => {
- 'info' => '--debug 20-22 - required to run debugger.',
- 'info-bsd' => '--debug 20-22 - required to run debugger.',
+ 'info' => '--debug 20-22 - required for debugger.',
+ 'info-bsd' => '--debug 20-22 - required for debugger.',
'apt' => 'Core Modules',
'pacman' => 'Core Modules',
+ 'pkgtool' => 'Core Modules',
'rpm' => 'perl-File-Find',
},
'File::Spec::Functions' => {
- 'info' => '--debug 20-22 - required to run debugger.',
- 'info-bsd' => '--debug 20-22 - required to run debugger.',
+ 'info' => '--debug 20-22 - required for debugger.',
+ 'info-bsd' => '--debug 20-22 - required for debugger.',
'apt' => 'Core Modules',
'pacman' => 'Core Modules',
+ 'pkgtool' => 'Core Modules',
'rpm' => 'Core Modules',
},
'HTTP::Tiny' => {
'info' => '-U; -w,-W; -i (if dig not installed).',
'info-bsd' => '-U; -w,-W; -i (if dig not installed)',
- 'apt' => 'libhttp-tiny-perl',
+ 'apt' => 'libhttp-tiny-perl (Core Modules >= 5.014)',
'pacman' => 'Core Modules',
+ 'pkgtool' => 'perl-http-tiny (Core Modules >= 5.014)',
'rpm' => 'Perl-http-tiny',
},
'IO::Socket::SSL' => {
@@ -3550,20 +3766,23 @@ sub item_data {
'info-bsd' => '-U; -w,-W; -i (if dig not installed)',
'apt' => 'libio-socket-ssl-perl',
'pacman' => 'perl-io-socket-ssl',
+ 'pkgtool' => 'perl-IO-Socket-SSL', # maybe in core modules
'rpm' => 'perl-IO-Socket-SSL',
},
'JSON::PP' => {
- 'info' => '--output json (in CoreModules, but slower).',
- 'info-bsd' => '--output json (in CoreModules, but slower).',
- 'apt' => 'libjson-pp-perl',
- 'pacman' => 'perl-json-pp',
+ 'info' => '-G wayland, --output json (in CoreModules, slower).',
+ 'info-bsd' => '-G wayland, --output json (in CoreModules, slower).',
+ 'apt' => 'libjson-pp-perl (Core Modules >= 5.014)',
+ 'pacman' => 'perl-json-pp (Core Modules >= 5.014)',
+ 'pkgtool' => 'Core Modules >= 5.014',
'rpm' => 'perl-JSON-PP',
},
'JSON::XS' => {
- 'info' => '--output json (legacy).',
- 'info-bsd' => '--output json (legacy).',
+ 'info' => '-G wayland, --output json (legacy).',
+ 'info-bsd' => '-G wayland, --output json (legacy).',
'apt' => 'libjson-xs-perl',
'pacman' => 'perl-json-xs',
+ 'pkgtool' => 'perl-JSON-XS',
'rpm' => 'perl-JSON-XS',
},
'Net::FTP' => {
@@ -3571,27 +3790,23 @@ sub item_data {
'info-bsd' => '--debug 21,22',
'apt' => 'Core Modules',
'pacman' => 'Core Modules',
+ 'pkgtool' => 'Core Modules',
'rpm' => 'Core Modules',
},
'OpenBSD::Pledge' => {
'info' => "$self_name Perl pledge support.",
'info-bsd' => "$self_name Perl pledge support.",
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'OpenBSD::Unveil' => {
'info' => "Experimental: $self_name Perl unveil support.",
'info-bsd' => "Experimental: $self_name Perl unveil support.",
- 'apt' => '',
- 'pacman' => '',
- 'rpm' => '',
},
'Time::HiRes' => {
'info' => '-C cpu sleep (not required); --debug timers',
'info-bsd' => '-C cpu sleep (not required); --debug timers',
'apt' => 'Core Modules',
'pacman' => 'Core Modules',
+ 'pkgtool' => 'Core Modules',
'rpm' => 'perl-Time-HiRes',
},
'XML::Dumper' => {
@@ -3599,26 +3814,33 @@ sub item_data {
'info-bsd' => '--output xml - Crude and raw.',
'apt' => 'libxml-dumper-perl',
'pacman' => 'perl-xml-dumper',
+ 'pkgtool' => '', # package does not appear to exist
'rpm' => 'perl-XML-Dumper',
},
## END PACKAGE MANAGER BLOCK ##
};
- return $data->{$type};
}
-sub get_pm {
- my ($pm) = ('');
+
+sub get_pms {
+ my @pms = ();
# support maintainers of other pm types using custom lists
if (main::check_program('dpkg')){
- $pm = 'apt';
+ push(@pms,'apt');
+ }
+ if (main::check_program('pacman')){
+ push(@pms,'pacman');
}
- elsif (main::check_program('pacman')){
- $pm = 'pacman';
+ # assuming netpkg uses installpkg as backend
+ if (main::check_program('installpkg')){
+ push(@pms,'pkgtool');
}
- elsif (main::check_program('rpm')){
- $pm = 'rpm';
+ # rpm needs to go last because it's sometimes available on other pm systems
+ if (main::check_program('rpm')){
+ push(@pms,'rpm');
}
- return $pm;
+ return @pms;
}
+
# note: end will vary, but should always be treated as longest value possible.
# expected values: Present/Missing
sub make_row {
@@ -3638,7 +3860,7 @@ sub make_row {
# Duplicates the functionality of awk to allow for one liner
# type data parsing. note: -1 corresponds to awk NF
-# args 1: array of data; 2: search term; 3: field result; 4: separator
+# args: 0: array of data; 1: search term; 2: field result; 3: separator
# correpsonds to: awk -F='separator' '/search/ {print $2}' <<< @data
# array is sent by reference so it must be dereferenced
# NOTE: if you just want the first row, pass it \S as search string
@@ -3667,7 +3889,7 @@ sub awk {
return $result;
}
-# $1 - Perl module to check
+# 0: Perl module to check
sub check_perl_module {
my ($module) = @_;
my $b_present = 0;
@@ -3676,7 +3898,7 @@ sub check_perl_module {
return $b_present;
}
-# arg: 1 - string or path to search gneerated @paths data for.
+# args: 0: string or path to search gneerated @paths data for.
# note: a few nano seconds are saved by using raw $_[0] for program
sub check_program {
(grep { return "$_/$_[0]" if -e "$_/$_[0]"} @paths)[0];
@@ -3691,7 +3913,7 @@ sub cleanup {
}
}
-# args: $1, $2, version numbers to compare by turning them to strings
+# args: 0,1: version numbers to compare by turning them to strings
# note that the structure of the two numbers is expected to be fairly
# similar, otherwise it may not work perfectly.
sub compare_versions {
@@ -3724,9 +3946,9 @@ sub count_dir_files {
return $count;
}
-# args: 1 - the string to get piece of
-# 2 - the position in string, starting at 1 for 0 index.
-# 3 - the separator, default is ' '
+# args: 0: the string to get piece of
+# 1: the position in string, starting at 1 for 0 index.
+# 2: the separator, default is ' '
sub get_piece {
eval $start if $b_log;
my ($string, $num, $sep) = @_;
@@ -3741,8 +3963,8 @@ sub get_piece {
}
}
-# arg: 1 - command to turn into an array; 2 - optional: splitter
-# 3 - optionsl, strip and clean data
+# args: 0: command to turn into an array; 1: optional: splitter;
+# 2: strip-trim, clean data, remove empty lines
# similar to reader() except this creates an array of data
# by lines from the command arg
sub grabber {
@@ -3765,7 +3987,7 @@ sub grabber {
return ($type eq 'arr') ? @rows : \@rows;
}
-# args: 1 - string value to glob
+# args: 0: string value to glob
sub globber {
eval $start if $b_log;
my @files = <$_[0]>;
@@ -3794,7 +4016,7 @@ sub is_numeric {
# gets array ref, which may be undefined, plus join string
# this helps avoid debugger print errors when we are printing arrays
# which we don't know are defined or not null.
-# args: 1 - array ref; 2 - join string; 3 - default value, optional
+# args: 0: array ref; 1: join string; 2: default value, optional
sub joiner {
my ($arr,$join,$default) = @_;
$default ||= '';
@@ -3851,504 +4073,9 @@ sub load_json {
eval $end if $b_log;
}
-# returns array of: 0: program print name 1: program version
-# args: 1: program values id 2: program version string
-# 3: $extra level. Note that StartClient runs BEFORE -x levels are set!
-# Only use this function when you only need the name/version data returned
-sub program_data {
- eval $start if $b_log;
- my ($values_id,$version_id,$level) = @_;
- my (@data,$path,@program_data);
- $level = 0 if !$level;
- # print "val_id: $values_id ver_id:$version_id lev:$level ex:$extra\n";
- $version_id = $values_id if !$version_id;
- @data = program_values($values_id);
- if ($data[3]){
- $program_data[0] = $data[3];
- # programs that have no version method return 0 0 for index 1 and 2
- if ($extra >= $level && $data[1] && $data[2]){
- $program_data[1] = program_version($version_id,$data[0],
- $data[1],$data[2],$data[5],$data[6],$data[7],$data[8]);
- }
- }
- $program_data[0] ||= '';
- $program_data[1] ||= '';
- eval $end if $b_log;
- return @program_data;
-}
-
-# It's almost 1000 times slower to load these each time program_values is called!!
-sub set_program_values {
- %program_values = (
- ## Clients ##
- 'bitchx' => ['bitchx',2,'','BitchX',1,0,0,'',''],# special
- 'finch' => ['finch',2,'-v','Finch',1,1,0,'',''],
- 'gaim' => ['[0-9.]+',2,'-v','Gaim',0,1,0,'',''],
- 'ircii' => ['[0-9.]+',3,'-v','ircII',1,1,0,'',''],
- 'irssi' => ['irssi',2,'-v','Irssi',1,1,0,'',''],
- 'irssi-text' => ['irssi',2,'-v','Irssi',1,1,0,'',''],
- 'konversation' => ['konversation',2,'-v','Konversation',0,0,0,'',''],
- 'kopete' => ['Kopete',2,'-v','Kopete',0,0,0,'',''],
- 'kvirc' => ['[0-9.]+',2,'-v','KVIrc',0,0,1,'',''], # special
- 'pidgin' => ['[0-9.]+',2,'-v','Pidgin',0,1,0,'',''],
- 'quassel' => ['',1,'-v','Quassel [M]',0,0,0,'',''], # special
- 'quasselclient' => ['',1,'-v','Quassel',0,0,0,'',''],# special
- 'quasselcore' => ['',1,'-v','Quassel (core)',0,0,0,'',''],# special
- 'gribble' => ['^Supybot',2,'--version','Gribble',1,0,0,'',''],# special
- 'limnoria' => ['^Supybot',2,'--version','Limnoria',1,0,0,'',''],# special
- 'supybot' => ['^Supybot',2,'--version','Supybot',1,0,0,'',''],# special
- 'weechat' => ['[0-9.]+',1,'-v','WeeChat',1,0,0,'',''],
- 'weechat-curses' => ['[0-9.]+',1,'-v','WeeChat',1,0,0,'',''],
- 'xchat-gnome' => ['[0-9.]+',2,'-v','X-Chat-Gnome',1,1,0,'',''],
- 'xchat' => ['[0-9.]+',2,'-v','X-Chat',1,1,0,'',''],
- ## Desktops / wm / compositors ##
- '2bwm' => ['^2bwm',0,'0','2bWM',0,1,0,'',''], # unverified/based on mcwm
- '3dwm' => ['^3dwm',0,'0','3Dwm',0,1,0,'',''], # unverified
- '5dwm' => ['^5dwm',0,'0','5Dwm',0,1,0,'',''], # unverified
- '9wm' => ['^9wm',3,'-version','9wm',0,1,0,'',''],
- 'aewm' => ['^aewm',3,'--version','aewm',0,1,0,'',''],
- 'aewm++' => ['^Version:',2,'-version','aewm++',0,1,0,'',''],
- 'afterstep' => ['^afterstep',3,'--version','AfterStep',0,1,0,'',''],
- 'amiwm' => ['^amiwm',0,'0','AmiWM',0,1,0,'',''], # no version
- 'antiwm' => ['^antiwm',0,'0','AntiWM',0,1,0,'',''], # no version known
- 'asc' => ['^asc',0,'0','asc',0,1,0,'',''],
- 'awc' => ['^awc',0,'0','awc',0,1,0,'',''], # unverified
- 'awesome' => ['^awesome',2,'--version','awesome',0,1,0,'',''],
- 'beryl' => ['^beryl',0,'0','Beryl',0,1,0,'',''], # unverified; legacy
- 'blackbox' => ['^Blackbox',2,'--version','Blackbox',0,1,0,'',''],
- 'bspwm' => ['^\S',1,'-v','bspwm',0,1,0,'',''],
- 'budgie-desktop' => ['^budgie-desktop',2,'--version','Budgie',0,1,0,'',''],
- 'budgie-wm' => ['^budgie',0,'0','budgie-wm',0,1,0,'',''],
- 'cage' => ['^cage',0,'0','Cage',0,1,0,'',''], # unverified
- 'cagebreak' => ['^Cagebreak',3,'-v','Cagebreak',0,1,0,'',''],
- 'calmwm' => ['^calmwm',0,'0','CalmWM',0,1,0,'',''], # unverified
- 'cardboard' => ['^cardboard',0,'0','Cardboard',0,1,0,'',''], # unverified
- 'catwm' => ['^catwm',0,'0','catwm',0,1,0,'',''], # unverified
- 'cde' => ['^cde',0,'0','CDE',0,1,0,'',''], # unverified
- 'chameleonwm' => ['^chameleon',0,'0','ChameleonWM',0,1,0,'',''], # unverified
- 'cinnamon' => ['^cinnamon',2,'--version','Cinnamon',0,1,0,'',''],
- 'clfswm' => ['^clsfwm',0,'0','clfswm',0,1,0,'',''], # no version
- 'comfc' => ['^comfc',0,'0','comfc',0,1,0,'',''], # unverified
- 'compiz' => ['^compiz',2,'--version','Compiz',0,1,0,'',''],
- 'compton' => ['^\d',1,'--version','Compton',0,1,0,'',''],
- 'ctwm' => ['^\S',1,'-version','ctwm',0,1,0,'',''],
- 'cwm' => ['^cwm',0,'0','CWM',0,1,0,'',''], # no version
- 'dcompmgr' => ['^dcompmgr',0,'0','dcompmgr',0,1,0,'',''], # unverified
- 'deepin' => ['^Version',2,'file','Deepin',0,100,'=','','/etc/deepin-version'], # special
- 'deepin-metacity' => ['^metacity',2,'--version','Deepin-Metacity',0,1,0,'',''],
- 'deepin-mutter' => ['^mutter',2,'--version','Deepin-Mutter',0,1,0,'',''],
- 'deepin-wm' => ['^gala',0,'0','DeepinWM',0,1,0,'',''], # no version
- 'dwc' => ['^dwc',0,'0','dwc',0,1,0,'',''], # unverified
- 'dwl' => ['^dwl',0,'0','dwl',0,1,0,'',''], # unverified
- 'dwm' => ['^dwm',1,'-v','dwm',0,1,1,'^dwm-',''],
- 'echinus' => ['^echinus',1,'-v','echinus',0,1,1,'',''], # echinus-0.4.9 (c)...
- # only listed here for compositor values, version data comes from xprop
- 'enlightenment' => ['^enlightenment',0,'0','enlightenment',0,1,0,'',''], # no version, yet?
- 'epd-wm' => ['^epd-wm',0,'0','epd-wm',0,1,0,'',''], # unverified
- 'evilwm' => ['evilwm',3,'-V','evilwm',0,1,0,'',''],# might use full path in match
- 'feathers' => ['^feathers',0,'0','feathers',0,1,0,'',''], # unverified
- 'fenestra' => ['^fenestra',0,'0','fenestra',0,1,0,'',''], # unverified
- 'fireplace' => ['^fireplace',0,'0','fireplace',0,1,0,'',''], # unverified
- 'fluxbox' => ['^fluxbox',2,'-v','Fluxbox',0,1,0,'',''],
- 'flwm' => ['^flwm',0,'0','FLWM',0,0,1,'',''], # no version
- # openbsd changed: version string: [FVWM[[main] Fvwm.. sigh, and outputs to stderr. Why?
- 'fvwm' => ['^fvwm',2,'-version','FVWM',0,1,0,'',''],
- 'fvwm1' => ['^Fvwm',3,'-version','FVWM1',0,1,1,'',''],
- 'fvwm2' => ['^fvwm',2,'--version','FVWM2',0,1,0,'',''],
- 'fvwm3' => ['^fvwm',2,'--version','FVWM3',0,1,0,'',''],
- 'fvwm95' => ['^fvwm',2,'--version','FVWM95',0,1,1,'',''],
- 'fvwm-crystal' => ['^fvwm',2,'--version','FVWM-Crystal',0,0,0,'',''], # for print name fvwm
- 'gala' => ['^gala',0,'0','gala',0,1,0,'',''], # pantheon wm: super slow result, 2, '--version' works?
- 'gamescope' => ['^gamescope',0,'0','Gamescope',0,1,0,'',''], # unverified
- 'glass' => ['^glass',3,'-v','Glass',0,1,0,'',''],
- 'gnome' => ['^gnome',3,'--version','GNOME',0,1,0,'',''], # no version, print name
- 'gnome-about' => ['^gnome',3,'--version','GNOME',0,1,0,'',''],
- 'gnome-shell' => ['^gnome',3,'--version','gnome-shell',0,1,0,'',''],
- 'greenfield' => ['^greenfield',0,'0','Greenfield',0,1,0,'',''], # unverified
- 'grefson' => ['^grefson',0,'0','Grefson',0,1,0,'',''], # unverified
- 'hackedbox' => ['^hackedbox',2,'-version','HackedBox',0,1,0,'',''], # unverified, assume blackbox
- # note, herbstluftwm when launched with full path returns full path in version string
- 'herbstluftwm' => ['herbstluftwm',2,'--version','herbstluftwm',0,1,0,'',''],
- 'hikari' => ['^hikari',0,'0','hikari',0,1,0,'',''], # unverified
- 'hopalong' => ['^hopalong',0,'0','Hopalong',0,1,0,'',''], # unverified
- 'hyprland' => ['^hyprland',0,'0','Hyprland',0,1,0,'',''], # unverified
- 'i3' => ['^i3',3,'--version','i3',0,1,0,'',''],
- 'icewm' => ['^icewm',2,'--version','IceWM',0,1,0,'',''],
- 'inaban' => ['^inaban',0,'0','inaban',0,1,0,'',''], # unverified
- 'instantwm' => ['^instantwm',1,'-v','instantWM',0,1,1,'^instantwm-?(instantos-?)?',''],
- 'ion3' => ['^ion3',0,'--version','Ion3',0,1,0,'',''], # unverified; also shell called ion
- 'japokwm' => ['^japokwm',0,'0','japokwm',0,1,0,'',''], # unverified
- 'jbwm' => ['jbwm',3,'-v','JBWM',0,1,0,'',''], # might use full path in match
- 'jwm' => ['^jwm',2,'--version','JWM',0,1,0,'',''],
- 'kded' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,1,0,'\sDevelopment Platform',''],
- 'kded1' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,1,0,'\sDevelopment Platform',''],
- 'kded2' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,1,0,'\sDevelopment Platform',''],
- 'kded3' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,1,0,'\sDevelopment Platform',''],
- 'kded4' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,1,0,'\sDevelopment Platform',''],
- 'kiwmi' => ['^kwimi',0,'0','kiwmi',0,1,0,'',''], # unverified
- 'ksmcon' => ['^ksmcon',0,'0','ksmcon',0,1,0,'',''],# no version
- 'kwin' => ['^kwin',0,'0','kwin',0,1,0,'',''],# no version
- 'kwin_wayland' => ['^kwin_wayland',0,'0','kwin_wayland',0,1,0,'',''],# no version
- 'kwin_x11' => ['^kwin_x11',0,'0','kwin_x11',0,1,0,'',''],# no version
- 'kwinft' => ['^kwinft',0,'0','KWinFT',0,1,0,'',''], # unverified
- 'labwc' => ['^labwc',0,'0','LabWC',0,1,0,'',''], # unverified
- 'laikawm' => ['^laikawm',0,'0','LaikaWM',0,1,0,'',''], # unverified
- 'larswm' => ['^larswm',2,'-v','larswm',0,1,1,'',''],
- 'leftwm' => ['^leftwm',0,'0','LeftWM',0,1,0,'',''],# no version, in CHANGELOG
- 'liri' => ['^liri',0,'0','liri',0,1,0,'',''],
- 'lipstick' => ['^lipstick',0,'0','Lipstick',0,1,0,'',''], # unverified
- 'liri' => ['^liri',0,'0','liri',0,1,0,'',''], # unverified
- 'lumina-desktop' => ['^\S',1,'--version','Lumina',0,1,1,'',''],
- 'lwm' => ['^lwm',0,'0','lwm',0,1,0,'',''], # no version
- 'lxpanel' => ['^lxpanel',2,'--version','LXDE',0,1,0,'',''],
- # command: lxqt-panel
- 'lxqt-panel' => ['^lxqt-panel',2,'--version','LXQt',0,1,0,'',''],
- 'lxqt-variant' => ['^lxqt-panel',0,'0','LXQt-Variant',0,1,0,'',''],
- 'lxsession' => ['^lxsession',0,'0','lxsession',0,1,0,'',''],
- 'mahogany' => ['^mahogany',0,'0','Mahogany',0,1,0,'',''], # unverified
- 'manokwari' => ['^manokwari',0,'0','Manokwari',0,1,0,'',''],
- 'marina' => ['^marina',0,'0','Marina',0,1,0,'',''], # unverified
- 'marco' => ['^marco',2,'--version','marco',0,1,0,'',''],
- 'matchbox' => ['^matchbox',0,'0','Matchbox',0,1,0,'',''],
- 'matchbox-window-manager' => ['^matchbox',2,'--help','Matchbox',0,0,0,'',''],
- 'mate-about' => ['^MATE[[:space:]]DESKTOP',-1,'--version','MATE',0,1,0,'',''],
- # note, mate-session when launched with full path returns full path in version string
- 'mate-session' => ['mate-session',-1,'--version','MATE',0,1,0,'',''],
- 'maze' => ['^maze',0,'0','Maze',0,1,0,'',''], # unverified
- 'mcwm' => ['^mcwm',0,'0','mcwm',0,1,0,'',''], # unverified/see 2bwm
- 'metacity' => ['^metacity',2,'--version','Metacity',0,1,0,'',''],
- 'metisse' => ['^metisse',0,'0','metisse',0,1,0,'',''],
- 'mini' => ['^Mini',5,'--version','Mini',0,1,0,'',''],
- 'mir' => ['^mir',0,'0','mir',0,1,0,'',''],# unverified
- 'moblin' => ['^moblin',0,'0','moblin',0,1,0,'',''],# unverified
- 'monsterwm' => ['^monsterwm',0,'0','monsterwm',0,1,0,'',''],# unverified
- 'motorcar' => ['^motorcar',0,'0','motorcar',0,1,0,'',''],# unverified
- 'muffin' => ['^muffin',2,'--version','Muffin',0,1,0,'',''],
- 'musca' => ['^musca',0,'-v','Musca',0,1,0,'',''], # unverified
- 'mutter' => ['^mutter',2,'--version','Mutter',0,1,0,'',''],
- 'mwm' => ['^mwm',0,'0','MWM',0,1,0,'',''],# no version
- 'nawm' => ['^nawm',0,'0','nawm',0,1,0,'',''],# unverified
- 'newm' => ['^newm',0,'0','newm',0,1,0,'',''], # unverified
- 'notion' => ['^.',1,'--version','Notion',0,1,0,'',''],
- 'nscde' => ['^nscde',0,'0','NsCDE',0,1,0,'',''], # unverified
- 'nucleus' => ['^nucleus',0,'0','Nucleus',0,1,0,'',''], # unverified
- 'openbox' => ['^openbox',2,'--version','Openbox',0,1,0,'',''],
- 'orbital' => ['^orbital',0,'0','Orbital',0,1,0,'',''],# unverified
- 'pantheon' => ['^pantheon',0,'0','Pantheon',0,1,0,'',''],# no version
- 'papyros' => ['^papyros',0,'0','papyros',0,1,0,'',''],# no version
- 'pekwm' => ['^pekwm',3,'--version','PekWM',0,1,0,'',''],
- 'penrose' => ['^penrose',0,'0','Penrose',0,1,0,'',''],# no version?
- 'perceptia' => ['^perceptia',0,'0','perceptia',0,1,0,'',''],
- 'phoc' => ['^phoc',0,'0','phoc',0,1,0,'',''], # unverified
- 'picom' => ['^\S',1,'--version','Picom',0,1,0,'^v',''],
- 'plasmashell' => ['^plasmashell',2,'--version','KDE Plasma',0,1,0,'',''],
- 'pywm' => ['^pywm',0,'0','pywm',0,1,0,'',''], # unverified
- 'qtile' => ['^',1,'--version','Qtile',0,1,0,'',''],
- 'qvwm' => ['^qvwm',0,'0','qvwm',0,1,0,'',''], # unverified
- 'razor-session' => ['^razor',0,'0','Razor-Qt',0,1,0,'',''],
- 'ratpoison' => ['^ratpoison',2,'--version','Ratpoison',0,1,0,'',''],
- 'river' => ['^river',0,'0','River',0,1,0,'',''], # unverified
- 'rootston' => ['^rootston',0,'0','rootston',0,1,0,'',''], # unverified, wlroot ref
- 'rustland' => ['^rustland',0,'0','rustland',0,1,0,'',''], # unverified
- 'sawfish' => ['^sawfish',3,'--version','Sawfish',0,1,0,'',''],
- 'scrotwm' => ['^scrotwm.*welcome.*',5,'-v','scrotwm',0,1,1,'',''],
- 'simulavr' => ['simulavr^',0,'0','SimulaVR',0,1,0,'',''], # unverified
- 'skylight' => ['^skylight',0,'0','Skylight',0,1,0,'',''], # unverified
- 'sommelier' => ['^sommelier',0,'0','sommelier',0,1,0,'',''], # unverified
- 'snapwm' => ['^snapwm',0,'0','snapwm',0,1,0,'',''], # unverified
- 'spectrwm' => ['^spectrwm.*welcome.*wm',5,'-v','spectrwm',0,1,1,'',''],
- # out of stump, 2 --version, but in tries to start new wm instance endless hang
- 'stumpwm' => ['^SBCL',0,'--version','StumpWM',0,1,0,'',''], # hangs when run in wm
- 'sway' => ['^sway',3,'-v','sway',0,1,0,'',''],
- 'swc' => ['^swc',0,'0','swc',0,1,0,'',''], # unverified
- 'swvkc' => ['^swvkc',0,'0','swvkc',0,1,0,'',''], # unverified
- 'tabby' => ['^tabby',0,'0','Tabby',0,1,0,'',''], # unverified
- 'taiwins' => ['^taiwins',0,'0','taiwins',0,1,0,'',''], # unverified
- 'tinybox' => ['^tinybox',0,'0','tinybox',0,1,0,'',''], # unverified
- 'tinywl' => ['^tinywl',0,'0','TinyWL',0,1,0,'',''], # unverified
- 'tinywm' => ['^tinywm',0,'0','TinyWM',0,1,0,'',''], # no version
- 'trinkster' => ['^trinkster',0,'0','Trinkster',0,1,0,'',''], # unverified
- 'tvtwm' => ['^tvtwm',0,'0','tvtwm',0,1,0,'',''], # unverified
- 'twin' => ['^Twin:',2,'--version','Twin',0,0,0,'',''],
- 'twm' => ['^twm',0,'0','TWM',0,1,0,'',''], # no version
- 'ukui' => ['^ukui-session',2,'--version','UKUI',0,1,0,'',''],
- 'ukwm' => ['^ukwm',2,'--version','ukwm',0,1,0,'',''],
- 'unagi' => ['^\S',1,'--version','unagi',0,1,0,'',''],
- 'unity' => ['^unity',2,'--version','Unity',0,1,0,'',''],
- 'unity-system-compositor' => ['^unity-system-compositor',2,'--version',
- 'unity-system-compositor (mir)',0,0,0,'',''],
- 'uwm' => ['^uwm',0,'0','UWM',0,1,0,'',''], # unverified
- 'velox' => ['^velox',0,'0','Velox',0,1,0,'',''], # unverified
- 'vimway' => ['^vimway',0,'0','vimway',0,1,0,'',''], # unverified
- 'vivarium' => ['^vivarium',0,'0','Vivarium',0,1,0,'',''], # unverified
- 'wavy' => ['^wavy',0,'0','wavy',0,1,0,'',''], # unverified
- 'waybox' => ['^way',0,'0','waybox',0,1,0,'',''], # unverified
- 'waycooler' => ['^way',3,'--version','way-cooler',0,1,0,'',''],
- 'way-cooler' => ['^way',3,'--version','way-cooler',0,1,0,'',''],
- 'wayfire' => ['^\d',1,'--version','wayfire',0,1,0,'',''], # -version/--version
- 'wayhouse' => ['^wayhouse',0,'0','wayhouse',0,1,0,'',''], # unverified
- 'waymonad' => ['^waymonad',0,'0','waymonad',0,1,0,'',''], # unverified
- 'westeros' => ['^westeros',0,'0','westeros',0,1,0,'',''], # unverified
- 'westford' => ['^westford',0,'0','westford',0,1,0,'',''], # unverified
- 'weston' => ['^weston',0,'0','Weston',0,1,0,'',''], # unverified
- 'windowlab' => ['^windowlab',2,'-about','WindowLab',0,1,0,'',''],
- 'wingo' => ['^wingo',0,'0','Wingo',0,1,0,'',''], # unverified
- 'wio' => ['^wio',0,'0','Wio',0,1,0,'',''], # unverified
- 'wio' => ['^wio\+',0,'0','wio+',0,1,0,'',''], # unverified
- 'wm2' => ['^wm2',0,'0','wm2',0,1,0,'',''], # no version
- 'wmaker' => ['^Window[[:space:]]*Maker',-1,'--version','WindowMaker',0,1,0,'',''],
- 'wmfs' => ['^wmfs',0,'0','WMFS',0,1,0,'',''], # unverified
- 'wmfs2' => ['^wmfs',0,'0','WMFS',0,1,0,'',''], # unverified
- 'wmii' => ['^wmii',1,'-v','wmii',0,1,0,'^wmii[234]?-',''], # wmii is wmii3
- 'wmii2' => ['^wmii2',1,'--version','wmii2',0,1,0,'^wmii[234]?-',''],
- 'wmx' => ['^wmx',0,'0','wmx',0,1,0,'',''], # no version
- 'wxrc' => ['^wx',0,'0','',0,1,0,'WXRC',''], # unverified
- 'wxrd' => ['^wx',0,'0','',0,1,0,'WXRD',''], # unverified
- 'xcompmgr' => ['^xcompmgr',0,'0','xcompmgr',0,1,0,'',''], # no version
- 'xfce4-panel' => ['^xfce4-panel',2,'--version','Xfce',0,1,0,'',''],
- 'xfce5-panel' => ['^xfce5-panel',2,'--version','Xfce',0,1,0,'',''],
- 'xfdesktop' => ['xfdesktop[[:space:]]version',5,'--version','Xfce',0,1,0,'',''],
- # command: xfdesktop
- 'xfdesktop-toolkit' => ['Built[[:space:]]with[[:space:]]GTK',4,'--version','Gtk',0,1,0,'',''],
- # ' This is xfwm4 version 4.16.1 (revision 5f61a84ad) for Xfce 4.16'
- 'xfwm' => ['xfwm[3-8]? version',5,'--version','xfwm',0,1,0,'^^\s+',''],# unverified
- 'xfwm4' => ['xfwm4? version',5,'--version','xfwm',0,1,0,'^^\s+',''],
- 'xfwm5' => ['xfwm5? version',5,'--version','xfwm',0,1,0,'^^\s+',''], # unverified
- 'xmonad' => ['^xmonad',2,'--version','XMonad',0,1,0,'',''],
- 'xuake' => ['^xuake',0,'0','xuake',0,1,0,'',''], # unverified
- 'yeahwm' => ['^yeahwm',0,'--version','YeahWM',0,1,0,'',''], # unverified
- ## Toolkits ##
- 'gtk-launch' => ['^\S',1,'--version','GTK',0,1,0,'',''],
- 'qmake' => ['^^Using Qt version',4,'--version','Qt',0,0,0,'',''],
- 'qtdiag' => ['^qt',2,'--version','Qt',0,1,0,'',''],
- ## Display Managers (dm) ##
- 'brzdm' => ['^brzdm version',3,'-v','brzdm',0,1,0,'',''], # unverified, slim fork
- 'cdm' => ['^cdm',0,'0','CDM',0,1,0,'',''],
- # might be xlogin, unknown output for -V
- 'clogin' => ['^clogin',0,'-V','clogin',0,1,0,'',''], # unverified, maybe xlogin
- 'emptty' => ['^emptty',0,'0','EMPTTY',0,1,0,'',''], # unverified
- 'entrance' => ['^entrance',0,'0','Entrance',0,1,0,'',''],
- 'gdm' => ['^gdm',2,'--version','GDM',0,1,0,'',''],
- 'gdm3' => ['^gdm',2,'--version','GDM3',0,1,0,'',''],
- 'greetd' => ['^greetd',0,'0','greetd',0,1,0,'',''], # no version
- 'kdm' => ['^kdm',0,'0','KDM',0,1,0,'',''],
- 'kdm3' => ['^kdm',0,'0','KDM',0,1,0,'',''],
- 'kdmctl' => ['^kdm',0,'0','KDM',0,1,0,'',''],
- 'ldm' => ['^ldm',0,'0','LDM',0,1,0,'',''],
- 'lightdm' => ['^lightdm',2,'--version','LightDM',0,1,1,'',''],
- 'lxdm' => ['^lxdm',0,'0','LXDM',0,1,0,'',''],
- 'ly' => ['^ly',3,'--version','Ly',0,1,0,'',''],
- 'mdm' => ['^mdm',0,'0','MDM',0,1,0,'',''],
- 'mlogin' => ['^mlogin',0,'0','mlogin',0,1,0,'',''], # unverified
- 'nodm' => ['^nodm',0,'0','nodm',0,1,0,'',''],
- 'pcdm' => ['^pcdm',0,'0','PCDM',0,1,0,'',''],
- 'qingy' => ['^qingy',0,'0','qingy',0,1,0,'',''], # unverified
- 'sddm' => ['^sddm',0,'0','SDDM',0,1,0,'',''],
- 'slim' => ['slim version',3,'-v','SLiM',0,1,0,'',''],
- 'slimski' => ['slimski version',3,'-v','slimski',0,1,0,'',''], # slim fork
- 'tbsm' => ['^tbsm',0,'0','tbsm',0,1,0,'',''], # unverified
- 'tdm' => ['^tdm',0,'0','TDM',0,1,0,'',''],
- 'udm' => ['^udm',0,'0','udm',0,1,0,'',''],
- 'wdm' => ['^wdm',0,'0','WINGs DM',0,1,0,'',''],
- 'xdm' => ['^xdm',0,'0','XDM',0,1,0,'',''],
- 'xdmctl' => ['^xdm',0,'0','XDM',0,1,0,'',''],# opensuse/redhat may use this to start real dm
- 'xenodm' => ['^xenodm',0,'0','xenodm',0,1,0,'',''],
- 'xlogin' => ['^xlogin',0,'-V','xlogin',0,1,0,'',''], # unverified, probably clogin
- ## Shells - not checked: ion, eshell ##
- ## See ShellData::shell_test() for unhandled but known shells
- 'ash' => ['',3,'pkg','ash',1,0,0,'',''], # special; dash precursor
- 'bash' => ['^GNU[[:space:]]bash',4,'--version','Bash',1,1,0,'',''],
- 'busybox' => ['^busybox',0,'0','BusyBox',1,0,0,'',''], # unverified, hush/ash likely
- 'cicada' => ['^\s*version',2,'cmd','cicada',1,1,0,'',''], # special
- 'csh' => ['^tcsh',2,'--version','csh',1,1,0,'',''], # mapped to tcsh often
- 'dash' => ['',3,'pkg','DASH',1,0,0,'',''], # no version, pkg query
- 'elvish' => ['^\S',1,'--version','Elvish',1,0,0,'',''],
- 'fish' => ['^fish',3,'--version','fish',1,0,0,'',''],
- 'fizsh' => ['^fizsh',3,'--version','FIZSH',1,0,0,'',''],
- # ksh/lksh/loksh/mksh/posh//pdksh need to print their own $VERSION info
- 'ksh' => ['^\S',1,'cmd','ksh',1,0,0,'^(Version|.*KSH)\s*',''], # special
- 'ksh93' => ['^\S',1,'cmd','ksh93',1,0,0,'^(Version|.*KSH)\s*',''], # special
- 'lksh' => ['^\S',1,'cmd','lksh',1,0,0,'^.*KSH\s*',''], # special
- 'loksh' => ['^\S',1,'cmd','loksh',1,0,0,'^.*KSH\s*',''], # special
- 'mksh' => ['^\S',1,'cmd','mksh',1,0,0,'^.*KSH\s*',''], # special
- 'nash' => ['^nash',0,'0','Nash',1,0,0,'',''], # unverified; rc based [no version]
- 'oh' => ['^oh',0,'0','Oh',1,0,0,'',''], # no version yet
- 'oil' => ['^Oil',3,'--version','Oil',1,1,0,'',''], # could use cmd $OIL_SHELL
- 'osh' => ['^osh',3,'--version','OSH',1,1,0,'',''], # precursor of oil
- 'pdksh' => ['^\S',1,'cmd','pdksh',1,0,0,'^.*KSH\s*',''], # special, in ksh family
- 'posh' => ['^\S',1,'cmd','posh',1,0,0,'',''], # special, in ksh family
- 'tcsh' => ['^tcsh',2,'--version','tcsh',1,1,0,'',''], # enhanced csh
- 'xonsh' => ['^xonsh',1,'--version','xonsh',1,0,0,'^xonsh[\/-]',''],
- 'yash' => ['^Y',5,'--version','yash',1,0,0,'',''],
- 'zsh' => ['^zsh',2,'--version','Zsh',1,0,0,'',''],
- ## Tools ##
- 'clang' => ['clang',3,'--version','Clang',1,0,0,'',''],
- 'gcc' => ['^gcc',3,'--version','GCC',1,0,0,'',''],
- 'gcc-apple' => ['Apple[[:space:]]LLVM',2,'--version','LLVM',1,0,0,'',''],
- 'sudo' => ['^Sudo',3,'-V','Sudo',1,1,0,'',''], # sudo pre 1.7 does not have --version
- );
-}
-
-# returns array of:
-# 0 - match string; 1 - search number; 2 - version string [alt: file];
-# 3 - Print name; 4 - console 0/1;
-# 5 - 0/1 exit version loop at 1 [alt: if version=file replace value with \s];
-# 6 - 0/1 write to stderr [alt: if version=file, path for file]
-# 7 - replace regex for further cleanup; 8 - extra data
-# note: setting index 1 or 2 to 0 will trip flags to not do version
-# arg: 1 - program lower case name
-sub program_values {
- my ($app) = @_;
- my (@program_data);
- set_program_values() if !%program_values;
- if (defined $program_values{$app}){
- @program_data = @{$program_values{$app}};
- }
- # my $debug = Dumper \@program_data;
- log_data('dump',"Program Data",\@program_data) if $b_log;
- return @program_data;
-}
-
-# args: 1 - desktop/app command for --version; 2 - search string;
-# 3 - space print number; 4 - [optional] version arg: -v, version, etc
-# 5 - [optional] exit first find 0/1; 6 - [optional] 0/1 stderr output
-# 7 - replace regex; 8 - extra data
-sub program_version {
- eval $start if $b_log;
- my ($app,$search,$num,$version,$exit,$stderr,$replace,$extra) = @_;
- my ($b_no_space,$cmd,$line,$output);
- my $version_nu = '';
- my $count = 0;
- my $app_name = $app;
- $app_name =~ s%^.*/%%;
- # print "app: $app :: appname: $app_name\n";
- $exit ||= 100; # basically don't exit ever
- $version ||= '--version';
- # adjust to array index, not human readable
- $num-- if (defined $num && $num > 0);
- # konvi in particular doesn't like using $ENV{'PATH'} as set, so we need
- # to always assign the full path if it hasn't already been done
- if ($version ne 'file' && $app !~ /^\//){
- if (my $program = check_program($app)){
- $app = $program;
- }
- else {
- log_data('data',"$app not found in path.") if $b_log;
- return 0;
- }
- }
- if ($version eq 'file'){
- return 0 unless $extra && -r $extra;
- my @data = reader($extra,'strip');
- @data = map {s/$stderr/ /;$_} @data if $stderr; # $stderr is the splitter
- $output = join("\n", @data);
- $cmd = '';
- }
- # These will mostly be shells that require running the shell command -c to get info data
- elsif ($version eq 'cmd'){
- ($cmd,$b_no_space) = program_version_cmd($app,$app_name,$extra);
- return 0 if !$cmd;
- }
- # slow: use pkg manager to get version, avoid unless you really want version
- elsif ($version eq 'pkg'){
- ($cmd,$search) = program_version_pkg($app_name);
- return 0 if !$cmd;
- }
- # note, some wm/apps send version info to stderr instead of stdout
- elsif ($stderr){
- $cmd = "$app $version 2>&1";
- }
- else {
- $cmd = "$app $version 2>/dev/null";
- }
- log_data('data',"version: $version num: $num search: $search command: $cmd") if $b_log;
- # special case, in rare instances version comes from file
- if ($version ne 'file'){
- $output = qx($cmd);
- log_data('data',"output: $output") if $b_log;
- }
- # print "cmd: $cmd\noutput:\n$output\n";
- # sample: dwm-5.8.2, ©.. etc, why no space? who knows. Also get rid of v in number string
- # xfce, and other, output has , in it, so dump all commas and parentheses
- if ($output){
- open(my $ch, '<', \$output) or error_handler('open-data',"$cmd", "$!");
- while (<$ch>){
- #chomp;
- last if $count > $exit;
- if ($_ =~ /$search/i){
- $_ = trimmer($_);
- # print "loop: $_ :: num: $num\n";
- $_ =~ s/$replace//i if $replace;
- $_ =~ s/\s/_/g if $b_no_space; # needed for some items with version > 1 word
- my @data = split(/\s+/, $_);
- $version_nu = $data[$num];
- last if ! defined $version_nu;
- # some distros add their distro name before the version data, which
- # breaks version detection. A quick fix attempt is to just add 1 to $num
- # to get the next value.
- $version_nu = $data[$num+1] if $data[$num+1] && $version_nu =~ /version/i;
- $version_nu =~ s/(\([^)]+\)|,|"|\||\(|\))//g if $version_nu;
- # trim off leading v but only when followed by a number
- $version_nu =~ s/^v([0-9])/$1/i if $version_nu;
- # print "$version_nu\n";
- last;
- }
- $count++;
- }
- close $ch if $ch;
- }
- log_data('data',"Program version: $version_nu") if $b_log;
- eval $end if $b_log;
- return $version_nu;
-}
-# print program_version('bash', 'bash', 4) . "\n";
-
-# returns ($cmdd, $b_no_space)
-# ksh: Version JM 93t+ 2010-03-05 [OR] Version A 2020.0.0
-# mksh: @(#)MIRBSD KSH R56 2018/03/09; lksh/pdksh: @(#)LEGACY KSH R56 2018/03/09
-# loksh: @(#)PD KSH v5.2.14 99/07/13.2; posh: 0.13.2
-sub program_version_cmd {
- eval $start if $b_log;
- my ($app,$app_name,$extra) = @_;
- my @data = ('',0);
- if ($app_name eq 'cicada'){
- $data[0] = $app . ' -c "' . $extra . '" 2>/dev/null';}
- elsif ($app_name =~ /^(|l|lo|m|pd)ksh(93)?$/){
- $data[0] = $app . ' -c \'printf %s "$KSH_VERSION"\' 2>/dev/null';
- $data[1] = 1;}
- elsif ($app_name eq 'posh'){
- $data[0] = $app . ' -c \'printf %s "$POSH_VERSION"\' 2>/dev/null'}
- # print "$data[0] :: $data[1]\n";
- eval $end if $b_log;
- return @data;
-}
-
-# returns $cmd, $search
-sub program_version_pkg {
- eval $start if $b_log;
- my ($app) = @_;
- my ($program,@data);
- # note: version $num is 3 in dpkg-query/pacman/rpm, which is convenient
- if ($program = check_program('dpkg-query')){
- $data[0] = "$program -W -f='\${Package}\tversion\t\${Version}\n' $app 2>/dev/null";
- $data[1] = "^$app\\b";
- }
- elsif ($program = check_program('pacman')){
- $data[0] = "$program -Q --info $app 2>/dev/null";
- $data[1] = '^Version';
- }
- elsif ($program = check_program('rpm')){
- $data[0] = "$program -qi --nodigest --nosignature $app 2>/dev/null";
- $data[1] = '^Version';
- }
- # print "$data[0] :: $data[1]\n";
- eval $end if $b_log;
- return @data;
-}
-
-# arg: 1 - full file path, returns array of file lines.
-# 2 - optionsl, strip and clean data
-# 3 - optional: undef|arr|ref|index return specific index, if it exists, else undef
+# args: 0: full file path, returns array of file lines;
+# 1: optionsl, strip and clean data;
+# 2: optional: undef|arr|ref|index return specific index, if it exists, else undef
# note: chomp has to chomp the entire action, not just <$fh>
sub reader {
eval $start if $b_log;
@@ -4380,7 +4107,7 @@ sub reader {
return $rows[$type];
}
-# args: 1 - the file to create if not exists
+# args: 0: the file to create if not exists
sub toucher {
my $file = shift;
if (! -e $file){
@@ -4389,7 +4116,7 @@ sub toucher {
}
# calling it trimmer to avoid conflicts with existing trim stuff
-# arg: 1 - string to be right left trimmed. Also slices off \n so no chomp needed
+# args: 0: string to be right left trimmed. Also slices off \n so no chomp needed
# this thing is super fast, no need to log its times etc, 0.0001 seconds or less
sub trimmer {
# eval $start if $b_log;
@@ -4399,14 +4126,14 @@ sub trimmer {
return $str;
}
-# args: 1 - array, by ref, modifying by ref
+# args: 0: array, by ref, modifying by ref
# send array, assign to hash, changed array by reference, uniq values only.
sub uniq {
my %seen;
@{$_[0]} = grep !$seen{$_}++, @{$_[0]};
}
-# arg: 1 file full path to write to; 2 - array ref or scalar of data to write.
+# args: 0: file full path to write to; 1: array ref or scalar of data to write.
# note: turning off strict refs so we can pass it a scalar or an array reference.
sub writer {
my ($path, $content) = @_;
@@ -4428,22 +4155,19 @@ sub writer {
#### UPDATER
#### -------------------------------------------------------------------
-# arg 1: type to return
+# args: 0: type to return
sub get_defaults {
my ($type) = @_;
my %defaults = (
'ftp-upload' => 'ftp.smxi.org/incoming',
- 'inxi-branch-1' => 'https://github.com/smxi/inxi/raw/one/',
- 'inxi-branch-2' => 'https://github.com/smxi/inxi/raw/two/',
- 'inxi-dev' => 'https://smxi.org/in/',
- 'inxi-main' => 'https://github.com/smxi/inxi/raw/master/',
- 'inxi-pinxi' => 'https://github.com/smxi/inxi/raw/inxi-perl/',
- 'inxi-man' => "https://smxi.org/in/$self_name.1",
- 'inxi-man-gh' => "https://github.com/smxi/inxi/raw/master/$self_name.1",
- 'pinxi-man' => "https://smxi.org/in/$self_name.1",
- 'pinxi-man-gh' => "https://github.com/smxi/inxi/raw/inxi-perl/$self_name.1",
+ 'inxi-branch-1' => 'https://codeberg.org/smxi/inxi/raw/one/',
+ 'inxi-branch-2' => 'https://codeberg.org/smxi/inxi/raw/two/',
+ "$self_name-dev" => 'https://smxi.org/in/',
+ "$self_name-dev-ftp" => 'ftp://ftp.smxi.org/outgoing/',
+ "inxi-main" => 'https://codeberg.org/smxi/inxi/raw/master/',
+ 'pinxi-main' => 'https://codeberg.org/smxi/pinxi/raw/master/',
);
- if (exists $defaults{$type}){
+ if ($defaults{$type}){
return $defaults{$type};
}
else {
@@ -4451,9 +4175,9 @@ sub get_defaults {
}
}
-# args: 1 - download url, not including file name; 2 - string to print out
-# 3 - update type option
-# note that 1 must end in / to properly construct the url path
+# args: 0: download url, not including file name; 1: string to print out
+# 2: update type option
+# note that 0 must end in / to properly construct the url path
sub update_me {
eval $start if $b_log;
my ($self_download,$download_id) = @_;
@@ -4463,7 +4187,6 @@ sub update_me {
$self_path =~ s/\/$//; # dirname sometimes ends with /, sometimes not
$self_download =~ s/\/$//; # dirname sometimes ends with /, sometimes not
my $full_self_path = "$self_path/$self_name";
-
if ($b_irc){
error_handler('not-in-irc', "-U/--update")
}
@@ -4480,7 +4203,6 @@ sub update_me {
$output = '';
$self_download = "$self_download/$self_name";
$file_contents = download_file('stdout', $self_download);
-
# then do the actual download
if ($file_contents){
# make sure the whole file got downloaded and is in the variable
@@ -4499,7 +4221,7 @@ sub update_me {
print $output;
$output = '';
if ($use{'man'}){
- update_man($download_id);
+ update_man($self_download,$download_id);
}
else {
print "Skipping man download because branch version is being used.\n";
@@ -4519,7 +4241,7 @@ sub update_me {
sub update_man {
eval $start if $b_log;
- my ($download_id) = @_;
+ my ($self_download,$download_id) = @_;
my $man_file_location = set_man_location();
my $man_file_path = "$man_file_location/$self_name.1" ;
my ($file_contents,$man_file_url,$output,$program) = ('','','','');
@@ -4545,13 +4267,8 @@ sub update_man {
print "Required program gzip not found. Unable to install man page.\n";
return 0;
}
- # first choice is inxi.1/pinxi.1 from gh, second from smxi.org
- if ($download_id ne 'dev server'){
- $man_file_url = get_defaults($self_name . '-man-gh');
- }
- else {
- $man_file_url = get_defaults($self_name . '-man');
- }
+ # first choice is inxi.1/pinxi.1 from gh, second from smxi.org
+ $man_file_url = $self_download . '.1';
print "Updating $self_name.1 in $man_file_location\n";
print "using $download_id branch as download source\n";
print "Downloading man page file...\n";
@@ -4649,9 +4366,10 @@ sub set_version_data {
## OptionsHandler
{
package OptionsHandler;
-# note: had %trigger local but tripped odd perl 5.008 failures unless global
-# so moved to %use and %show globals.
+# Note: used %trigger here, but perl 5.008 had issues, so mmoved to global.
+# Careful with hash globals in first Perl 5.0080.
my ($self_download,$download_id);
+
sub get {
eval $start if $b_log;
$show{'short'} = 1;
@@ -4691,6 +4409,8 @@ sub get {
'C|cpu' => sub {
$show{'short'} = 0;
$show{'cpu'} = 1;},
+ 'config|configs|configuration|configurations' => sub {
+ $show{'configs'} = 1;},
'd|disk-full|optical' => sub {
$show{'short'} = 0;
$show{'disk'} = 1;
@@ -4732,10 +4452,7 @@ sub get {
$show{'swap'} = 1;
$show{'system'} = 1;},
'gpu|nvidia|nv' => sub {
- $b_admin = 1;
- $show{'short'} = 0;
- $show{'graphic'} = 1;
- $show{'graphic-full'} = 1;},
+ main::error_handler('option-removed', '--gpu/--nvidia/--nv','-Ga');},
'G|graphics|graphic' => sub {
$show{'short'} = 0;
$show{'graphic'} = 1;
@@ -4748,7 +4465,16 @@ sub get {
$show{'ip'} = 1;
$show{'network'} = 1;
$show{'network-advanced'} = 1;
- $use{'downloader'} = 1 if ! main::check_program('dig');},
+ $use{'downloader'} = 1 if !main::check_program('dig');},
+ 'ip-limit|limit:i' => sub {
+ my ($opt,$arg) = @_;
+ if ($arg != 0){
+ $limit = $arg;
+ $use{'ip-limit'} = 1;
+ }
+ else {
+ main::error_handler('bad-arg',$opt,$arg);
+ }},
'I|info' => sub {
$show{'short'} = 0;
$show{'info'} = 1;},
@@ -4760,14 +4486,6 @@ sub get {
$show{'usb'} = 1;},
'l|labels|label' => sub {
$show{'label'} = 1;},
- 'limit:i' => sub {
- my ($opt,$arg) = @_;
- if ($arg != 0){
- $limit = $arg;
- }
- else {
- main::error_handler('bad-arg',$opt,$arg);
- }},
'L|logical|lvm' => sub {
$show{'short'} = 0;
$show{'logical'} = 1;},
@@ -4799,17 +4517,18 @@ sub get {
$show{'short'} = 0;
$show{'partition'} = 0;
$show{'partition-full'} = 1;},
- 'P|partitions|partition' => sub {
- $show{'short'} = 0;
- $show{'partition'} = 1;},
- 'partition-sort:s' => sub {
+ 'partition-sort|partitions-sort|ps:s' => sub {
my ($opt,$arg) = @_;
if ($arg =~ /^(dev-base|fs|id|label|percent-used|size|uuid|used)$/){
$show{'partition-sort'} = $arg;
+ $use{'partition-sort'} = 1;
}
else {
main::error_handler('bad-arg',$opt,$arg);
}},
+ 'P|partition|partitions' => sub {
+ $show{'short'} = 0;
+ $show{'partition'} = 1;},
'r|repos|repo' => sub {
$show{'short'} = 0;
$show{'repo'} = 1;},
@@ -4820,11 +4539,43 @@ sub get {
's|sensors|sensor' => sub {
$show{'short'} = 0;
$show{'sensor'} = 1;},
+ 'sensors-default' => sub {
+ $use{'sensors-default'} = 1;},
+ 'sensors-exclude:s' => sub {
+ my ($opt,$arg) = @_;
+ if ($arg){
+ @sensors_exclude = split(/\s*,\s*/, $arg);
+ $use{'sensors-exclude'} = 1;
+ }
+ else {
+ main::error_handler('bad-arg',$opt,$arg);
+ }},
+ 'sensors-use:s' => sub {
+ my ($opt,$arg) = @_;
+ if ($arg){
+ @sensors_use = split(/\s*,\s*/, $arg);
+ $use{'sensors-use'} = 1;
+ }
+ else {
+ main::error_handler('bad-arg',$opt,$arg);
+ }},
+ 'separator|sep:s' => sub {
+ my ($opt,$arg) = @_;
+ if ($arg){
+ $sep{'s1-console'} = $arg;
+ $sep{'s2-console'} = $arg;
+ $sep{'s1-irc'} = $arg;
+ $sep{'s2-irc'} = $arg;
+ }
+ else {
+ main::error_handler('bad-arg',$opt,$arg);
+ }},
'sleep:s' => sub {
my ($opt,$arg) = @_;
$arg ||= 0;
if ($arg >= 0){
$cpu_sleep = $arg;
+ $use{'cpu-sleep'} = 1;
}
else {
main::error_handler('bad-arg',$opt,$arg);
@@ -4932,49 +4683,44 @@ sub get {
else {
main::error_handler('bad-arg',$opt,$arg);
}},
- 'V|version' => sub {
+ 'V' => sub {
+ main::error_handler('option-deprecated', '-V','--version/--vf');
+ $show{'version'} = 1;},
+ 'version|vf' => sub {
$show{'version'} = 1;},
'version-short|vs' => sub {
$show{'version-short'} = 1;},
- 'w|weather' => sub {
- my ($opt) = @_;
- $show{'short'} = 0;
- $use{'downloader'} = 1;
- if ($use{'weather'}){
- $show{'weather'} = 1;
- }
- else {
- main::error_handler('distro-block', $opt);
- }},
- 'W|weather-location:s' => sub {
+ 'w|weather:s' => sub {
my ($opt,$arg) = @_;
- $arg ||= '';
- $arg =~ s/\s//g;
$show{'short'} = 0;
$use{'downloader'} = 1;
if ($use{'weather'}){
+ $arg =~ s/\s//g if $arg;
if ($arg){
$show{'weather'} = 1;
$show{'weather-location'} = $arg;
}
else {
- main::error_handler('bad-arg',$opt,$arg);
+ $show{'weather'} = 1;
}
}
else {
main::error_handler('distro-block', $opt);
}},
+ 'W|weather-location:s' => sub {
+ main::error_handler('option-removed', '-W','-w/--weather [location]');},
'ws|weather-source:s' => sub {
my ($opt,$arg) = @_;
# let api processor handle checks if valid, this
# future proofs this
if ($arg =~ /^[1-9]$/){
$weather_source = $arg;
+ $use{'weather-source'} = 1;
}
else {
main::error_handler('bad-arg',$opt,$arg);
}},
- 'weather-unit:s' => sub {
+ 'weather-unit|wu:s' => sub {
my ($opt,$arg) = @_;
$arg ||= '';
$arg =~ s/\s//g;
@@ -4983,6 +4729,7 @@ sub get {
my %units = ('c'=>'m','f'=>'i','cf'=>'mi','fc'=>'im');
$arg = $units{$arg} if defined $units{$arg};
$weather_unit = $arg;
+ $use{'weather-unit'} = 1;
}
else {
main::error_handler('bad-arg',$opt,$arg);
@@ -5089,8 +4836,8 @@ sub get {
},
'bt-tool:s' => sub {
my ($opt,$arg) = @_;
- if ($arg =~ /^(bluetoothctl|bt-adapter|hciconfig|rfkill)$/i){
- $bt_tool = lc($arg);
+ if ($arg =~ /^(bluetoothctl|bt-adapter|btmgmt|hciconfig|rfkill)$/i){
+ $force{lc($arg)} = 1;
}
else {
main::error_handler('bad-arg', $opt, $arg);
@@ -5116,12 +4863,21 @@ sub get {
}},
'debug-arg:s' => sub {
my ($opt,$arg) = @_;
- if ($arg){
+ if ($arg && $arg =~ /^--?[a-z]/ig){
$debugger{'arg'} = $arg;
}
else {
main::error_handler('bad-arg', $opt, $arg);
}},
+ 'debug-arg-use:s' => sub {
+ my ($opt,$arg) = @_;
+ print "$arg\n";
+ if ($arg && $arg =~ /^--?[a-z]/ig){
+ $debugger{'arg-use'} = $arg;
+ }
+ else {
+ main::error_handler('bad-arg', $opt, $arg);
+ }},
'debug-filter|debug-z' => sub {
$debugger{'filter'} = 1 },
'debug-id:s' => sub {
@@ -5212,10 +4968,12 @@ sub get {
'fake:s' => sub {
my ($opt,$arg) = @_;
if ($arg){
- my $wl = 'bluetooth|compiler|cpu|dboot|dmidecode|elbrus|ipmi|logical|lspci|';
- $wl .= 'partitions|pciconf|pcictl|pcidump|raid-btrfs|raid-hw|raid-lvm|';
- $wl .= 'raid-md|raid-soft|raid-zfs|sensors|sensors-sys|swaymsg|sysctl|';
- $wl .= 'uptime|usbconfig|usbdevs|vmstat|wl-info|wlr-randr|xorg-log|xrandr';
+ my $wl = 'bluetooth|compiler|cpu|dboot|dmidecode|egl|elbrus|glx|';
+ $wl .= 'iomem|ip-if|ipmi|logical|lspci|partitions|pciconf|pcictl|pcidump|';
+ $wl .= 'raid-btrfs|raid-hw|raid-lvm|raid-md|raid-soft|raid-zfs|';
+ $wl .= 'sensors|sensors-sys|swaymsg|sys-mem|sysctl|';
+ $wl .= 'udevadm|uptime|usbconfig|usbdevs|vmstat|vulkan|wl-info|wlr-randr|';
+ $wl .= 'xdpyinfo|xorg-log|xrandr';
for (split(',',$arg)){
if ($_ =~ /\b($wl)\b/){
$fake{lc($1)} = 1;
@@ -5239,9 +4997,10 @@ sub get {
'force:s' => sub {
my ($opt,$arg) = @_;
if ($arg){
- my $wl = 'colors|cpuinfo|display|dmidecode|hddtemp|lsusb|man|meminfo|';
- $wl .= 'no-dig|no-doas|no-html-wan|no-sudo|pkg|rpm|sensors-sys|usb-sys|';
- $wl .= 'vmstat|wayland|wmctrl';
+ my $wl = 'bluetoothctl|bt-adapter|btmgmt|colors|cpuinfo|display|dmidecode|';
+ $wl .= 'hciconfig|hddtemp|ip|ifconfig|lsusb|man|meminfo|';
+ $wl .= 'no-dig|no-doas|no-html-wan|no-sudo|pkg|rfkill|rpm|sensors-sys|';
+ $wl .= 'udevadm|usb-sys|vmstat|wayland|wmctrl';
for (split(',',$arg)){
if ($_ =~ /\b($wl)\b/){
$force{lc($1)} = 1;
@@ -5270,6 +5029,8 @@ sub get {
$show{'no-host'} = 0;},
'html-wan' => sub {
$force{'no-html-wan'} = 0;},
+ 'ifconfig' => sub {
+ $force{'ifconfig'} = 1;},
'indent:i' => sub {
my ($opt,$arg) = @_;
if ($arg >= 11){
@@ -5317,7 +5078,7 @@ sub get {
$use{'no-ssl'} = 1;},
'no-sudo' => sub {
$force{'no-sudo'} = 1;},
- 'output:s' => sub {
+ 'output|export:s' => sub {
my ($opt,$arg) = @_;
if ($arg =~ /^(json|screen|xml)$/){
$output_type = $arg;
@@ -5325,7 +5086,7 @@ sub get {
else {
main::error_handler('bad-arg', $opt, $arg);
}},
- 'output-file:s' => sub {
+ 'output-file|export-file:s' => sub {
my ($opt,$arg) = @_;
if ($arg){
if ($arg eq 'print' || main::check_output_path($arg)){
@@ -5350,26 +5111,8 @@ sub get {
undef %risc;
$risc{'id'} = 'riscv';
$risc{'riscv'} = 1;},
- 'sensors-default' => sub {
- $use{'sensors-default'} = 1;},
- 'sensors-exclude:s' => sub {
- my ($opt,$arg) = @_;
- if ($arg){
- @sensors_exclude = split(/\s*,\s*/, $arg);
- }
- else {
- main::error_handler('bad-arg',$opt,$arg);
- }},
'sensors-sys' => sub {
$force{'sensors-sys'} = 1;},
- 'sensors-use:s' => sub {
- my ($opt,$arg) = @_;
- if ($arg){
- @sensors_use = split(/\s*,\s*/, $arg);
- }
- else {
- main::error_handler('bad-arg',$opt,$arg);
- }},
'sparc' => sub {
undef %risc;
$risc{'id'} = 'sparc';
@@ -5378,7 +5121,7 @@ sub get {
$debugger{'sys-force'} = 1;},
'tty' => sub { # workaround for ansible/scripts running this
$b_irc = 0;},
- 'U|update:s' => sub { # 1,2,3 OR http://myserver/path/inxi
+ 'U|update:s' => sub { # 1,2,3,4 OR http://myserver/path/inxi
my ($opt,$arg) = @_;
process_updater($opt,$arg);},
'usb-sys' => sub {
@@ -5405,53 +5148,70 @@ sub get {
main::error_handler('unknown-option', "$opt", "");}
); # or error_handler('unknown-option', "@ARGV", '');
# run all these after so that we can change widths, downloaders, etc
- # print Data::Dumper::Dumper \%trigger;
post_process();
eval $end if $b_log;
}
+
+# These options require other option[s] to function, and have no meaning alone.
+sub check_modifiers {
+ if ($use{'cpu-sleep'} && !$show{'cpu'} && !$show{'cpu-basic'} &&
+ !$show{'short'}){
+ main::error_handler('arg-modifier', '--sleep', '[no-options], -b, -C, -v [>0]');
+ }
+ if ($show{'label'} && !$show{'partition'} && !$show{'partition-full'} &&
+ !$show{'swap'} && !$show{'unmounted'}){
+ main::error_handler('arg-modifier', '-l/--label', '-j, -o, -p, -P');
+ }
+ if ($use{'ip-limit'} && !$show{'ip'}){
+ main::error_handler('arg-modifier', '--limit', '-i');
+ }
+ if ($output_type && $output_type ne 'screen' && !$output_file){
+ main::error_handler('arg-modifier', '--output', '--output-file [filename]');
+ }
+ if ($use{'partition-sort'} && !$show{'partition'} && !$show{'partition-full'}){
+ main::error_handler('arg-modifier', '--partition-sort', '-p, -P');
+ }
+ if ($use{'sensors-default'} && !$show{'sensor'}){
+ main::error_handler('arg-modifier', '--sensors-default', '-s');
+ }
+ if ($use{'sensors-exclude'} && !$show{'sensor'}){
+ main::error_handler('arg-modifier', '--sensors-exclude', '-s');
+ }
+ if ($use{'sensors-use'} && !$show{'sensor'}){
+ main::error_handler('arg-modifier', '--sensors-use', '-s');
+ }
+ if ($show{'uuid'} && !$show{'machine'} && !$show{'partition'} &&
+ !$show{'partition-full'} && !$show{'swap'} && !$show{'unmounted'}){
+ main::error_handler('arg-modifier', '-u/--uuid', '-j, -M, -o, -p, -P');
+ }
+ if ($use{'weather-source'} && !$show{'weather'}){
+ main::error_handler('arg-modifier', '--weather-source/--ws', '-w');
+ }
+ if ($use{'weather-unit'} && !$show{'weather'}){
+ main::error_handler('arg-modifier', '--weather-unit/--wu', '-w');
+ }
+}
+
sub post_process {
+ # first run all the stuff that exits after running
CheckRecommends::run() if $show{'recommends'};
+ Configs::show() if $show{'configs'};
+ main::show_options() if $show{'help'};
+ main::show_version() if ($show{'version'} || $show{'version-short'});
# sets for either config or arg here
if ($use{'downloader'} || $wan_url || ($force{'no-dig'} && $show{'ip'})){
main::set_downloader();
}
- main::set_xorg_log() if $show{'graphic'};
- if ($show{'version'} || $show{'version-short'}){
- main::show_version();
- }
- main::show_options() if $show{'help'};
$use{'man'} = 0 if (!$use{'yes-man'} || $use{'no-man'});
- main::update_me($self_download, $download_id) if $use{'update-trigger'};
- if ($b_pledge){
- my $b_update;
- # if -c 9x, remove in SelectColors::set_selection(), else remove here
- if (!$colors{'selector'} && $debugger{'level'} < 21){
- @pledges = grep {$_ ne 'getpw'} @pledges;
- $b_update = 1;
- }
- if ($debugger{'level'} < 21){ # remove ftp upload
- @pledges = grep {!/(dns|inet)/} @pledges;
- $b_update = 1;
- }
- # not writing/creating .inxi data dirs colors selector launches set_color()
- if (!$show{'weather'} && !$colors{'selector'} && $debugger{'level'} < 10 &&
- $output_type eq 'screen'){
- @pledges = grep {!/(cpath|wpath)/} @pledges;
- $b_update = 1;
- }
- OpenBSD::Pledge::pledge(@pledges) if $b_update;
- }
- if ($output_type){
- if ($output_type ne 'screen' && !$output_file){
- main::error_handler('bad-arg', '--output', '--output-file not provided');
- }
- }
- if (($show{'label'} || $show{'uuid'}) && !$show{'partition'} &&
- !$show{'partition-full'} && !$show{'swap'} && !$show{'unmounted'}){
- main::error_handler('bad-arg', '-l/-u', 'missing required option(s) -j, -o, -p, -P');
+ main::update_me($self_download,$download_id) if $use{'update-trigger'};
+ main::set_xorg_log() if $show{'graphic'};
+ set_pledge() if $b_pledge;
+ $extra = 3 if $b_admin; # before check_modifiers in case we make $estra based.
+ check_modifiers();
+ # this turns off basic for F/v graphic output levels.
+ if ($show{'graphic-basic'} && $show{'graphic-full'} && $extra > 1){
+ $show{'graphic-basic'} = 0;
}
- $extra = 3 if $b_admin;
- $show{'graphic-basic'} = 0 if $show{'graphic-full'} && $extra > 1;
if ($force{'rpm'}){
$force{'pkg'} = 1;
delete $force{'rpm'};
@@ -5466,7 +5226,7 @@ sub post_process {
$use{'block-tool'} = 1;
}
if ($show{'short'} || $show{'raid'} || $show{'disk'} || $show{'disk-total'} ||
- $show{'disk-basic'} || $show{'unmounted'}){
+ $show{'disk-basic'} || $show{'unmounted'}){
$use{'btrfs'} = 1;
$use{'mdadm'} = 1;
}
@@ -5495,16 +5255,20 @@ sub post_process {
$show{'disk-basic'} = 0;
$show{'disk-total'} = 0;
}
- if ($show{'ram'} || $show{'slot'} || ($show{'cpu'} && ($extra > 1 || $bsd_type)) ||
- (($bsd_type || $force{'dmidecode'}) && ($show{'machine'} || $show{'battery'}))){
+ if ($show{'ram'} || $show{'slot'} ||
+ ($show{'cpu'} && ($extra > 1 || $bsd_type)) ||
+ (($bsd_type || $force{'dmidecode'}) && ($show{'machine'} || $show{'battery'}))){
$use{'dmidecode'} = 1;
}
+ if (!$bsd_type && ($show{'ram'})){
+ $use{'udevadm'} = 1;
+ }
if ($show{'audio'} || $show{'bluetooth'} || $show{'graphic'} ||
- $show{'network'} || $show{'raid'}){
+ $show{'network'} || $show{'raid'}){
$use{'pci'} = 1;
}
- if ($show{'usb'} || $show{'audio'} || $show{'bluetooth'} ||
- $show{'graphic'} || $show{'network'}){
+ if ($show{'usb'} || $show{'audio'} || $show{'bluetooth'} || $show{'disk'} ||
+ $show{'graphic'} || $show{'network'}){
$use{'usb'} = 1;
}
if ($bsd_type){
@@ -5516,8 +5280,8 @@ sub post_process {
$use{'bsd-cpu'} = 1;
$use{'bsd-sleep'} = 1;}
if ($show{'short'} || $show{'disk-basic'} || $show{'disk-total'} ||
- $show{'disk'} || $show{'partition'} || $show{'partition-full'} ||
- $show{'raid'} || $show{'swap'} || $show{'unmounted'}){
+ $show{'disk'} || $show{'partition'} || $show{'partition-full'} ||
+ $show{'raid'} || $show{'swap'} || $show{'unmounted'}){
$use{'bsd-disk'} = 1;
$use{'bsd-partition'} = 1;
$use{'bsd-raid'} = 1;}
@@ -5533,6 +5297,8 @@ sub post_process {
if ($use{'pci'}){
$use{'bsd-pci'} = 1;}
if ($show{'raid'}){
+ $use{'bsd-raid'} = 1;}
+ if ($show{'ram'}){
$use{'bsd-ram'} = 1;}
if ($show{'sensor'}){
$use{'bsd-sensor'} = 1;}
@@ -5540,37 +5306,45 @@ sub post_process {
$use{'sysctl'} = 1;
}
}
+
sub process_updater {
my ($opt,$arg) = @_;
$use{'downloader'} = 1;
if ($use{'update'}){
$use{'update-trigger'} = 1;
- if (!$arg && $self_name eq 'pinxi'){
+ if (!$arg){
$use{'man'} = 1;
- $download_id = 'inxi-perl branch';
- $self_download = main::get_defaults('inxi-pinxi');
+ $download_id = "$self_name main branch";
+ $self_download = main::get_defaults("$self_name-main");
}
elsif ($arg && $arg eq '3'){
$use{'man'} = 1;
$download_id = 'dev server';
- $self_download = main::get_defaults('inxi-dev');
+ $self_download = main::get_defaults("$self_name-dev");
}
- else {
- if (!$arg){
- $download_id = 'main branch';
- $self_download = main::get_defaults('inxi-main');
- $use{'man'} = 1;
- $use{'yes-man'} = 1;
- }
- elsif ($arg =~ /^[12]$/){
+ elsif ($arg && $arg eq '4'){
+ $use{'man'} = 1;
+ $use{'ftp-download'} = 1;
+ $download_id = 'dev server ftp';
+ $self_download = main::get_defaults("$self_name-dev-ftp");
+ }
+ elsif ($arg =~ /^[12]$/){
+ if ($self_name eq 'inxi'){
$download_id = "branch $arg";
$self_download = main::get_defaults("inxi-branch-$arg");
}
- elsif ($arg =~ /^http/){
- $download_id = 'alt server';
- $self_download = $arg;
+ else {
+ main::error_handler('bad-arg', $opt, $arg);
}
}
+ elsif ($arg =~ /^(ftp|https?):/){
+ $download_id = 'alt server';
+ $self_download = $arg;
+ }
+ if ($self_download && $self_name eq 'inxi'){
+ $use{'man'} = 1;
+ $use{'yes-man'} = 1;
+ }
if (!$self_download){
main::error_handler('bad-arg', $opt, $arg);
}
@@ -5579,6 +5353,26 @@ sub process_updater {
main::error_handler('distro-block', $opt);
}
}
+
+sub set_pledge {
+ my $b_update;
+ # if -c 9x, remove in SelectColors::set_selection(), else remove here
+ if (!$colors{'selector'} && $debugger{'level'} < 21){
+ @pledges = grep {$_ ne 'getpw'} @pledges;
+ $b_update = 1;
+ }
+ if ($debugger{'level'} < 21){ # remove ftp upload
+ @pledges = grep {!/(dns|inet)/} @pledges;
+ $b_update = 1;
+ }
+ # not writing/creating .inxi data dirs colors selector launches set_color()
+ if (!$show{'weather'} && !$colors{'selector'} && $debugger{'level'} < 10 &&
+ $output_type eq 'screen'){
+ @pledges = grep {!/(cpath|wpath)/} @pledges;
+ $b_update = 1;
+ }
+ OpenBSD::Pledge::pledge(@pledges) if $b_update;
+}
}
sub show_options {
@@ -5600,10 +5394,10 @@ sub show_options {
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, --edid, --slots.
- If you use them with -v [level], -b or -F, $self_name will add the requested
- lines to the output."],
+ to show or add the item(s) you want to see: A, B, C, d, D, E, f, G, i, I, j,
+ J, l, L, m, M, n, N, o, p, P, r, R, s, S, t, u, w, --edid, --mm, --ms,
+ --slots. If you use them with -v [level], -b or -F, $self_name will add the
+ requested lines to the output."],
['0', '', '', '' ],
['0', '', '', "Examples:^$self_name^-v4^-c6 OR $self_name^-bDc^6 OR
$self_name^-FzjJxy^80"],
@@ -5613,7 +5407,7 @@ sub show_options {
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
+ ['1', '-A', '--audio', "Audio/sound devices(s), driver; active sound APIs and
servers."],
['1', '-b', '--basic', "Basic output, short form. Same as $self_name^-v^2."],
['1', '-B', '--battery', "System battery info, including charge, condition
@@ -5635,30 +5429,31 @@ sub show_options {
['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', '', '--gpu', "Deprecated. Triggers -Ga."],
['1', '-G', '--graphics', "Graphics info (devices(s), drivers, display
protocol (if available), display server/Wayland compositor, resolution, X.org:
- renderer, OpenGL version; Xvesa: VBE info."],
+ renderer, basic EGL, OpenGL, Vulkan API data; Xvesa API: VBE info."],
['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."],
- ['1', '-I', '--info', "General info, including processes, uptime, memory,
- IRC client or shell type, $self_name version."],
+ ['1', '', '--ip-limit, --limit', "[-1; 1-x] Set max output limit of IP
+ addresses for -i (default 10; -1 removes limit)."],
+ ['1', '-I', '--info', "General info, including processes, uptime, memory (if
+ -m/-tm not used), 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."],
- ['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, type (e.g. DDR3), size, speed. If neither
- -I nor -tm are selected, also shows RAM used/total."],
+ ['1', '-m', '--memory', "Memory (RAM) data. Numbers of devices (slots)
+ supported and individual memory devices (sticks of memory etc). For devices,
+ shows device locator, type (e.g. DDR3), size, speed. Also shows System RAM
+ report, and removes Memory report from -I or -tm."],
['1', '', '--memory-modules,--mm', "Memory (RAM) data. Exclude empty module slots."],
['1', '', '--memory-short,--ms', "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).
+ 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"],
@@ -5672,13 +5467,17 @@ sub show_options {
['1', '', '', "Example: ^<username>^ALL^=^NOPASSWD:^/usr/bin/file^"],
['1', '-p', '--partitions-full', "Full $partition_string information (-P plus
all other detected ${partition_string}s)."],
+ ['1', '', '--partitions-sort, --ps', "
+ [dev-base|fs|id|label|percent-used|size|uuid|used] Change sort order of
+ ${partition_string} output. See man page for specifics."],
['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."],
['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."],
+ APT, CARDS, EOPKG, NETPKG, NIX, PACMAN, PACMAN-G2, PISI, PKG (BSDs), PORTAGE,
+ PORTS (BSDs), SBOPKG, SBOUI, SCRATCHPKG, SLACKPKG, SLAPT_GET, SLPKG, TCE,
+ TAZPKG, 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."],
@@ -5693,7 +5492,8 @@ sub show_options {
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."],
+ ['1', '-u', '--uuid', "$partition_string_u, system board UUIDs. Use with -j,
+ -M, -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"],
@@ -5720,18 +5520,19 @@ sub show_options {
# if distro maintainers don't want the weather feature disable it
if ($use{'weather'}){
push(@$rows,
- ['1', '-w', '--weather', "Local weather data/time. To check an alternate
- location, see -W. NO AUTOMATED QUERIES OR EXCESSIVE USE ALLOWED!"],
- ['1', '-W', '--weather-location', "[location] Supported options for
- [location]: postal code[,country/country code]; city, state (USA)/country
+ ['1', '-w', '--weather', "NO^AUTOMATED^QUERIES^OR^EXCESSIVE^USE^ALLOWED!"],
+ ['1', '', '', "Without [location]: Your current local (local to
+ your IP address) weather data/time.Example:^$self_name^-w"],
+ ['1', '', '', "With [location]: Supported location options are:
+ postal code[,country/country code]; city, state (USA)/country
(country/two character country code); latitude, longitude. Only use if you
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
+ Example:^$self_name^-w^[new+york,ny^london,gb^madrid,es]"],
+ ['1', '', '--weather-source,--ws', "[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)."],
+ ['1', '', '--weather-unit,--wu', "Set weather units to metric (m), imperial
+ (i), metric/imperial (mi), or imperial/metric (im)."],
);
}
push(@$rows,
@@ -5747,7 +5548,7 @@ sub show_options {
['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."],
+ -o, -p, -P, -Sa, board UUIDs in -Mxxx."],
['1', '', '--zv,--filter-vulnerabilities', "Filters out Vulnerabilities
report in -Ca."],
['1', '-Z', '--no-filter', "Disable output filters. Useful for debugging
@@ -5770,16 +5571,14 @@ sub show_options {
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', '', '--separator, --sep', "[key:value separator character]. Change
+ separator character(s) for key: value pairs."],
['1', '-y', '--width', "[empty|-1|1|60-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.
@@ -5795,7 +5594,7 @@ sub show_options {
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."],
+ inactive sound servers/APIs."],
['2', '-B', '', "Current/minimum voltage, vendor/model, status (if available);
attached devices (e.g. wireless mouse, keyboard, if present)."],
['2', '-C', '', "L1/L3 cache (if most Linux, or if root and dmidecode
@@ -5813,19 +5612,19 @@ sub show_options {
['2', '-E', '', "PCI/USB Bus ID of device, driver version,
LMP version."],
['2', '-G', '', "GPU arch (AMD/Intel/Nvidia only); Specific vendor/product
- information (if relevant); PCI/USB ID of device; Direct rendering status
- (in X); Screen number GPU is running on (Nvidia only); device temp (Linux,
- if found)."],
+ information (if relevant); PCI/USB ID of device; Screen number GPU is running
+ on (Nvidia only); device temp (Linux, if found); APIs: EGL: active/inactive
+ platforms; OpenGL: direct rendering status (in X); Vulkan device counts."],
['2', '-i', '', "For IPv6, show additional scope addresses: Global, Site,
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/target (if available). Total
- count of all packages discovered in system (if not -r)."],
+ ['2', '-I', '', "Default system compilers. With -xx, also shows other
+ installed compiler versions. If running in shell, not in IRC client, shows
+ shell version number, if detected. Init/RC type and runlevel/target (if
+ available). Total count of all packages discovered in system (if not -r)."],
['2', '-j', '', "Add mapped: name if partition mapped."],
- ['2', '-J', '', "For Device: driver."],
+ ['2', '-J', '', "For Device: driver; Si speed (base 10, bits/s)."],
['2', '-L', '', "For VG > LV, and other Devices, dm:"],
- ['2', '-m,--memory-modules', '', "Max memory module size (if available)."],
+ ['2', '-m,--mm', '', "Max memory module size (if available)."],
['2', '-N', '', "Specific vendor/product information (if relevant);
PCI/USB ID of device; Version/port(s)/driver version (if available); device
temperature (Linux, if found)."],
@@ -5844,54 +5643,60 @@ sub show_options {
);
if ($use{'weather'}){
push(@$rows,
- ['2', '-w,-W', '', "Wind speed and direction, humidity, pressure,
- and time zone, if available."]);
+ ['2', '-w', '', "Wind speed and direction, humidity, pressure, and time
+ zone, if available."]);
}
push(@$rows,
['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; PCIe speed,
- lanes (if found)."],
- ['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)."],
+ lanes (if found); USB rev, speed, lanes (if found); sound server/api helper
+ daemons/plugins."],
+ ['2', '-B', '', "Power used, in watts; serial number."],
+ ['2', '-D', '', "Disk transfer speed; NVMe lanes; USB rev, speed, lanes (if
+ found); Disk serial number; LVM volume group free space (if available); disk
+ duid (some BSDs)."],
['2', '-E', '', "Chip vendor:product ID, LMP subversion; PCIe speed, lanes
- (if found)."],
+ (if found); USB rev, speed, lanes (if found)."],
['2', '-G', '', "Chip vendor:product ID for each video device; Output ports,
- used and empty; PCIe speed, lanes (if found); Xorg: 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 Screen data: ID, s-res, dpi; Monitors: ID, position (if > 1),
- resolution, dpi, model, diagonal."],
- ['2', '-I', '', "Other detected installed gcc versions (if present). System
- default target/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
+ used and empty; PCIe speed, lanes (if found); USB rev, speed, lanes (if
+ found); Xorg: 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 Screen data: ID, s-res, dpi; Monitors:
+ ID, position (if > 1), resolution, dpi, model, diagonal; APIs: EGL: per
+ platform report; OpenGL: ES version, device-ID, display-ID (if not found in
+ Display line); Vulkan: per device report."],
+ ['2', '-I', '', "Adds Power: with children uptime, wakeups (from suspend);
+ other detected installed gcc versions (if present). System default
+ target/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."],
+ ['2', '-J', '', "Vendor:chip-ID; lanes (Linux only)."],
['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
+ ['2', '-m,--mm', '', "Manufacturer, part number; single/double
bank (if found); memory array voltage (legacy, rare); module voltage (if
available)."],
- ['2', '-M', '', "Chassis info, BIOS ROM size (dmidecode only), if available."],
- ['2', '-N', '', "Chip vendor:product ID; PCIe speed, lanes (if found)."],
+ ['2', '-M', '', "Chassis info, part number, BIOS ROM size (dmidecode only),
+ if available."],
+ ['2', '-N', '', "Chip vendor:product ID; PCIe speed, lanes (if found); USB
+ rev, speed, lanes (if found)."],
['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)."],
- ['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', '-S', '', "Desktop toolkit (tk), if available (only some DE/wm
+ supported); window manager (wm); display/Login manager (dm,lm) (e.g. kdm,
+ gdm3, lightdm, greetd, seatd)."],
['2', '--slots', '', "Slot length; slot voltage, if available."],
);
if ($use{'weather'}){
push(@$rows,
- ['2', '-w,-W', '', "Snow, rain, precipitation, (last observed hour),
- cloud cover, wind chill, dew point, heat index, if available."]
+ ['2', '-w', '', "Snow, rain, precipitation, (last observed hour), cloud
+ cover, wind chill, dew point, heat index, if available."]
);
}
push(@$rows,
@@ -5904,29 +5709,34 @@ sub show_options {
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', '-E', '', "Serial number, class ID, bluetooth device class ID, HCI
+ version and revision."],
['2', '-G', '', "Device serial number, class ID; Xorg Screen size, diag;
- Monitors: hz, size, modes, serial, scale, modes (max/min)."],
- ['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
+ Monitors: hz, size, modes, serial, scale, modes (max/min); APIs: EGL: hardware
+ driver info; Vulkan: layer count, device hardware vendor."],
+ ['2', '-I', '', "For Power:, adds states, suspend/hibernate active type;
+ 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."],
+ ['2', '-J', '', "If present: Devices: serial number, interface count, max
+ power."],
+ ['2', '-m,--mm', '', "Width of memory bus, data and total (if
present and greater than data); Detail for Type, if present; module current,
min, max voltages (if present and different from each other); serial number."],
+ ['2', '-M', '', "Board/Chassis UUID, if available."],
['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."],
+ ['2', '-S', '', "Kernel clocksource; if in non console wm/desktop; window
+ manager version number; if available: panel/tray/bar/dock (with:);
+ screensavers/lockers running (tools:); virtual terminal number;
+ display/login manager version number."],
);
if ($use{'weather'}){
push(@$rows,
- ['2', '-w,-W', '', "Location (uses -z/irc filter), weather observation
- time, altitude, sunrise/sunset, if available."]
+ ['2', '-w', '', "Location (uses -z/irc filter), weather observation time,
+ altitude, sunrise/sunset, if available."]
);
}
push(@$rows,
@@ -5935,7 +5745,8 @@ sub show_options {
verbose or line output, not short form); check man page for explanations!;
also sets --extra=3:"],
['2', '-A', '', "If available: list of alternate kernel modules/drivers
- for device(s); PCIe lanes-max: gen, speed, lanes (if relevant)."],
+ for device(s); PCIe lanes-max: gen, speed, lanes (if relevant); USB mode (if
+ found); list of installed tools for servers."],
['2', '-C', '', "If available: microarchitecture level (64 bit AMD/Intel
only).CPU generation, process node, built years; CPU socket type, base/boost
speeds (dmidecode+root/sudo/doas required); Full topology line, with cores,
@@ -5943,34 +5754,48 @@ sub show_options {
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."],
+ family; maj:min; USB mode (if found); USB drive specifics; SMART report."],
+ ['2', '-E', '', "PCIe lanes-max: gen, speed, lanes (if relevant); USB mode
+ (if found); If available: in Report:, adds status: discoverable, pairing;
+ adds Info: line: acl-mtu, sco-mtu, link-policy, link-mode, service-classes."],
['2', '-G', '', "GPU process node, built year (AMD/Intel/Nvidia only);
non-free driver info (Nvidia only); PCIe lanes-max: gen, speed, lanes (if
- relevant); list of alternate kernel modules/drivers for device(s) (if
- available); Monitor built year, gamma, screen ratio (if available)."],
- ['2', '-I', '', "Adds to Packages total number of lib files found for each
- package manager and pm tools (if not -r); adds init service tool."],
+ relevant); USB mode (if found); list of alternate kernel modules/drivers for
+ device(s) (if available); Monitor built year, gamma, screen ratio (if
+ available); APIs: OpenGL: device memory, unified memory status; Vulkan: adds
+ full device report, device name, driver version, surfaces."],
+ ['2', '-I', '', "Adds to Power suspend/hibernate available non active states,
+ hibernate image size, suspend failed totals (if not 0), active power services;
+ Packages total number of lib files found for each package manager and pm tools
+ (if not -r); adds init service tool."],
['2', '-j,-p,-P', '', "For swap (if available): swappiness and vfs cache
pressure, and if values are default or not."],
+ ['2', '-j', '', "Linux only: (if available): row one zswap data, and per zram
+ row, active and available zram compressions, max compression streams."],
+ ['2', '-J', '', "Adds USB mode (Linux only); IEC speed (base 2, Bytes/s)."],
['2', '-L', '', "LV, Crypto, devices, components: add maj:min; show
full device/components report (speed, mapped names)."],
['2', '-m', '', "Show full volts report, current, min, max, even if
- identical."],
- ['2', '-n,-N', '', "If available: list of alternate kernel modules/drivers
- for device(s); PCIe lanes-max: gen, speed, lanes (if relevant)."],
+ identical; show firmware version (if available)."],
+ ['2', '-n,-i', '', "Info: services: line, with running network services."],
+ ['2', '-n,-N,-i', '', "If available: list of alternate kernel modules/drivers
+ for device(s); PCIe lanes-max: gen, speed, lanes (if relevant); USB mode (if
+ found)."],
['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."],
- ['2', '', '--slots', "If available: slot bus ID children."],
+ ['2', '-S', '', "If available: kernel alternate clocksources, boot parameters;
+ de extra data (info: eg kde frameworks); screensaver/locker tools available
+ but not active (avail:)."],
+ ['2', '--slots', '', "If available: slot bus ID children."],
);
push(@$rows,
[0, '', '', "$line"],
[0, '', '', "Additional Options:"],
+ ['1', '--config', '--configuration', "Show active configurations, by file(s).
+ Last item listed overrides previous."],
['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
@@ -5983,15 +5808,16 @@ sub show_options {
otherwise user is fine. Man page installs require root. No arguments
downloads from main $self_name git repo."],
['1', '', '', "Use alternate sources for updating $self_name"],
- ['2', '1', '', "Get the git branch one version."],
- ['2', '2', '', "Get the git branch two version."],
- ['3', '3', '', "Get the dev server (smxi.org) version."],
- ['2', '<http>', '', "Get a version of $self_name from your own server.
- Use the full download path, e.g.^$self_name^-U^https://myserver.com/inxi"],
+ ['2', '3', '', "Get the dev server (smxi.org) version."],
+ ['2', '4', '', "Get the dev server (smxi.org) FTP version. Use if SSL issues
+ and --no-ssl doesn't work."],
+ ['2', '[http|https|ftp]', '', "Get a version of $self_name from your own
+ server. Use the full download path, e.g.
+ ^$self_name^-U^https://myserver.com/inxi"],
);
}
push(@$rows,
- ['1', '-V', '--version', "Prints full $self_name version info then exits."],
+ ['1', '', '--version, --vf', "Prints full $self_name version info then exits."],
['1', '', '--version-short,--vs', "Prints 1 line $self_name version info. Can
be used with other line options."],
['0', '', '', "$line"],
@@ -6003,22 +5829,24 @@ sub show_options {
['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', '', '--bt-tool', "[bt-adapter btmgmt hciconfig rfkill] Force use of
+ given tool forbluetooth report. Or use --force [tool]."],
['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
+ ['1', '', '--downloader', "Force $self_name to use [curl fetch perl wget] for
downloads."],
- ['1', '', '--force', "[dmidecode|hddtemp|lsusb|meminfo|usb-sys|vmstat|wmctrl].
+ ['1', '', '--force', "[bt-adapter btmgmt dmidecode hciconfig hddtemp ip
+ ifconfig lsusb meminfo rfkill 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)."],
+ ['1', '', '--ifconfig', "Force use of ifconfig for IF with -i."],
);
if ($use{'update'}){
push(@$rows,
@@ -6044,7 +5872,7 @@ sub show_options {
['1', '', '--no-sudo', "Skip internal program use of sudo features (not
related to starting $self_name with sudo)."],
['1', '', '--rpm', "Force use of disabled package manager counts for packages
- feature with -rx/-Ix. RPM disabled by default due to slow to massive RPM
+ feature with -rx/-Ix. RPM disabled by default due to slow to massive rpm
package query times."],
['1', '', '--sensors-default', "Removes configuration item SENSORS_USE and
SENSORS_EXCLUDE. Same as default behavior."],
@@ -6067,7 +5895,7 @@ sub show_options {
(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"],
+ Example:^$self_name^-i^--wan-ip-url^https://yoursite.com/remote-ip"],
['1', '', '--wm', "Force wm: to use wmctrl as data source. Default uses ps."],
['0', '', '', $line ],
['0', '', '', "Debugging Options:"],
@@ -6146,7 +5974,7 @@ sub show_version {
}
push(@$rows,
[ 0, '', '', '' ],
- [ 0, '', '', "Website:^https://github.com/smxi/inxi^or^https://smxi.org/" ],
+ [ 0, '', '', "Website:^https://codeberg.org/smxi/inxi^or^https://smxi.org/" ],
[ 0, '', '', "IRC:^irc.oftc.net channel:^#smxi" ],
[ 0, '', '', "Forums:^https://techpatterns.com/forums/forum-33.html" ],
[ 0, '', '', '' ],
@@ -6181,9 +6009,10 @@ my $pppid = '';
# # print "$type\n";
# return bless $self, $class;
# }
+
sub set {
eval $start if $b_log;
- main::set_ps_aux() if !$loaded{'ps-aux'};
+ PsData::set_cmd() if !$loaded{'ps-cmd'};
# $b_irc = 1; # for testing, like cli konvi start which shows as tty
if (!$b_irc){
# we'll run ShellData::set() for -I, but only then
@@ -6206,7 +6035,7 @@ sub get_client_name {
$client_name = lc(readlink "/proc/$ppid/exe");
$client_name =~ s/^.*\///;
if ($client_name =~ /^(bash|csh|dash|fish|sh|python.*|perl.*|zsh)$/){
- $pppid = (main::grabber("ps -wwp $ppid -o ppid"))[1];
+ $pppid = (main::grabber("ps -wwp $ppid -o ppid 2>/dev/null"))[1];
# my @temp = (main::grabber("ps -wwp $ppid -o ppid 2>/dev/null"))[1];
$pppid =~ s/^\s+|\s+$//g;
$client_name =~ s/[0-9\.]+$//; # clean things like python2.7
@@ -6245,18 +6074,20 @@ sub get_client_name {
}
}
if ($b_log){
- my $string = "Client: $client{'name'} :: version: $client{'version'} :: konvi: $client{'konvi'} :: PPID: $ppid";
+ my $string = "Client: $client{'name'} :: version: $client{'version'} ::";
+ $string .= " konvi: $client{'konvi'} :: PPID: $ppid";
main::log_data('data', $string);
}
eval $end if $b_log;
}
+
sub get_client_version {
eval $start if $b_log;
- @app = main::program_values($client{'name'});
+ my @app = ProgramData::values($client{'name'});
my (@data,@working,$string);
if (@app){
$string = ($client{'name'} =~ /^gribble|limnoria|supybot$/) ? 'supybot' : $client{'name'};
- $client{'version'} = main::program_version($string,$app[0],$app[1],$app[2],$app[4],$app[5],$app[6]);
+ $client{'version'} = ProgramData::version($string,$app[0],$app[1],$app[2],$app[4],$app[5],$app[6]);
$client{'name-print'} = $app[3];
$client{'console-irc'} = $app[4];
}
@@ -6265,7 +6096,7 @@ sub get_client_version {
$client{'console-irc'} = 1;
}
elsif ($client{'name'} eq 'bitchx'){
- @data = main::grabber("$client{'name'} -v");
+ @data = main::grabber("$client{'name'} -v 2>/dev/null");
$string = awk(\@data,'Version');
if ($string){
$string =~ s/[()]|bitchx-//g;
@@ -6327,9 +6158,8 @@ sub get_client_version {
# (KSirc sucks anyway ;)
foreach (@$cmdline){
if ($_ =~ /dsirc/){
- $client{'version'} = main::program_version('ksirc','KSirc:',2,'-v',0,0);
$client{'name'} = 'ksirc';
- $client{'name-print'} = 'KSirc';
+ ($client{'name-print'},$client{'version'}) = ProgramData::full('ksirc');
}
}
$client{'console-irc'} = 1;
@@ -6365,6 +6195,7 @@ sub get_client_version {
}
eval $end if $b_log;
}
+
sub get_cmdline {
eval $start if $b_log;
my @cmdline;
@@ -6390,16 +6221,18 @@ sub get_cmdline {
eval $end if $b_log;
return [@cmdline];
}
+
sub perl_python_client {
eval $start if $b_log;
return 1 if $client{'version'};
+ my @app;
# this is a hack to try to show konversation if inxi is running but started via /cmd
# OR via program shortcuts, both cases in fact now
# main::print_line("konvi: " . scalar grep { $_ =~ /konversation/ } @ps_cmd);
if ($b_display && main::check_program('konversation') &&
(grep { $_ =~ /konversation/ } @ps_cmd)){
- @app = main::program_values('konversation');
- $client{'version'} = main::program_version('konversation',$app[0],$app[1],$app[2],$app[5],$app[6]);
+ @app = ProgramData::values('konversation');
+ $client{'version'} = ProgramData::version('konversation',$app[0],$app[1],$app[2],$app[5],$app[6]);
$client{'name'} = 'konversation';
$client{'name-print'} = $app[3];
$client{'console-irc'} = $app[4];
@@ -6410,8 +6243,8 @@ sub perl_python_client {
(main::check_program('supybot') ||
main::check_program('gribble') || main::check_program('limnoria')) &&
(grep { $_ =~ /supybot/ } @ps_cmd)){
- @app = main::program_values('supybot');
- $client{'version'} = main::program_version('supybot',$app[0],$app[1],$app[2],$app[5],$app[6]);
+ @app = ProgramData::values('supybot');
+ $client{'version'} = ProgramData::version('supybot',$app[0],$app[1],$app[2],$app[5],$app[6]);
if ($client{'version'}){
if (grep { $_ =~ /gribble/ } @ps_cmd){
$client{'name'} = 'gribble';
@@ -6436,14 +6269,17 @@ sub perl_python_client {
$client{'name-print'} = "Unknown $client{'name'} client";
}
if ($b_log){
- my $string = "namep: $client{'name-print'} name: $client{'name'} version: $client{'version'}";
+ my $string = "namep: $client{'name-print'} name: $client{'name'} ";
+ $string .= " version: $client{'version'}";
main::log_data('data',$string);
}
eval $end if $b_log;
}
-## try to infer the use of Konversation >= 1.2, which shows $PPID improperly
-## no known method of finding Konvi >= 1.2 as parent process, so we look to see if it is running,
-## and all other irc clients are not running. As of 2014-03-25 this isn't used in my cases
+
+# Try to infer the use of Konversation >= 1.2, which shows $PPID improperly
+# no known method of finding Konvi >= 1.2 as parent process, so we look to
+# see if it is running, and all other irc clients are not running. As of
+# 2014-03-25 this isn't used in my cases
sub check_modern_konvi {
eval $start if $b_log;
return 0 if !$client{'qdbus'};
@@ -6467,8 +6303,8 @@ sub check_modern_konvi {
}
# print "$pid $konvi\n";
if ($konvi){
- @app = main::program_values('konversation');
- $konvi_version = main::program_version($konvi,$app[0],$app[1],$app[2],$app[5],$app[6]);
+ my @app = ProgramData::values('konversation');
+ $konvi_version = ProgramData::version($konvi,$app[0],$app[1],$app[2],$app[5],$app[6]);
$client{'console-irc'} = $app[4];
$client{'konvi'} = 3;
$client{'name'} = 'konversation';
@@ -6493,6 +6329,7 @@ sub check_modern_konvi {
eval $end if $b_log;
return $b_modern_konvi;
}
+
sub set_konvi_data {
eval $start if $b_log;
# https://userbase.kde.org/Konversation/Scripts/Scripting_guide
@@ -6509,27 +6346,6 @@ sub set_konvi_data {
}
# for some reason this logic hiccups on multiple spaces between args
@ARGV = grep { $_ ne '' } @ARGV;
- # my $config_cmd = '';
- # there's no current kde 5 konvi config tool that we're aware of. Correct if changes.
- # This part may never have worked, but I don't have legacy data to determine.
- # The idea was to get inxi.conf files from konvi data stores, but that was never right.
- # if (main::check_program('kde4-config')){
- # $config_cmd = 'kde4-config --path data';
- # }
- # kde5-coinfig never existed, was replaced by $XDG_DATA_HOME in KDE
- # elsif (main::check_program('kde-config')){
- # $config_cmd = 'kde-config --path data';
- # }
- # elsif (main::check_program('qtpaths')){
- # $config_cmd = 'qtpaths --paths GenericDataLocation';
- # }
- # The section below is on request of Argonel from the Konversation developer team:
- # it sources config files like $HOME/.kde/share/apps/konversation/scripts/inxi.conf
- # if ($config_cmd){
- # my @data = main::grabber("$config_cmd 2>/dev/null",':');
- # Configs::set(\@data) if @data;
- # main::log_data('dump',"kde config \@data",\@data) if $b_log;
- # }
eval $end if $b_log;
}
}
@@ -6636,7 +6452,7 @@ sub clean_regex {
return $string;
}
-# $extra optional, if you want to add custom filter to defaults
+# args: 0: string; 1: 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 |';
@@ -6647,9 +6463,10 @@ sub clean_unset {
}
sub filter {
- my ($string) = @_;
+ my ($string,$type) = @_;
if ($string){
- if ($use{'filter'} && $string ne message('root-required')){
+ $type ||= 'filter';
+ if ($use{$type} && $string ne message('root-required')){
$string = $filter_string;
}
}
@@ -6659,7 +6476,7 @@ sub filter {
return $string;
}
-# note, let the print logic handle N/A cases
+# Note, let the print logic handle N/A cases
sub filter_partition {
my ($source,$string,$type) = @_;
return $string if !$string || $string eq 'N/A';
@@ -6681,7 +6498,7 @@ sub filter_pci_long {
return $string;
}
-# args: list of values, return the first one that is defined
+# args: 0: list of values. Return the first one that is defined.
sub get_defined {
for (@_){
return $_ if defined $_;
@@ -6689,8 +6506,8 @@ sub get_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
+# args: 0: vendor id; 1: product id.
+# Returns print ready vendor:chip id string, or na variants
sub get_chip_id {
my ($vendor,$product)= @_;
my $id = 'N/A';
@@ -6705,9 +6522,10 @@ sub get_chip_id {
}
return $id;
}
-# args: $1 - size in KB, return KB, MB, GB, TB, PB, EB; $2 - 'string';
-# $3 - default value if null
-# returns string with units or array or size unmodified if not numeric
+
+# args: 0: size in KiB, return KiB, MiB, GiB, TiB, PiB, EiB; 1: 'string';
+# 2: default value if null. Assumes KiB input.
+# Returns string with units or array or size unmodified if not numeric
sub get_size {
my ($size,$type,$empty) = @_;
my (@data);
@@ -6772,11 +6590,37 @@ sub make_line {
return $line;
}
+# Takes an array ref, creates value ref, comma separated, with ','/', '
+# depending on assigned max list value length.
+# args: 0: array ref; 1: value result ref; 2: [separator]; 3: [sort];
+# 4: [N/A value, if missing, return undef]
+sub make_list_value {
+ my $sep = $_[2];
+ $sep ||= ',';
+ if (!defined $_[0] || !@{$_[0]}){
+ ${$_[1]} = $_[4] if $_[4];
+ return;
+ }
+ # note: printer only wraps if value 'word' count > 2, and trick with quoting
+ # array includes 1 white space between values
+ if (scalar @{$_[0]} > 2 && length("@{$_[0]}") > $size{'max-join-list'}){
+ $sep .= ' ';
+ }
+ @{$_[0]} = sort {"\L$a" cmp "\L$b"} @{$_[0]} if $_[3] && $_[3] eq 'sort';
+ ${$_[1]} = join($sep,@{$_[0]});
+}
+
+# args: 0: type; 1: info [optional]; 2: info [optional]
sub message {
- my ($type,$id) = @_;
+ my ($type,$id,$id2) = @_;
$id ||= '';
+ $id2 ||= '';
my %message = (
'arm-cpu-f' => 'Use -f option to see features',
+ 'audio-server-on-pipewire-pulse' => 'off (using pipewire-pulse)',
+ 'audio-server-process-on' => 'active (process)',
+ 'audio-server-root-na' => 'n/a (root, process)',
+ 'audio-server-root-on' => 'active (root, process)',
'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.',
@@ -6792,7 +6636,8 @@ sub message {
'disk-data' => 'No disk data found.',
'disk-data-bsd' => 'No disk data found.',
'disk-size-0' => 'Total N/A',
- 'display-driver-na' => 'X driver n/a',
+ 'display-driver-na' => 'X driver n/a', # legacy, leave for now
+ 'display-driver-na-try-root' => 'X driver n/a, try sudo/root',
'display-server' => 'No display server data found. Headless machine?',
'dmesg-boot-permissions' => 'dmesg.boot permissions',
'dmesg-boot-missing' => 'dmesg.boot not found',
@@ -6801,18 +6646,22 @@ sub message {
'edid-revision' => "invalid EDID revision: $id",
'edid-sync' => "bad sync value: $id",
'edid-version' => "invalid EDID version: $id",
- 'egl-wayland' => 'No known Wayland EGL/GBM data sources.',
- 'egl-wayland-console' => 'No known Wayland EGL/GBM data sources.',
- 'gfx-api' => 'No display API data. No known data sources.',
- 'gfx-api-console' => 'No display API data available in console. Headless machine?',
- 'gfx-api-xvesa' => 'No Xvesa VBE/GOP data found.',
- 'gl-console-glxinfo-missing' => 'GL data unavailable in console and glxinfo missing.',
- 'gl-console-root' => 'GL data unavailable in console for root.',
- 'gl-console-try' => 'GL data unavailable in console. Try -G --display',
- 'gl-display-root' => 'GL data unavailable for root.',
- 'gl-null' => 'No GL data found on this system.',
- 'gl-value-empty' => 'Unset. Missing GL driver?',
- 'glxinfo-missing' => 'Unable to show GL data. Required tool glxinfo missing.',
+ 'egl-missing' => 'EGL data requires eglinfo. Check --recommends.',
+ 'egl-missing-console' => 'EGL data unavailable in console, eglinfo missing.',
+ 'egl-null' => 'No EGL data available.',
+ 'file-unreadable' => 'File not readable (permissions?)',
+ 'gfx-api' => 'No display API data available.',
+ 'gfx-api-console' => 'No API data available in console. Headless machine?',
+ 'glx-console-root' => 'GL data unavailable in console for root.',
+ 'glx-console-try' => 'GL data unavailable in console. Try -G --display',
+ 'glx-display-root' => 'GL data unavailable for root.',
+ 'glx-egl' => 'incomplete (EGL sourced)',
+ 'glx-egl-console' => 'console (EGL sourced)',
+ 'glx-egl-missing' => 'glxinfo missing (EGL sourced)',
+ 'glx-missing' => 'Unable to show GL data. glxinfo is missing.',
+ 'glx-missing-console' => 'GL data unavailable in console, glxinfo missing.',
+ 'glx-null' => 'No GL data available.',
+ 'glx-value-empty' => 'Unset. Missing GL driver?',
'IP' => "No $id found. Connected to web? SSL issues?",
'IP-dig' => "No $id found. Connected to web? SSL issues? Try --no-dig",
'IP-no-dig' => "No $id found. Connected to web? SSL issues? Try enabling dig",
@@ -6827,12 +6676,14 @@ sub message {
'monitor-id' => 'not-matched',
'monitor-na' => 'N/A',
'monitor-wayland' => 'no compositor data',
+ 'network-services' => 'No services found.',
'note-check' => 'check',
'note-est' => 'est.',
'note-not-reliable' => 'not reliable',
'nv-current' => "current (as of $id)",
+ 'nv-current-eol' => "current (as of $id; EOL~$id2)",
'nv-legacy-active' => "legacy-active (EOL~$id)",
- 'nv-legacy-eol' => 'legacy (EOL)',
+ 'nv-legacy-eol' => "legacy (EOL~$id)",
'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:",
@@ -6845,12 +6696,16 @@ sub message {
'pci-card-data' => 'No PCI device data found.',
'pci-card-data-root' => 'PCI device data requires root.',
'pci-slot-data' => 'No PCI Slot data found.',
- 'pm-rpm-disabled' => 'see --rpm',
+ 'pm-disabled' => "see --$id",
'ps-data-null' => 'No process data available.',
'raid-data' => 'No RAID data found.',
- 'ram-data' => 'No RAM data found.',
+ 'ram-data' => "No RAM data found using $id.",
'ram-data-complete' => 'For complete report, try with --dmidecode',
'ram-data-dmidecode' => 'No RAM data found. Try with --dmidecode',
+ 'ram-no-module' => 'no module installed',
+ 'ram-udevadm' => 'For most reliable report, use superuser + dmidecode.',
+ 'ram-udevadm-root' => 'For most reliable report, install dmidecode.',
+ 'ram-udevadm-version' => "Installed udevadm v$id. Requires >= 249. Try root?",
'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?",
@@ -6860,7 +6715,7 @@ sub message {
'root-required' => '<superuser required>',
'root-suggested' => 'try sudo/root',# gdm only
'screen-wayland' => 'no compositor data',
- 'screen-xvesa' => 'no Xvesa data',
+ 'screen-tinyx' => "no X$id data",
'sensor-data-bsd' => "$id sensor data found but not usable.",
'sensor-data-bsd-ok' => 'No sensor data found. Are data sources present?',
'sensor-data-bsd-unsupported' => 'Sensor data not available. Unsupported BSD variant.',
@@ -6893,18 +6748,23 @@ sub message {
'unmounted-file' => 'No /proc/partitions file found.',
'unsupported' => '<unsupported>',
'usb-data' => 'No USB data found. Server?',
+ 'usb-mode-mismatch' => '<unknown rev+speed>',
'unknown-cpu-topology' => 'ERR-103',
'unknown-desktop-version' => 'ERR-101',
'unknown-dev' => 'ERR-102',
'unknown-device-id' => 'unknown device ID',
'unknown-shell' => 'ERR-100',
+ 'vulkan-missing' => 'Unable to show Vulkan data. vulkaninfo is missing.', # not used yet
+ 'vulkan-null' => 'No Vulkan data available.',
'weather-error' => "Error: $id",
'weather-null' => "No $id found. Internet connection working?",
+ 'xvesa-null' => 'No Xvesa VBE/GOP data found.',
);
return $message{$type};
}
-# string of range types (2-5; 3 4; 3,4,2-12) to generate single regex string for
+# args: 0: 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;
@@ -6932,15 +6792,16 @@ sub remove_duplicates {
return $string;
}
-# convert string passed to KB, based on GB/MB/TB id
-# NOTE: K 1024 KB 1000 KiB 1024
+# args: 0: string to turn to KiB integer value.
+# Convert string passed to KB, based on GB/MB/TB id
+# NOTE: 1 [K 1000; kB: 1000; KB 1024; KiB 1024] bytes
# The logic will turn false MB to M for this tool
# Hopefully one day sizes will all be in KiB type units
sub translate_size {
my ($working) = @_;
my ($size,$unit) = (0,'');
# print ":$working:\n";
- return if ! defined $working;
+ return if !defined $working;
my $math = ($working =~ /B$/) ? 1000: 1024;
if ($working =~ /^([0-9\.]+)\s*([kKMGTPE])i?B?$/i){
$size = $1;
@@ -6983,7 +6844,7 @@ sub check_output_path {
return $b_good;
}
-# passing along hash ref
+# Passing along hash ref
sub output_handler {
my ($data) = @_;
# print Dumper \%data;
@@ -6998,7 +6859,7 @@ sub output_handler {
}
}
-# passing along hash ref
+# Passing along hash ref
# NOTE: file has already been set and directory verified
sub generate_json {
eval $start if $b_log;
@@ -7168,9 +7029,8 @@ sub print_basic {
}
}
-# this has to get a hash of hashes, at least for now.
-# because perl does not retain insertion order, I use a prefix for each
-# hash key to force sorts.
+# This has to get a hash of hashes, at least for now. Because perl does not
+# retain insertion order, I use a prefix for each hash key to force sorts.
sub print_data {
my ($data) = @_;
my ($counter,$length,$split_count) = (0,0,0);
@@ -7197,7 +7057,7 @@ sub print_data {
}
$start_holder = $key;
$indent_2 = $indent + $size{'indents'};
- $b_ni2 = ($start_holder eq 'Info') ? 1 : 0;
+ $b_ni2 = 0; # ($start_holder eq 'Info') ? 1 : 0;
if ($indent < 10){
$line = "$start\n";
print_line($line);
@@ -7225,7 +7085,7 @@ sub print_data {
'Monitor' => 1,
'Optical' => 1,
'Screen' => 1,
- 'Sound Server' => 1,
+ 'Server' => 1, # was 'Sound Server'
'variant' => 1, # arm > 1 cpu type
);
foreach my $val1 (@{$data->{$key1}}){
@@ -7263,7 +7123,7 @@ sub print_data {
if (!$b_single && $val2 || $val2 eq '0'){
$val2 .= " ";
}
- # see: Use of implicit split to @_ is deprecated. Only get this
+ # See: Use of implicit split to @_ is deprecated. Only get this
# warning in Perl 5.08 oddly enough. ie, no: scalar (split(...));
my @values = split(/\s+/, $val2);
$split_count = scalar @values;
@@ -7274,7 +7134,7 @@ sub print_data {
$length += length("$key$sep{'s2'} $val2");
$holder .= "$colors{'c1'}$key$sep{'s2'}$colors{'c2'} $val2";
}
- # handle case where the key/value pair is > max, and where there are
+ # 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. But we don't
# want to wrap things like: 3.45 MiB (6.3%)
@@ -7284,7 +7144,7 @@ sub print_data {
# print "m-2 r1: $b_row1 iu: $indent_use\n";
$val3 = shift @values;
$start2 = "$colors{'c1'}$key$sep{'s2'}$colors{'c2'} $val3 ";
- # case where not first item in line, but when key+first word added,
+ # 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'}){
@@ -7338,7 +7198,7 @@ sub print_data {
$start = '';
}
}
- # we don't want to start a new line, continue until full length.
+ # We don't want to start a new line, continue until full length.
if ($holder2 !~ /^\s*$/){
# print "p-2: r1: $b_row1 iu: $indent_use\n";
$holder2 = "$colors{'c2'}$holder2";
@@ -7386,28 +7246,31 @@ sub print_data {
$start = '';
}
}
- # only for repos currently
+ # Only for repos currently
elsif (ref($val1) eq 'ARRAY'){
# print "p-5: r1: $b_row1 iu: $indent_use\n";
- my $array=0;
+ my $num = 0;
+ my ($l1,$l2);
$indent_use = $indent_2;
foreach my $item (@$val1){
- $array++;
+ $num++;
if ($size{'max-lines'}){
- my $l1 = length("$array$sep{'s2'} $item") + $indent_use;
+ $l1 = length("$num$sep{'s2'} $item") + $indent_use;
+ # Cut down the line string until it's short enough to fit in term
if ($l1 > $size{'term-cols'}){
- my $l2 = length("$array$sep{'s2'} ") + $indent_use + 6;
- # print "$l1 $size{'term-cols'} $l2 $array $indent_use\n";
+ $l2 = length("$num$sep{'s2'} ") + $indent_use + 6;
+ # print "$l1 $size{'term-cols'} $l2 $num $indent_use\n";
$item = substr($item,0,$size{'term-cols'} - $l2) . '[...]';
}
}
- $line = "$colors{'c1'}$array$sep{'s2'} $colors{'c2'}$item$colors{'cn'}";
+ $line = "$colors{'c1'}$num$sep{'s2'} $colors{'c2'}$item$colors{'cn'}";
$line = sprintf("%-${indent_use}s%s\n","","$line");
print_line($line);
}
+
}
}
- # we want a space between data blocks for single
+ # We want a space between data blocks for single
print_line("\n") if $b_single;
}
}
@@ -7436,9 +7299,9 @@ sub print_line {
# -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'})){
+ $size{'max-lines'} == $size{'lines'}) ||
+ ($size{'max-lines'} < $size{'term-lines'} &&
+ $size{'max-lines'} + 1 == $size{'lines'})){
output_control();
}
}
@@ -7486,7 +7349,7 @@ sub get {
}
@$rows = ({main::key($num++,0,1,$key) => main::message($type,'')});
}
- sound_server_output($rows);
+ sound_output($rows);
eval $end if $b_log;
return $rows;
}
@@ -7543,6 +7406,7 @@ sub device_output {
}
eval $end if $b_log;
}
+
# this handles fringe cases where there is no card on pcibus,
# but there is a card present. I don't know the exact architecture
# involved but I know this situation exists on at least one old machine.
@@ -7579,6 +7443,7 @@ sub asound_output {
# print Data::Dumper:Dumper $rows;
eval $end if $b_log;
}
+
sub usb_output {
eval $start if $b_log;
my $rows = $_[0];
@@ -7586,133 +7451,457 @@ sub usb_output {
my ($j,$num) = (0,1);
return if !$usb{'audio'};
foreach my $row (@{$usb{'audio'}}){
- # print Data::Dumper::Dumper $row;
$num = 1;
+ $j = scalar @$rows;
# make sure to reset, or second device trips last flag
($path_id,$product) = ('','');
$product = main::clean($row->[13]) if $row->[13];
- $path_id = $row->[2] if $row->[2];
$product ||= 'N/A';
$row->[15] ||= 'N/A';
push(@$rows, {
main::key($num++,1,1,'Device') => $product,
- main::key($num++,0,2,'type') => 'USB',
main::key($num++,0,2,'driver') => $row->[15],
+ main::key($num++,1,2,'type') => 'USB',
});
if ($extra > 0){
+ # print "$j \n";
+ if ($extra > 1){
+ $row->[8] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'rev')} = $row->[8];
+ if ($row->[17]){
+ $rows->[$j]{main::key($num++,0,3,'speed')} = $row->[17];
+ }
+ if ($row->[24]){
+ $rows->[$j]{main::key($num++,0,3,'lanes')} = $row->[24];
+ }
+ if ($b_admin && $row->[22]){
+ $rows->[$j]{main::key($num++,0,3,'mode')} = $row->[22];
+ }
+ }
+ $path_id = $row->[2] if $row->[2];
$rows->[$j]{main::key($num++,0,2,'bus-ID')} = "$path_id:$row->[1]";
+ if ($extra > 1){
+ $row->[7] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
+ }
+ if ($extra > 2){
+ if (defined $row->[5] && $row->[5] ne ''){
+ $rows->[$j]{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]";
+ }
+ if ($row->[16]){
+ $rows->[$j]{main::key($num++,0,2,'serial')} = main::filter($row->[16]);
+ }
+ }
}
- if ($extra > 1){
- $row->[7] ||= 'N/A';
- $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
- }
- if ($extra > 2 && defined $row->[5] && $row->[5] ne ''){
- $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::filter($row->[16]);
- }
- $j = scalar @$rows;
}
eval $end if $b_log;
}
-sub sound_server_output {
+
+sub sound_output {
eval $start if $b_log;
my $rows = $_[0];
- my ($program);
+ my ($key,$program,$value);
my ($j,$num) = (0,0);
- foreach my $server (@{sound_server_data()}){
- next if $extra < 1 && (!$server->[3] || $server->[3] ne 'yes');
+ foreach my $server (@{sound_data()}){
+ next if $extra < 1 && (!$server->[3] || $server->[3] !~ /^(active|.*api)/);
$j = scalar @$rows;
$server->[2] ||= 'N/A';
$server->[3] ||= 'N/A';
push(@$rows, {
main::key($num++,1,1,$server->[0]) => $server->[1],
main::key($num++,0,2,'v') => $server->[2],
- main::key($num++,0,2,'running') => $server->[3],
+ main::key($num++,0,2,'status') => $server->[3],
});
- }
- eval $end if $b_log;
-}
-sub sound_server_data {
- eval $start if $b_log;
- my ($program,$running,$server,$type,$version);
- my $servers = [];
- if (my $file = $system_files{'asound-version'}){
- # avoid possible second line if compiled by user
- my $content = main::reader($file,'',0);
- # some alsa strings have the build date in (...)
- $version = (split(/\s+/, $content))[-1];
- $version =~ s/\.$//; # trim off period
- $server = 'ALSA';
- $type = 'Sound API';
- $running = 'yes';
- # not needed I think, if asound is there, it's running, but if that's
- # not correct, can use one of the info/list/stat tests for aplay
- # if (main::check_program('aplay') && main::grabber('aplay -l 2>/dev/null')){
- # $running = 'yes';
- # }
- push(@$servers, [$type,$server,$version,$running]);
- ($running,$version) = ('','');
- }
- # sndstat file may be removed in linux oss
- if (-e '/dev/sndstat' || ($program = main::check_program('ossinfo'))){
- $server = 'OSS';
- $type = 'Sound API';
- #$version = main::program_version('oss','\S',2);
- $version = (grep {/^hw.snd.version:/} @{$sysctl{'audio'}})[0] if $sysctl{'audio'};
- $version = (split(/:\s*/,$version),1)[1] if $version;
- $version =~ s|/.*$|| if $version;
- # not a great test, but ok for now
- $running = (-e '/dev/sndstat') ? 'yes' : 'no?';
- push(@$servers, [$type,$server,$version,$running]);
- ($running,$version) = ('','');
+ if ($extra > 1 && defined $server->[4] && ref $server->[4] eq 'ARRAY'){
+ my $b_multi = (scalar @{$server->[4]} > 1) ? 1: 0;
+ my $b_start;
+ my $k = 0;
+ foreach my $item (@{$server->[4]}){
+ if ($item->[2] eq 'daemon'){
+ $key = 'status';
+ $value = $item->[3];
+ }
+ else {
+ $key = 'type';
+ $value = $item->[2];
+ }
+ if (!$b_multi){
+ $rows->[$j]{main::key($num++,1,2,$item->[0])} = $item->[1];
+ $rows->[$j]{main::key($num++,0,3,$key)} = $value;
+ }
+ else {
+ $rows->[$j]{main::key($num++,1,2,$item->[0])} = '' if !$b_start;
+ $b_start = 1;
+ $k++;
+ $rows->[$j]{main::key($num++,1,3,$k)} = $item->[1];
+ $rows->[$j]{main::key($num++,0,4,$key)} = $value;
+ }
+ }
+ }
+ if ($b_admin){
+ # Let long lines wrap for high tool counts, but best avoid too many tools
+ my $join = (defined $server->[5] && length(join(',',@{$server->[5]})) > 40) ? ', ': ',';
+ my $val = (defined $server->[5]) ? join($join,@{$server->[5]}) : 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'tools')} = $val;
+ }
+ }
+ eval $end if $b_log;
+}
+
+# see docs/inxi-audio.txt for unused or alternate helpers/tools
+sub sound_data {
+ eval $start if $b_log;
+ my ($config,$helpers,$name,$program,$status,$test,$tools,$type,$version);
+ my $data = [];
+ ## API Types ##
+ # not yet, user lib: || main::globber('/usr/lib*{,/*}/libasound.so*')
+ # the config test is expensive but will only trigger on servers with no audio
+ # devices. Checks if kernel was compiled with SND_ items, even if no devices.
+ if (!$bsd_type && -r "/boot/config-$uname[2]"){
+ $config = "/boot/config-$uname[2]";
+ }
+ if ($system_files{'asound-version'} ||
+ ($config && (grep {/^CONFIG_SND_/} @{main::reader($config,'','ref')}))){
+ $name = 'ALSA';
+ $type = 'API';
+ # always true until find better test for inactive API test
+ if ($system_files{'asound-version'}){
+ # avoid possible second line if compiled by user
+ my $content = main::reader($system_files{'asound-version'},'',0);
+ # we want the string after driver version for old and new ALSA
+ # some alsa strings have the build date in (...) after Version
+ if ($content =~ /Driver Version (\S+)(\s|\.?$)/){
+ $version = $1;
+ $version =~ s/\.$//; # trim off period
+ }
+ $status = 'kernel-api';
+ }
+ else {
+ $status = 'inactive';
+ $version = $uname[2];
+ $version =~ s/^k//; # avoid double kk possible result
+ $version = 'k' . $version;
+ }
+ if ($extra > 1){
+ $test = [['osspd','daemon'],['aoss','oss-emulator'],
+ ['apulse','pulse-emulator'],];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ $test = [qw(alsactl alsamixer alsamixergui amixer)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
+ }
+ # sndstat file may be removed in linux oss, but ossinfo part of oss4-base
+ # alsa oss compat driver will create /dev/sndstat in linux however
+ # Note: kernel compile: SOUND_OSS
+ if ((-e '/dev/sndstat' && !$system_files{'asound-version'}) ||
+ main::check_program('ossinfo')){
+ $name = 'OSS';
+ # not a great test, but ok for now, check on current Linux, seems unlikely
+ # to find OSS on OpenBSD in general.
+ if ($bsd_type){
+ $status = (-e '/dev/sndstat') ? 'kernel-api' : 'inactive';
+ }
+ else {
+ $status = (-e '/dev/sndstat') ? 'active' : 'off?';
+ }
+ $type = 'API'; # not strictly an API on linux, but almost nobody uses it.
+ # not certain to be cross distro, Debian/Ubuntu at least.
+ if (-e '/etc/oss4/version.dat'){
+ $version = main::reader('/etc/oss4/version.dat','',0);
+ }
+ elsif ($sysctl{'audio'}){
+ $version = (grep {/^hw.snd.version:/} @{$sysctl{'audio'}})[0];
+ $version = (split(/:\s*/,$version),1)[1] if $version;
+ $version =~ s|/.*$|| if $version;
+ }
+ if ($extra > 1){
+ # virtual_oss freebsd, not verified; osspd-alsa/pulseaudio no path exec
+ $test = [['virtual_oss','daemon'],['virtual_equalizer','plugin']];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ # *mixer are FreeBSD tools
+ $test = [qw(dsbmixer mixer ossctl ossinfo ossmix ossxmix vmixctl)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
}
if ($program = main::check_program('sndiod')){
- $server = 'sndio';
- $type = 'Sound Interface';
- #$version = main::program_version('sndio','\S',2);
- $running = (grep {/sndiod/} @ps_cmd) ? 'yes': 'no';
- push(@$servers, [$type,$server,$version,$running]);
- ($running,$version) = ('','');
+ if ($bsd_type){
+ push(@$data, ['API','sndio',undef,'sound-api',undef,undef]);
+ }
+ $name = 'sndiod';
+ # verified: accurate
+ $status = (grep {/sndiod/} @ps_cmd) ? 'active': 'off';
+ $type = 'Server';
+ # $version: no known method
+ if ($b_admin){
+ $test = [qw(aucat midicat mixerctl sndioctl)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
+ }
+ ## Servers ##
+ if ($program = main::check_program('artsd')){
+ ($name,$version) = ProgramData::full('arts',$program);
+ $status = (grep {/artsd/} @ps_cmd) ? 'active': 'off';
+ $type = 'Server';
+ if ($extra > 1){
+ $test = [['artswrapper','daemon'],];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ $test = [qw(artsbuilder artsdsp)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
+ }
+ # pulseaudio-esound-compat has esd pointing to esdcompat
+ if (($program = main::check_program('esd')) &&
+ !main::check_program('esdcompat')){
+ ($name,$version) = ProgramData::full('esound',$program);
+ $status = (grep {/\besd\b/} @ps_cmd) ? 'active': 'off';
+ $type = 'Server';
+ # if ($extra > 1){
+ # $test = [['','daemon'],];
+ # $helpers = sound_helpers($test);
+ # }
+ if ($b_admin){
+ $test = [qw(esdcat esdctl esddsp)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
}
if ($program = main::check_program('jackd')){
- $server = 'JACK';
- $type = 'Sound Server';
- $version = main::program_version($program,'^jackd',3,'--version',1);
- $running = (grep {/jackd/} @ps_cmd) ? 'yes':'no' ;
- push(@$servers, [$type,$server,$version,$running]);
- ($running,$version) = ('','');
+ ($name,$version) = ProgramData::full('jack',$program);
+ $status = jack_status();
+ $type = 'Server';
+ if ($extra > 1){
+ $test = [['a2jmidid','daemon'],['nsmd','daemon']];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ $test = [qw(agordejo cadence jack_control jack_mixer qjackctl)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
}
- # note: pactl info/list/stat could be used
- if ($program = main::check_program('pactl')){
- $server = 'PulseAudio';
- $type = 'Sound Server';
- $version = main::program_version($program,'^pactl',2,'--version',1);
- $running = (grep {m|/pulseaudiod?\b|} @ps_cmd) ? 'yes':'no' ;
- push(@$servers, [$type,$server,$version,$running]);
- ($running,$version) = ('','');
+ if ($program = main::check_program('nasd')){
+ ($name,$version) = ProgramData::full('nas',$program);
+ $status = (grep {/(^|\/)nasd/} @ps_cmd) ? 'active': 'off';
+ $type = 'Server';
+ if ($extra > 1){
+ $test = [['audiooss','oss-compat'],];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ $test = [qw(auctl auinfo)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
}
if ($program = main::check_program('pipewire')){
- $server = 'PipeWire';
- $type = 'Sound Server';
- $version = main::program_version($program,'^Compiled with libpipe',4,'--version',1);
- $running = (grep {/pipewire/} @ps_cmd) ? 'yes':'no' ;
- push(@$servers, [$type,$server,$version,$running]);
- ($running,$version) = ('','');
+ ($name,$version) = ProgramData::full('pipewire',$program);
+ $status = pipewire_status();
+ $type = 'Server';
+ if ($extra > 1){
+ # pipewire-alsa is a plugin, but is just some config files
+ $test = [['pipewire-pulse','daemon'],['pipewire-media-session','daemon'],
+ ['wireplumber','daemon'],
+ ['pipewire-alsa','plugin','/etc/alsa/conf.d/*-pipewire-default.conf'],
+ ['pw-jack','plugin']];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ $test = [qw(pw-cat pw-cli wpctl)];
+ # note: pactl can be used w/pipewire-pulse;
+ if (!main::check_program('pulseaudio') &&
+ main::check_program('pipewire-pulse')){
+ splice(@$test,0,0,'pactl');
+ }
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
+ }
+ # note: pactl info/list/stat could be used
+ if ($program = main::check_program('pulseaudio')){
+ ($name,$version) = ProgramData::full('pulseaudio',$program);
+ $status = pulse_status($program);
+ $type = 'Server';
+ if ($extra > 1){
+ $test = [['pulseaudio-dlna','daemon'],
+ ['pulseaudio-alsa','plugin','/etc/alsa/conf.d/*-pulseaudio-default.conf'],
+ ['esdcompat','plugin'],
+ ['pulseaudio-jack','module','/usr/lib/pulse*/modules/module-jack-sink.so']];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ $test = [qw(pacat pactl paman pamix pamixer pavucontrol pulsemixer)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
+ }
+ if ($program = main::check_program('roard')){
+ ($name,$version) = ProgramData::full('roaraudio',$program);# no version so far
+ $status = (grep {/roard/} @ps_cmd) ? 'active': 'off';
+ $type = 'Server';
+ if ($extra > 1){
+ $test = [['roarplaylistd','daemon'],['roarify','pulse/viff-emulation']];
+ $helpers = sound_helpers($test);
+ }
+ if ($b_admin){
+ $test = [qw(roarcat roarctl)];
+ $tools = sound_tools($test);
+ }
+ push(@$data,[$type,$name,$version,$status,$helpers,$tools]);
+ ($status,$version,$helpers,$tools) = ('','',undef,undef);
+ }
+ main::log_data('dump','sound data: @$data',$data) if $b_log;
+ print 'Sound data: ', Data::Dumper::Dumper $data if $dbg[26];
+ eval $end if $b_log;
+ return $data;
+}
+
+# assume if jackd running we have active jack, update if required
+sub jack_status {
+ eval $start if $b_log;
+ my $status;
+ if (grep {/jackd/} @ps_cmd){
+ if (my $program = main::check_program('jack_control')){
+ system("$program status > /dev/null 2>&1");
+ # 0 means running, always, else 1.
+ if ($? == 0){
+ $status = 'active';
+ }
+ else {
+ $status = ($b_root) ? main::message('audio-server-root-na') : 'off';
+ }
+ }
+ $status = main::message('audio-server-process-on') if !$status;
+ }
+ else {
+ $status = 'off';
+ }
+ eval $end if $b_log;
+ return $status;
+}
+
+# pipewire is complicated, it can be there and running without being active server
+# This is NOT verified as valid true/yes case!!
+sub pipewire_status {
+ eval $start if $b_log;
+ my ($b_process,$program,$status,@data);
+ if (grep {/(^|\/)pipewire(d|\s|:|$)/} @ps_cmd){
+ # note: if pipewire was stopped but not masked, pw-cli can start service so
+ # only use if pipewire process already running
+ if ($program = main::check_program('pw-cli')){
+ @data = qx($program ls 2>/dev/null);
+ main::log_data('dump','pw-cli @data', \@data) if $b_log;
+ print 'pw-cli: ', Data::Dumper::Dumper \@data if $dbg[52];
+ if (@data){
+ $status = (grep {/media\.class\s*=\s*"(Audio|Midi)/i} @data) ? 'active' : 'off';
+ }
+ elsif ($b_root){
+ $status = main::message('audio-server-root-na');
+ }
+ }
+ $status = main::message('audio-server-process-on') if !$status;
+ }
+ else {
+ $status = 'off';
+ }
+ eval $end if $b_log;
+ return $status;
+}
+
+# pulse might be running through pipewire
+sub pulse_status {
+ eval $start if $b_log;
+ my $program = $_[0];
+ my ($status,@data);
+ if (grep {/(^|\/)pulseaudiod?\b/} @ps_cmd){
+ # this is almost certainly not needed, but keep for now
+ system("$program --check > /dev/null 2>&1");
+ # 0 means running, always, other could be an error.
+ if ($? == 0){
+ $status = 'active';
+ }
+ else {
+ $status = ($b_root) ? main::message('audio-server-root-on') : 'off';
+ }
+ }
+ else {
+ # can't use pactl info test because starts pulseaudio/pipewire if unmasked
+ if (main::check_program('pipewire-pulse') &&
+ (grep {/(^|\/)pipewire-pulse/} @ps_cmd)){
+ $status = main::message('audio-server-on-pipewire-pulse');
+ }
+ else {
+ $status = 'off';
+ }
+ }
+ eval $end if $b_log;
+ return $status;
+}
+
+sub sound_helpers {
+ eval $start if $b_log;
+ my $test = $_[0];
+ my ($helpers,$name,$status,$key);
+ foreach my $item (@$test){
+ if (main::check_program($item->[0]) ||
+ (defined $item->[2] && main::globber($item->[2]))){
+ $name = $item->[0];
+ $key = 'with';
+ # these are active/off daemons unless not a daemon
+ if ($item->[1] eq 'daemon'){
+ $status = (grep {/$item->[0]/} @ps_cmd) ? 'active':'off' ;
+ }
+ else {
+ $status = $item->[1];
+ }
+ push(@$helpers,[$key,$name,$item->[1],$status]);
+ }
+ }
+ # push(@$helpers, ['with','pipewire-pulse','daemon','active'],['with','pw-jack','plugin']);
+ # push(@$helpers, ['with','pipewire-pulse','daemon','active']);
+ eval $end if $b_log;
+ # print Data::Dumper::Dumper $helpers;
+ return $helpers;
+}
+
+sub sound_tools {
+ eval $start if $b_log;
+ my $test = $_[0];
+ my $tools;
+ foreach my $item (@$test){
+ if (main::check_program($item)){
+ push(@$tools,$item);
+ }
}
- main::log_data('dump','sound servers: @$servers',$servers) if $b_log;
- print Data::Dumper::Dumper $servers if $dbg[26];
eval $end if $b_log;
- return $servers;
+ # print Data::Dumper::Dumper $tools;
+ return $tools;
}
}
## BatteryItem
{
package BatteryItem;
-
my (@upower_items,$b_upower,$upower);
+
sub get {
eval $start if $b_log;
my ($key1,$val1);
@@ -7777,27 +7966,28 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
# alarm capacity capacity_level charge_full charge_full_design charge_now
-# cycle_count energy_full energy_full_design energy_now location manufacturer model_name
-# power_now present serial_number status technology type voltage_min_design voltage_now
-# 0 name - battery id, not used
-# 1 status
-# 2 present
-# 3 technology
-# 4 cycle_count
-# 5 voltage_min_design
-# 6 voltage_now
-# 7 power_now
-# 8 energy_full_design
-# 9 energy_full
-# 10 energy_now
-# 11 capacity
-# 12 capacity_level
-# 13 of_orig
-# 14 model_name
-# 15 manufacturer
-# 16 serial_number
-# 17 location
+# cycle_count energy_full energy_full_design energy_now location manufacturer model_name
+# power_now present serial_number status technology type voltage_min_design voltage_now
+# 0: name - battery id, not used
+# 1: status
+# 2: present
+# 3: technology
+# 4: cycle_count
+# 5: voltage_min_design
+# 6: voltage_now
+# 7: power_now
+# 8: energy_full_design
+# 9: energy_full
+# 10: energy_now
+# 11: capacity
+# 12: capacity_level
+# 13: of_orig
+# 14: model_name
+# 15: manufacturer
+# 16: serial_number
+# 17: location
sub battery_output {
eval $start if $b_log;
my ($rows,$battery) = @_;
@@ -7843,6 +8033,11 @@ sub battery_output {
main::key($num++,0,2,'charge') => $charge,
main::key($num++,0,2,'condition') => $condition,
});
+ if ($extra > 2){
+ if ($battery->{$key}{'power_now'}){
+ $rows->[$j]{main::key($num++,0,2,'power')} = sprintf('%0.1f W',($battery->{$key}{'power_now'}/10**6));
+ }
+ }
if ($extra > 0 || ($battery->{$key}{'voltage_now'} &&
$battery->{$key}{'voltage_min_design'} &&
($battery->{$key}{'voltage_now'} - $battery->{$key}{'voltage_min_design'}) < 0.5)){
@@ -8076,6 +8271,7 @@ sub battery_data_sys {
main::log_data('dump','sys: %$battery',$battery) if $b_log;
eval $end if $b_log;
}
+
sub battery_data_sysctl {
eval $start if $b_log;
my $battery = $_[0];
@@ -8163,6 +8359,7 @@ sub battery_data_sysctl {
main::log_data('dump','dmi: %$battery',$battery) if $b_log;
eval $end if $b_log;
}
+
# note, dmidecode does not have charge_now or charge_full
sub battery_data_dmi {
eval $start if $b_log;
@@ -8215,18 +8412,19 @@ sub battery_data_dmi {
main::log_data('dump','dmi: %$battery',$battery) if $b_log;
eval $end if $b_log;
}
+
sub upower_data {
my ($id) = @_;
eval $start if $b_log;
my $data = {};
if (!$b_upower && $upower){
- @upower_items = main::grabber("$upower -e",'','strip');
+ @upower_items = main::grabber("$upower -e 2>/dev/null",'','strip');
$b_upower = 1;
}
if ($upower && @upower_items){
foreach (@upower_items){
if ($_ =~ /$id/){
- my @working = main::grabber("$upower -i $_",'','strip');
+ my @working = main::grabber("$upower -i $_ 2>/dev/null",'','strip');
foreach my $row (@working){
my @temp = split(/\s*:\s*/, $row);
if ($temp[0] eq 'percentage'){
@@ -8249,15 +8447,17 @@ sub upower_data {
## BluetoothItem
{
package BluetoothItem;
-
my ($b_bluetooth,$b_hci_error,$b_hci,$b_rfk,$b_service);
my ($service);
my (%hci);
+
sub get {
eval $start if $b_log;
my $rows = [];
my $num = 0;
- $b_bluetooth = 1 if @ps_cmd && (grep {m|/bluetoothd\b|} @ps_cmd);
+ if ($fake{'bluetooth'} || (@ps_cmd && (grep {m|/bluetoothd\b|} @ps_cmd))){
+ $b_bluetooth = 1;
+ }
# note: rapi 4 has pci bus
if (%risc && !$use{'soc-bluetooth'} && !$use{'pci-tool'}){
# do nothing, but keep the test conditions to force
@@ -8346,6 +8546,7 @@ sub device_output {
}
eval $end if $b_log;
}
+
sub usb_output {
eval $start if $b_log;
return if !$usb{'bluetooth'};
@@ -8364,47 +8565,52 @@ sub usb_output {
$path_id = $row->[2] if $row->[2];
push(@$rows, {
main::key($num++,1,1,'Device') => $product,
- main::key($num++,0,2,'type') => 'USB',
main::key($num++,1,2,'driver') => $row->[15],
},);
if ($extra > 0 && $row->[15] && !$bsd_type){
my $version = main::get_module_version($row->[15]);
$rows->[$j]{main::key($num++,0,3,'v')} = $version if $version;
}
+ $rows->[$j]{main::key($num++,1,2,'type')} = 'USB';
if ($extra > 0){
+ if ($extra > 1){
+ $row->[8] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'rev')} = $row->[8];
+ if ($row->[17]){
+ $rows->[$j]{main::key($num++,0,3,'speed')} = $row->[17];
+ }
+ if ($row->[24]){
+ $rows->[$j]{main::key($num++,0,3,'lanes')} = $row->[24];
+ }
+ if ($b_admin && $row->[22]){
+ $rows->[$j]{main::key($num++,0,3,'mode')} = $row->[22];
+ }
+ }
$rows->[$j]{main::key($num++,0,2,'bus-ID')} = "$path_id:$row->[1]";
- }
- if ($extra > 1){
- $row->[7] ||= 'N/A';
- $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
- }
- if ($extra > 2 && defined $row->[5] && $row->[5] ne ''){
- $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::filter($row->[16]);
+ if ($extra > 1){
+ $row->[7] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
+ }
+ if ($extra > 2){
+ if (defined $row->[5] && $row->[5] ne ''){
+ $rows->[$j]{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]";
+ }
+ if ($row->[16]){
+ $rows->[$j]{main::key($num++,0,2,'serial')} = main::filter($row->[16]);
+ }
+ }
}
advanced_output($rows,'usb',$path_id) if $path_id;
}
eval $end if $b_log;
}
+
sub advanced_output {
eval $start if $b_log;
my ($rows,$type,$bus_id) = @_;
my (@temp);
my ($j,$num,$k,$l,$m,$n,$address,$id,$note,$tool) = (0,1,2,3,4,5,'','','','');
- if (!$b_hci && $alerts{'hciconfig'}->{'action'} eq 'use'){
- hciconfig_data();
- $tool = 'hciconfig';
- }
- elsif (!$b_hci && $alerts{'bt-adapter'}->{'action'} eq 'use'){
- bt_tool_data();
- $tool = 'bt-adapter';
- }
- if (!$b_rfk && -e '/sys/class/bluetooth/'){
- rfkill_data();
- $tool = 'rfkill' if !$tool;
- }
+ set_bluetooth_data(\$tool);
# print "bid: $bus_id\n";
if ($type ne 'check'){
@temp = main::globber('/sys/class/bluetooth/*');
@@ -8471,10 +8677,9 @@ sub advanced_output {
$address = main::filter($hci{$item}->{'address'});
}
$rows->[$j]{main::key($num++,0,$l,'address')} = $address;
- # lmp/hci version only hciconfig sadly
- if (defined $hci{$item}->{'lmp-version'} &&
- (my $btv = bluetooth_version($hci{$item}->{'lmp-version'}))){
- $rows->[$j]{main::key($num++,0,$l,'bt-v')} = $btv;
+ # lmp/hci version only hciconfig
+ if ($hci{$item}->{'bt-version'}){
+ $rows->[$j]{main::key($num++,0,$l,'bt-v')} = $hci{$item}->{'bt-version'};
}
if ($extra > 0 && defined $hci{$item}->{'lmp-version'}){
$rows->[$j]{main::key($num++,0,$l,'lmp-v')} = $hci{$item}->{'lmp-version'};
@@ -8482,25 +8687,34 @@ sub advanced_output {
$rows->[$j]{main::key($num++,0,$m,'sub-v')} = $hci{$item}->{'lmp-subversion'};
}
}
- if ($extra > 0 && defined $hci{$item}->{'hci-version'} && ($extra > 2 || !$hci{$item}->{'lmp-version'} ||
- ($hci{$item}->{'lmp-version'} && $hci{$item}->{'lmp-version'} ne $hci{$item}->{'hci-version'}))){
+ if ($extra > 0 && defined $hci{$item}->{'hci-version'} &&
+ ($extra > 2 || !$hci{$item}->{'lmp-version'} ||
+ ($hci{$item}->{'lmp-version'} &&
+ $hci{$item}->{'lmp-version'} ne $hci{$item}->{'hci-version'}))){
$rows->[$j]{main::key($num++,0,$l,'hci-v')} = $hci{$item}->{'hci-version'};
if ($extra > 1 && $hci{$item}->{'hci-revision'}){
$rows->[$j]{main::key($num++,0,$m,'rev')} = $hci{$item}->{'hci-revision'};
}
}
- # if ($extra > 1 && $hci{$item}->{'discoverable'}){
- # $rows->[$j]{main::key($num++,1,$l,'discover')} = $hci{$item}->{'discoverable'};
- # if ($extra > 2 && $hci{$item}->{'discovering'}){
- # $rows->[$j]{main::key($num++,1,$m,'active')} = $hci{$item}->{'discovering'};
- # }
- # }
- # if ($extra > 1 && $hci{$item}->{'pairable'}){
- # $rows->[$j]{main::key($num++,0,$l,'pair')} = $hci{$item}->{'pairable'};
- # }
- # this data only from hciconfig
if ($b_admin &&
- ($hci{$item}->{'acl-mtu'} || $hci{$item}->{'sco-mtu'} || $hci{$item}->{'link-policy'})){
+ ($hci{$item}->{'discoverable'} || $hci{$item}->{'pairable'})){
+ $rows->[$j]{main::key($num++,1,$l,'status')} = '';
+ if ($hci{$item}->{'discoverable'}){
+ $rows->[$j]{main::key($num++,1,$m,'discoverable')} = $hci{$item}->{'discoverable'};
+ if ($hci{$item}->{'discovering'}){
+ $rows->[$j]{main::key($num++,1,$n,'active')} = $hci{$item}->{'discovering'};
+ }
+ }
+ if ($hci{$item}->{'pairable'}){
+ $rows->[$j]{main::key($num++,0,$m,'pairing')} = $hci{$item}->{'pairable'};
+ }
+ }
+ if ($extra > 2 && $hci{$item}->{'class'}){
+ $rows->[$j]{main::key($num++,0,$l,'class-ID')} = $hci{$item}->{'class'};
+ }
+ # this data only from hciconfig
+ if ($b_admin && ($hci{$item}->{'acl-mtu'} || $hci{$item}->{'sco-mtu'} ||
+ $hci{$item}->{'link-policy'})){
$j = scalar @$rows;
push(@$rows,{
main::key($num++,1,$l,'Info') => '',
@@ -8527,11 +8741,13 @@ sub advanced_output {
}
# since $rows is ref, we need to just check if no $j were set.
if (!$j && !$b_hci_error && ($alerts{'hciconfig'}->{'action'} ne 'use' &&
- $alerts{'bt-adapter'}->{'action'} ne 'use')){
+ $alerts{'bt-adapter'}->{'action'} ne 'use' &&
+ $alerts{'btmgmt'}->{'action'} ne 'use')){
my $key = 'Report';
my $value = '';
if ($alerts{'hciconfig'}->{'action'} eq 'platform' ||
- $alerts{'bt-adapter'}->{'action'} eq 'platform'){
+ $alerts{'bt-adapter'}->{'action'} eq 'platform' ||
+ $alerts{'btmgmt'}->{'action'} eq 'platform'){
$value = main::message('tool-missing-os','bluetooth');
}
else {
@@ -8545,7 +8761,34 @@ sub advanced_output {
eval $end if $b_log;
}
-sub bt_tool_data {
+# note: echo 'show' | bluetoothctl outputs everything but hciX ID, and is fast
+# args: 0: $tool, by ref
+sub set_bluetooth_data {
+ eval $start if $b_log;
+ if (!$b_hci && !$force{'bt-adapter'} && !$force{'btmgmt'} &&
+ !$force{'rfkill'} &&
+ ($fake{'bluetooth'} || $alerts{'hciconfig'}->{'action'} eq 'use')){
+ hciconfig_data();
+ ${$_[0]} = 'hciconfig';
+ }
+ elsif (!$b_hci && !$force{'rfkill'} && !$force{'bt-adapter'} &&
+ ($fake{'bluetooth'} || $alerts{'btmgmt'}->{'action'} eq 'use')){
+ btmgmt_data();
+ ${$_[0]} = 'btmgmt';
+ }
+ elsif (!$b_hci && !$force{'rfkill'} &&
+ ($fake{'bluetooth'} || $alerts{'bt-adapter'}->{'action'} eq 'use')){
+ bt_adapter_data();
+ ${$_[0]} = 'bt-adapter';
+ }
+ if (!$b_rfk && ($fake{'bluetooth'} || -e '/sys/class/bluetooth/')){
+ rfkill_data();
+ ${$_[0]} = 'rfkill' if !${$_[0]};
+ }
+ eval $end if $b_log;
+}
+
+sub bt_adapter_data {
eval $start if $b_log;
$b_hci = 1;
my (@data,$id);
@@ -8557,7 +8800,7 @@ sub bt_tool_data {
else {
if ($b_bluetooth){
my $cmd = "$alerts{'bt-adapter'}->{'path'} --info 2>/dev/null";
- @data = main::grabber($cmd,'', 'strip');
+ @data = main::grabber($cmd,'','strip');
}
}
# print Data::Dumper::Dumper \@data;
@@ -8572,6 +8815,9 @@ sub bt_tool_data {
elsif ($working[0] eq 'Address'){
$hci{$id}->{'address'} = join(':',@working[1 .. $#working]);
}
+ elsif ($working[0] eq 'Class' && $working[1] =~ /^0x0*(\S+)/){
+ $hci{$id}->{'class'} = $1;
+ }
elsif ($working[0] eq 'Powered'){
$hci{$id}->{'state'} = ($working[1] =~ /^(1|yes)\b/) ? 'up': 'down';
}
@@ -8588,17 +8834,61 @@ sub bt_tool_data {
if (!@data && !$b_bluetooth){
$hci{'alert'} = main::message('bluetooth-down');
}
- print Data::Dumper::Dumper \%hci if $dbg[27];
+ print 'bt-adapter: ', Data::Dumper::Dumper \%hci if $dbg[27];
+ main::log_data('dump','%hci', \%hci) if $b_log;
+ eval $end if $b_log;
+}
+
+sub btmgmt_data {
+ eval $start if $b_log;
+ $b_hci = 1;
+ my (@data,$id);
+ if ($fake{'bluetooth'}){
+ my $file;
+ $file = "$fake_data_dir/bluetooth/btmgmt-2.txt";
+ @data = main::reader($file,'strip');
+ }
+ else {
+ if ($b_bluetooth){
+ my $cmd = "$alerts{'btmgmt'}->{'path'} info 2>/dev/null";
+ @data = main::grabber($cmd,'', 'strip');
+ }
+ }
+ # print Data::Dumper::Dumper \@data;
+ main::log_data('dump','@data', \@data) if $b_log;
+ foreach (@data){
+ next if /^Index list/;
+ if (/^(hci[0-9]+):\s+/){
+ $id = $1;
+ }
+ # addr 4C:F3:72:9C:B4:D3 version 6 manufacturer 15 class 0x000104
+ elsif (/^addr\s+([0-9A-F:]+)\s+version\s+([0-9]+)\s/){
+ $hci{$id}->{'address'} = $1;
+ $hci{$id}->{'lmp-version'} = $2; # assume non hex integer
+ $hci{$id}->{'bt-version'} = bluetooth_version($2);
+ if (/ class\s+0x0*(\S+)\b/){
+ $hci{$id}->{'class'} = $1;
+ }
+ }
+ elsif (/^current settings:\s+(.*)/){
+ my $settings = $1;
+ $hci{$id}->{'state'} = ($settings =~ /\bpowered\b/) ? 'up' : 'down';
+ $hci{$id}->{'discoverable'} = ($settings =~ /\bdiscoverable\b/) ? 'yes' : 'no';
+ $hci{$id}->{'pairable'} = ($settings =~ /\bconnectable\b/) ? 'yes' : 'no';
+ }
+ }
+ print 'btmgmt: ', Data::Dumper::Dumper \%hci if $dbg[27];
main::log_data('dump','%hci', \%hci) if $b_log;
eval $end if $b_log;
}
+
sub hciconfig_data {
eval $start if $b_log;
$b_hci = 1;
my (@data,$id);
if ($fake{'bluetooth'}){
my $file;
- $file = "";
+ $file = "$fake_data_dir/bluetooth/hciconfig-a-2.txt";
@data = main::reader($file,'strip');
}
else {
@@ -8623,13 +8913,28 @@ sub hciconfig_data {
elsif (/^(UP|DOWN).*/){
$hci{$id}->{'state'} = lc($1);
}
- elsif (/^HCI Version:\s+([0-9\.]+)\s+.*Revision:\s+0x([0-9a-f]+)/){
- $hci{$id}->{'hci-version'} = $1;
- $hci{$id}->{'hci-revision'} = $2;
- }
- elsif (/^LMP Version:\s+([0-9\.]+)\s+.*Subversion:\s+0x([0-9a-f]+)/){
- $hci{$id}->{'lmp-version'} = $1;
- $hci{$id}->{'lmp-subversion'} = $2;
+ elsif (/^Class:\s+0x0*(\S+)/){
+ $hci{$id}->{'class'} = $1;
+ }
+ # HCI Version: 4.0 (0x6) Revision: 0x1000
+ # HCI Version: 6.6 Revision: 0x1000 [don't know if this exists]
+ # HCI Version: (0x7) Revision: 0x3101
+ elsif (/^HCI Version:\s+(([0-9\.]+)\s+)?\(0x([0-9a-f]+)\)\s+Revision:\s+0x([0-9a-f]+)/i){
+ $hci{$id}->{'hci-revision'} = $4;
+ if (defined $3){
+ $hci{$id}->{'bt-version'} = bluetooth_version(hex($3));
+ $hci{$id}->{'hci-version'} = hex($3);
+ $hci{$id}->{'hci-version-hex'} = $3;
+ }
+ }
+ # LMP Version: 4.0 (0x6) Subversion: 0x220e
+ # LMP Version: 6.6 Revision: 0x1000 [don't know if this exists]
+ # LMP Version: (0x7) Subversion: 0x1
+ elsif (/^LMP Version:\s+(([0-9\.]+)\s+)?\(0x([0-9a-f]+)\)\s+Subversion:\s+0x([0-9a-f]+)/i){
+ $hci{$id}->{'lmp-subversion'} = $4;
+ $hci{$id}->{'bt-version'} = bluetooth_version(hex($3));
+ $hci{$id}->{'lmp-version'} = hex($3);
+ $hci{$id}->{'lmp-version-hex'} = $3;
}
elsif (/^Link policy:\s+(.*)/){
$hci{$id}->{'link-policy'} = lc($1);
@@ -8641,10 +8946,11 @@ sub hciconfig_data {
$hci{$id}->{'service-classes'} = main::clean_unset(lc($1));
}
}
- print Data::Dumper::Dumper \%hci if $dbg[27];
+ print 'hciconfig: ', Data::Dumper::Dumper \%hci if $dbg[27];
main::log_data('dump','%hci', \%hci) if $b_log;
eval $end if $b_log;
}
+
sub rfkill_data {
eval $start if $b_log;
$b_rfk = 1;
@@ -8677,10 +8983,11 @@ sub rfkill_data {
$hci{$id}->{'rf-index'} = $value;
}
}
- print Data::Dumper::Dumper \%hci if $dbg[27];
+ print 'rfkill: ', Data::Dumper::Dumper \%hci if $dbg[27];
main::log_data('dump','%hci', \%hci) if $b_log;
eval $end if $b_log;
}
+
sub check_service {
eval $start if $b_log;
if (!$b_service){
@@ -8690,13 +8997,17 @@ sub check_service {
}
eval $end if $b_log;
}
+
+# args: 0: lmp versoin - could be hex, but probably decimal, like 6.6
sub bluetooth_version {
eval $start if $b_log;
my ($lmp) = @_;
- return if !defined $lmp || !main::is_numeric($lmp);
+ return if !defined $lmp;
+ return if !main::is_numeric($lmp);
$lmp = int($lmp);
- # conveniently, LMP starts with 0, so perfect for array indexes
- my @bt = qw(1.0b 1.1 1.2 2.0 2.1 3.0 4.0 4.1 4.2 5.0 5.1 5.2);
+ # Conveniently, LMP starts with 0, so perfect for array indexes.
+ # 6.0 is coming, but might be 5.5 first, nobody knows.
+ my @bt = qw(1.0b 1.1 1.2 2.0 2.1 3.0 4.0 4.1 4.2 5.0 5.1 5.2 5.3 5.4);
return $bt[$lmp];
eval $end if $b_log;
}
@@ -8705,7 +9016,8 @@ sub bluetooth_version {
## CpuItem
{
package CpuItem;
-my ($type);
+my (%fake_data,$type);
+
sub get {
eval $start if $b_log;
($type) = @_;
@@ -9018,6 +9330,7 @@ sub full_output {
}
eval $end if $b_log;
}
+
# $num, $rows passed by reference
sub full_output_caches {
eval $start if $b_log;
@@ -9061,6 +9374,7 @@ sub full_output_caches {
}
eval $end if $b_log;
}
+
sub short_output {
eval $start if $b_log;
my ($rows,$cpu) = @_;
@@ -9120,6 +9434,7 @@ sub short_data {
eval $end if $b_log;
return $data;
}
+
sub prep_short_data {
eval $start if $b_log;
my ($cpu_data) = @_;
@@ -9155,6 +9470,7 @@ sub cpuinfo_data {
my ($cpu,$arch,$note,$temp);
# has to be set above fake cpu section
set_cpu_data(\$cpu);
+ set_fake_data() if $fake{'cpu'} && !$loaded{'cpu-fake-data'};
# sleep is also set in front of sysctl_data for BSDs, same idea
my $sleep = $cpu_sleep * 1000000;
if ($b_hires){
@@ -9163,48 +9479,8 @@ sub cpuinfo_data {
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;
- }
- }
+ # Run first to get raw as possible speeds
+ cpuinfo_speed_sys(\$cpu) if $fake{'cpu'} || -e '/sys/devices/system/cpu/';
cpuinfo_data_grabber($file,\$cpu->{'type'}) if !$loaded{'cpuinfo'};
$cpu->{'type'} = cpu_vendor($cpu_arch) if $cpu_arch eq 'elbrus'; # already set to lower
my ($core_count,$proc_count,$speed) = (0,0,0);
@@ -9217,6 +9493,7 @@ sub cpuinfo_data {
next if !$block;
if ($b_block_1){
$b_block_1 = 0;
+ # this may also kick in for centaur/via types, but no data available, guess
if (!$cpu->{'type'} && $block->{'vendor_id'}){
$cpu->{'type'} = cpu_vendor($block->{'vendor_id'});
}
@@ -9394,64 +9671,97 @@ sub cpuinfo_data {
}
}
main::log_data('dump','%$cpu',$cpu) if $b_log;
- print Data::Dumper::Dumper $cpu if $dbg[8];
+ print 'cpuinfo: ', Data::Dumper::Dumper $cpu if $dbg[8];
eval $end if $b_log;
return $cpu;
}
+
+# args: 0: $cpu ref;
+sub cpuinfo_speed_sys {
+ eval $start if $b_log;
+ my @data;
+ my $val_id = 0;
+ # 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 ($fake{'cpu'}){
+ if ($fake_data{'sys'} && (my @fake = main::reader($fake_data{'sys'},'strip'))){
+ my $pattern = '/sys/devices/system/cpu/cpufreq/policy\d+/(affected_cpus|';
+ # reading cpuinfo WAY faster than scaling, but root only
+ if (grep {m%/sys/devices/system/cpu/cpufreq/policy0/cpuinfo_cur_freq%} @fake){
+ $pattern .= 'cpuinfo_cur_freq)';
+ }
+ else {
+ $pattern .= 'scaling_cur_freq)';
+ }
+ @data = grep {m%^$pattern%} @fake;
+ # print Data::Dumper::Dumper \@fake,"\n";
+ }
+ $val_id = 1;
+ }
+ else {
+ 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}';
+ }
+ @data = main::globber($glob);
+ }
+ my ($error,$file,$key,%working,%freq,@value);
+ foreach (@data){
+ next if !$fake{'cpu'} && ! -r $_;
+ undef $error;
+ # print "loop: $_\n";
+ my $fh;
+ # $fh always non null, even on error
+ if (!$fake{'cpu'}){
+ open($fh, '<', $_) or $error = $!;
+ }
+ if (!$error){
+ if (m%/sys/devices/system/cpu/(cpufreq/)?(cpu|policy)(\d+)/(cpufreq/)?(affected_cpus|(cpuinfo|scaling)_cur_freq)%){
+ $key = $3;
+ $file = $5;
+ if (!$fake{'cpu'}){
+ chomp(@value = <$fh>);
+ close $fh;
+ }
+ else {
+ @value = split(/::/,$_,2);
+ }
+ if ($file eq 'affected_cpus'){
+ # chomp seems to turn undefined into '', not sure why. Behavior varies
+ # so check for both cases.
+ if (defined $value[$val_id] && $value[$val_id] ne ''){
+ $working{$key}->[0] = $value[$val_id];
+ }
+ }
+ else {
+ $working{$key}->[1] = clean_speed($value[$val_id],'khz');
+ }
+ }
+ }
+ }
+ if (%working){
+ foreach (keys %working){
+ $freq{sprintf("%04d",$_)} = $working{$_}->[1] if defined $working{$_}->[0];
+ }
+ ${$_[0]}->{'sys-freq'} = \%freq if %freq;
+ # print 'result: ', Data::Dumper::Dumper $_[0];
+ }
+ eval $end if $b_log;
+}
+
sub cpuinfo_data_grabber {
eval $start if $b_log;
my ($file,$cpu_type) = @_; # type by ref
$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 = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-cpuinfo.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-cpuinfo-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-cpuinfo-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~cpuinfo.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~cpuinfo-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~cpuinfo-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-cpuinfo-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-cpuinfo.txt";
- ## ARM/MIPS
- # $file = "$fake_data_dir/cpu/arm/arm-4-core-pinebook-1.txt";
- # $file = "$fake_data_dir/cpu/arm/armv6-single-core-1.txt";
- # $file = "$fake_data_dir/cpu/arm/armv7-dual-core-1.txt";
- # $file = "$fake_data_dir/cpu/arm/armv7-new-format-model-name-single-core.txt";
- # $file = "$fake_data_dir/cpu/arm/arm-2-die-96-core-rk01.txt";
- # $file = "$fake_data_dir/cpu/arm/arm-shevaplug-1.2ghz.txt";
- # $file = "$fake_data_dir/cpu/mips/mips-mainusg-cpuinfo.txt";
- # $file = "$fake_data_dir/cpu/ppc/ppc-debian-ppc64-cpuinfo.txt";
- ## x86
- # $file = "$fake_data_dir/cpu/amd/16-core-32-mt-ryzen.txt";
- # $file = "$fake_data_dir/cpu/amd/2-16-core-epyc-abucodonosor.txt";
- # $file = "$fake_data_dir/cpu/amd/2-core-probook-antix.txt";
- # $file = "$fake_data_dir/cpu/amd/4-core-jean-antix.txt";
- # $file = "$fake_data_dir/cpu/amd/4-core-althlon-mjro.txt";
- # $file = "$fake_data_dir/cpu/amd/4-core-apu-vc-box.txt";
- # $file = "$fake_data_dir/cpu/amd/4-core-a10-5800k-1.txt";
- # $file = "$fake_data_dir/cpu/intel/1-core-486-fourtysixandtwo.txt";
- # $file = "$fake_data_dir/cpu/intel/2-core-ht-atom-bruh.txt";
- # $file = "$fake_data_dir/cpu/intel/core-2-i3.txt";
- # $file = "$fake_data_dir/cpu/intel/8-core-i7-damentz64.txt";
- # $file = "$fake_data_dir/cpu/intel/2-10-core-xeon-ht.txt";
- # $file = "$fake_data_dir/cpu/intel/4-core-xeon-fake-dual-die-zyanya.txt";
- # $file = "$fake_data_dir/cpu/intel/2-core-i5-fake-dual-die-hek.txt";
- # $file = "$fake_data_dir/cpu/intel/2-1-core-xeon-vm-vs2017.txt";
- # $file = "$fake_data_dir/cpu/intel/4-1-core-xeon-vps-frodo1.txt";
- # $file = "$fake_data_dir/cpu/intel/4-6-core-xeon-no-mt-lathander.txt";
- ## Elbrus
- # $cpu_type = 'elbrus'; # uncomment to test elbrus
- # $file = "$fake_data_dir/cpu/elbrus/elbrus-2c3/cpuinfo.txt";
- # $file = "$fake_data_dir/cpu/elbrus/1xE1C-8.txt";
- # $file = "$fake_data_dir/cpu/elbrus/1xE2CDSP-4.txt";
- # $file = "$fake_data_dir/cpu/elbrus/1xE2S4-3-monocub.txt";
- # $file = "$fake_data_dir/cpu/elbrus/1xMBE8C-7.txt";
- # $file = "$fake_data_dir/cpu/elbrus/4xEL2S4-3.txt";
- # $file = "$fake_data_dir/cpu/elbrus/4xE8C-7.txt";
- # $file = "$fake_data_dir/cpu/elbrus/4xE2CDSP-4.txt";
- # $file = "$fake_data_dir/cpu/elbrus/cpuinfo.e8c2.txt";
- }
+ $file = $fake_data{'cpuinfo'} if $fake{'cpu'};
my $raw = main::reader($file,'','ref');
@$raw = map {$_ =~ s/^\s*$/~~~/;$_;} @$raw;
push(@$raw,'~~~') if @$raw;
@@ -9498,6 +9808,7 @@ sub cpuinfo_data_grabber {
}
eval $end if $b_log;
}
+
sub cpu_sys_data {
eval $start if $b_log;
my $sys_freq = $_[0];
@@ -9520,8 +9831,10 @@ sub cpu_sys_data {
$core_id = sprintf("%08d",$cpu->{'topology'}{'core_id'});
if ($fake{'cpu'}){
if (defined $cpu->{'cpufreq'}{'scaling_cur_freq'} &&
- $cpu->{'cpufreq'}{'affected_cpus'} &&
- $cpu->{'cpufreq'}{'affected_cpus'} ne 'UNDEFINED'){
+ $cpu->{'cpufreq'}{'affected_cpus'} &&
+ $cpu->{'cpufreq'}{'affected_cpus'} ne 'UNDEFINED' &&
+ # manually generated cpu debuggers will show '', not UNDEFINED
+ $cpu->{'cpufreq'}{'affected_cpus'} ne ''){
$speed = clean_speed($cpu->{'cpufreq'}{'scaling_cur_freq'},'khz');
}
}
@@ -9617,7 +9930,7 @@ sub cpu_sys_data {
}
# die_id is relatively new, core_siblings_list has been around longer
if (defined $cpu->{'topology'}{'die_id'} ||
- defined $cpu->{'topology'}{'core_siblings_list'}){
+ defined $cpu->{'topology'}{'core_siblings_list'}){
my $die = $cpu->{'topology'}{'die_id'};
$die = $cpu->{'topology'}{'core_siblings_list'} if !defined $die;
if (!grep {$_ eq $die} @{$cpu_sys->{'cpus'}{$phys_id}{'dies'}}){
@@ -9626,7 +9939,7 @@ sub cpu_sys_data {
}
}
if (defined $cpu_sys->{'data'}{'cpufreq-boost'} &&
- $cpu_sys->{'data'}{'cpufreq-boost'} =~ /^[01]$/){
+ $cpu_sys->{'data'}{'cpufreq-boost'} =~ /^[01]$/){
if ($cpu_sys->{'data'}{'cpufreq-boost'}){
$cpu_sys->{'data'}{'cpufreq-boost'} = 'enabled';
}
@@ -9657,34 +9970,28 @@ sub cpu_sys_data {
}
# this corrects a bug we see sometimes in min/max frequencies
if ((scalar @ci_freq_max < 2 && scalar @ci_freq_min < 2) &&
- (defined $cpu_sys->{'data'}{'speeds'}{'min-freq'} &&
- defined $cpu_sys->{'data'}{'speeds'}{'max-freq'}) &&
- ($cpu_sys->{'data'}{'speeds'}{'min-freq'} > $cpu_sys->{'data'}{'speeds'}{'max-freq'} ||
- $cpu_sys->{'data'}{'speeds'}{'min-freq'} == $cpu_sys->{'data'}{'speeds'}{'max-freq'})){
+ (defined $cpu_sys->{'data'}{'speeds'}{'min-freq'} &&
+ defined $cpu_sys->{'data'}{'speeds'}{'max-freq'}) &&
+ ($cpu_sys->{'data'}{'speeds'}{'min-freq'} > $cpu_sys->{'data'}{'speeds'}{'max-freq'} ||
+ $cpu_sys->{'data'}{'speeds'}{'min-freq'} == $cpu_sys->{'data'}{'speeds'}{'max-freq'})){
$cpu_sys->{'data'}{'speeds'}{'min-freq'} = 0;
}
main::log_data('dump','%$cpu_sys',$cpu_sys) if $b_log;
- print Data::Dumper::Dumper $cpu_sys if $dbg[8];
+ print 'cpu-sys: ', Data::Dumper::Dumper $cpu_sys if $dbg[8];
eval $end if $b_log;
return $cpu_sys;
}
+
sub sys_data_grabber {
eval $start if $b_log;
my (@files);
+ set_fake_data() if $fake{'cpu'} && !$loaded{'cpu-fake-data'};
# 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 = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-sys.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-sys-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-sys-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~sys.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~sys-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~sys-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-sys-1.txt";
- # $file = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-sys.txt";
- # @files = main::reader($file);
+ # print "$fake_data{'sys'}\n";
+ @files = main::reader($fake_data{'sys'}) if $fake_data{'sys'};
+ # print Data::Dumper::Dumper \@files;
}
# There's a massive time hit reading full globbed set of files, so grab and
# read only what we need.
@@ -9708,6 +10015,7 @@ sub sys_data_grabber {
$glob .= ',vulnerabilities/*' if $b_admin;
$glob .= '}';
}
+ # print "sys glob: $glob\n";
@files = main::globber($glob);
}
main::log_data('dump','@files',\@files) if $b_log;
@@ -9815,6 +10123,80 @@ sub sys_data_grabber {
eval $end if $b_log;
return $working;
}
+
+# Set in one place to make sure we get them all consistent
+sub set_fake_data {
+ $loaded{'cpu-fake-data'} = 1;
+ my ($ci,$sys);
+ ## CPUINFO DATA FILES ##
+ ## ARM/MIPS
+ # $ci = "$fake_data_dir/cpu/arm/arm-4-core-pinebook-1.txt";
+ # $ci = "$fake_data_dir/cpu/arm/armv6-single-core-1.txt";
+ # $ci = "$fake_data_dir/cpu/arm/armv7-dual-core-1.txt";
+ # $ci = "$fake_data_dir/cpu/arm/armv7-new-format-model-name-single-core.txt";
+ # $ci = "$fake_data_dir/cpu/arm/arm-2-die-96-core-rk01.txt";
+ # $ci = "$fake_data_dir/cpu/arm/arm-shevaplug-1.2ghz.txt";
+ # $ci = "$fake_data_dir/cpu/mips/mips-mainusg-cpuinfo.txt";
+ # $ci = "$fake_data_dir/cpu/ppc/ppc-debian-ppc64-cpuinfo.txt";
+ ## x86
+ # $ci = "$fake_data_dir/cpu/amd/16-core-32-mt-ryzen.txt";
+ # $ci = "$fake_data_dir/cpu/amd/2-16-core-epyc-abucodonosor.txt";
+ # $ci = "$fake_data_dir/cpu/amd/2-core-probook-antix.txt";
+ # $ci = "$fake_data_dir/cpu/amd/4-core-jean-antix.txt";
+ # $ci = "$fake_data_dir/cpu/amd/4-core-althlon-mjro.txt";
+ # $ci = "$fake_data_dir/cpu/amd/4-core-apu-vc-box.txt";
+ # $ci = "$fake_data_dir/cpu/amd/4-core-a10-5800k-1.txt";
+ # $ci = "$fake_data_dir/cpu/intel/1-core-486-fourtysixandtwo.txt";
+ # $ci = "$fake_data_dir/cpu/intel/2-core-ht-atom-bruh.txt";
+ # $ci = "$fake_data_dir/cpu/intel/core-2-i3.txt";
+ # $ci = "$fake_data_dir/cpu/intel/8-core-i7-damentz64.txt";
+ # $ci = "$fake_data_dir/cpu/intel/2-10-core-xeon-ht.txt";
+ # $ci = "$fake_data_dir/cpu/intel/4-core-xeon-fake-dual-die-zyanya.txt";
+ # $ci = "$fake_data_dir/cpu/intel/2-core-i5-fake-dual-die-hek.txt";
+ # $ci = "$fake_data_dir/cpu/intel/2-1-core-xeon-vm-vs2017.txt";
+ # $ci = "$fake_data_dir/cpu/intel/4-1-core-xeon-vps-frodo1.txt";
+ # $ci = "$fake_data_dir/cpu/intel/4-6-core-xeon-no-mt-lathander.txt";
+ ## Elbrus
+ # $cpu_type = 'elbrus'; # uncomment to test elbrus
+ # $ci = "$fake_data_dir/cpu/elbrus/elbrus-2c3/cpuinfo.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/1xE1C-8.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/1xE2CDSP-4.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/1xE2S4-3-monocub.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/1xMBE8C-7.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/4xEL2S4-3.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/4xE8C-7.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/4xE2CDSP-4.txt";
+ # $ci = "$fake_data_dir/cpu/elbrus/cpuinfo.e8c2.txt";
+
+ ## CPU CPUINFO/SYS PAIRS DATA FILES ##
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-cpuinfo.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/android-pocom3-fake-sys.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-cpuinfo-1.txt";v
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/arm-pine64-sys-1.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-cpuinfo-1.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/arm-riscyslack2-sys-1.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~cpuinfo.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/ppc-stuntkidz~sys.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~cpuinfo-1.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/riscv-unmatched-2021~sys-1.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~cpuinfo-1.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-brickwizard-atom-n270~sys-1.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-cpuinfo-1.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-amd-phenom-chrisretusn-sys-1.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-cpuinfo.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/x86-drgibbon-intel-i7-sys.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/ryzen-threadripper-1x64-3950x-cpuinfo.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/ryzen-threadripper-1x64-3950x-sys.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/amd-threadripper-1x12-5945wx-cpuinfo-1.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/amd-threadripper-1x12-5945wx-sys-1.txt";
+ # $ci = "$fake_data_dir/cpu/sys-ci-pairs/intel-i7-1165G7-4-core-no-smt-cpuinfo.txt";
+ # $sys = "$fake_data_dir/cpu/sys-ci-pairs/intel-i7-1165G7-4-core-no-smt-sys.txt";
+ $ci = "$fake_data_dir/cpu/sys-ci-pairs/elbrus-e16c-1-cpuinfo.txt";
+ $sys = "$fake_data_dir/cpu/sys-ci-pairs/elbrus-e16c-1-sys.txt";
+ $fake_data{'cpuinfo'} = $ci;
+ $fake_data{'sys'} = $sys;
+}
+
sub sysctl_data {
eval $start if $b_log;
my ($cpu,@line,%speeds,@working);
@@ -10108,6 +10490,7 @@ sub dboot_data {
eval $end if $b_log;
return $values;
}
+
sub dmidecode_data {
eval $start if $b_log;
my $dmi_data = {'L1' => 0, 'L2' => 0,'L3' => 0, 'phys-cnt' => 0,
@@ -10448,6 +10831,7 @@ sub cp_data_dmi {
$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) = @_;
@@ -10612,6 +10996,7 @@ sub cp_data_fallback {
}
eval $end if $b_log;
}
+
# all values passed by reference so no need for returns
sub cp_data_sys {
eval $start if $b_log;
@@ -10721,6 +11106,7 @@ sub cp_data_sys {
# 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) = @_;
@@ -10751,7 +11137,8 @@ sub cp_cache_desc {
undef $cache_desc;
return $desc;
}
-# $caches passed by reference
+
+# args: 0: $caches passed by reference
sub cp_cache_processor {
my ($cache,$count) = @_;
my $output;
@@ -10765,6 +11152,7 @@ sub cp_cache_processor {
# print "$cache :: $count :: $output\n";
return $output;
}
+
sub cp_caches_fallback {
eval $start if $b_log;
my ($counts,$cpu,$caches,$cache_check) = @_;
@@ -10839,8 +11227,10 @@ sub cp_cpu_arch {
$model = '' if !defined $model; # model can be 0
my ($arch,$gen,$note,$process,$year);
my $check = main::message('note-check');
- # See: docs/inxi-resources.txt
+ # See: docs/inxi-cpu.txt
# print "type:$type fam:$family model:$model step:$stepping\n";
+ # Note: AMD family is not Ext fam . fam but rather Ext-fam + fam.
+ # But model is Ext model . model...
if ($type eq 'amd'){
if ($family eq '3'){
$arch = 'Am386';
@@ -10944,7 +11334,7 @@ sub cp_cpu_arch {
$year = '2004-2008';}
}
# K9 was planned but skipped
- elsif ($family eq '10'){
+ elsif ($family eq '10'){ # 1F
## verified
if ($model =~ /^(2)$/){
$arch = 'K10'; # 2:2:budapest;2:1,3:barcelona
@@ -10963,7 +11353,7 @@ sub cp_cpu_arch {
}
# very loose, all stepping 1: covers athlon x2, sempron, turion x2
# years unclear, could be 2005 start, or 2008
- elsif ($family eq '11'){
+ elsif ($family eq '11'){ # 2F
if ($model =~ /^(3)$/){
$arch = 'K11 Turion X2'; # mix of K8/K10
$note = $check;
@@ -10971,7 +11361,7 @@ sub cp_cpu_arch {
$year = ''; }
}
# might also need cache handling like 14/16
- elsif ($family eq '12'){
+ elsif ($family eq '12'){ # 3F
if ($model =~ /^(1)$/){
$arch = 'K12 Fusion'; # K10 based apu, llano
$process = 'GF 32nm';
@@ -10982,7 +11372,7 @@ sub cp_cpu_arch {
$year = '2011';} # check years
}
# SOC, apu
- elsif ($family eq '14'){
+ elsif ($family eq '14'){ # 5F
if ($model =~ /^(1|2)$/){
$arch = 'Bobcat';
$process = 'GF 40nm';
@@ -10992,7 +11382,7 @@ sub cp_cpu_arch {
$process = 'GF 40nm';
$year = '2011-13';}
}
- elsif ($family eq '15'){
+ elsif ($family eq '15'){ # 6F
# note: only model 1 confirmd
if ($model =~ /^(0|1|3|4|5|6|7|8|9|A|B|C|D|E|F)$/){
$arch = 'Bulldozer';
@@ -11019,7 +11409,7 @@ sub cp_cpu_arch {
$year = '2011-12';}
}
# SOC, apu
- elsif ($family eq '16'){
+ elsif ($family eq '16'){ # 7F
if ($model =~ /^(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)$/){
$arch = 'Jaguar';
$process = 'GF 28nm';
@@ -11033,7 +11423,7 @@ sub cp_cpu_arch {
$process = 'GF 28nm';
$year = '2013-14';}
}
- elsif ($family eq '17'){
+ elsif ($family eq '17'){ # 8F
# can't find stepping/model for no ht 2x2 core/die models, only first ones
if ($model =~ /^(1|11|20)$/){
$arch = 'Zen';
@@ -11055,7 +11445,7 @@ sub cp_cpu_arch {
$process = 'GF 12nm';
$year = '2018-21';}
# used this but it didn't age well: ^(2[0123456789ABCDEF]|
- elsif ($model =~ /^(31|47|60|68|71|90|98|A.)$/){
+ elsif ($model =~ /^(3.|4.|5.|6.|7.|8.|9.|A.)$/){
$arch = 'Zen 2';
$gen = '3';
$process = 'TSMC n7 (7nm)'; # some consumer maybe GF 14nm
@@ -11067,22 +11457,30 @@ sub cp_cpu_arch {
$year = '';}
}
# Joint venture between AMD and Chinese companies. Type amd? or hygon?
- elsif ($family eq '18'){
+ elsif ($family eq '18'){ # 9F
# model 0, zen 1
$arch = 'Zen (Hygon Dhyana)';
$gen = '1';
$process = 'GF 14nm';
$year = '';}
- elsif ($family eq '19'){
- # ext model 6,7, but no base models yet
+ elsif ($family eq '19'){ # AF
+ # zen 4 raphael, phoenix 1 use n5 I believe
+ # Epyc Bergamo zen4c 4nm, only few full model IDs, update when appear
+ # zen4c is for cloud hyperscale
+ if ($model =~ /^(78)$/){
+ $arch = 'Zen 4c';
+ $gen = '5';
+ $process = 'TSMC n4 (4nm)';
+ $year = '2023+';}
+ # ext model 6,7, base models trickling in
# 10 engineering sample
- if ($model =~ /^(1.|6.|7.|A.)$/){
+ elsif ($model =~ /^(1.|6.|7.|A.)$/){
$arch = 'Zen 4';
$gen = '5';
$process = 'TSMC n5 (5nm)';
- $year = '2022';}
- # double check 40, 44
- elsif ($model =~ /^(4.)$/){
+ $year = '2022+';}
+ # double check 40, 44; 21 confirmed
+ elsif ($model =~ /^(21|4.)$/){
$arch = 'Zen 3+';
$gen = '4';
$process = 'TSMC n6 (7nm)';
@@ -11098,9 +11496,29 @@ sub cp_cpu_arch {
$note = $check;
$process = 'TSMC n5 (5nm)';
$year = '2021-22';}
- # Zen 5: TSMC n3
}
+ # Zen 5: TSMC n3/n4, epyc turin / granite ridge? / turin dense zen 5c 3nm
+ elsif ($family eq '20'){ # BF
+ if ($model =~ /^(0)$/){
+ $arch = 'Zen 5';
+ $gen = '5';
+ $process = 'TSMC n3 (3nm)'; # turin could be 4nm, need more data
+ $year = '2023+';}
+ elsif ($model =~ /^(20|40)$/){
+ $arch = 'Zen 5';
+ $gen = '5';
+ $process = 'TSMC n3 (3nm)'; # desktop, granite ridge, confirm 2024
+ $year = '2024+';}
+ else {
+ $arch = 'Zen 5';
+ $note = $check;
+ $process = 'TSMC n3/n4 (3,4nm)';
+ $year = '2024+';}
+ }
+ # Roadmap: check to verify, AMD is usually closer to target than Intel
+ # Epyc 4 genoa: zen 4, nm, 2022+ (dec 2022), cxl-1.1,pcie-5, ddr-5
}
+ # we have no advanced data for ARM cpus, this is an area that could be improved?
elsif ($type eq 'arm'){
if ($family ne ''){
$arch="ARMv$family";}
@@ -11128,26 +11546,44 @@ sub cp_cpu_arch {
}
elsif ($family eq '6'){
if ($model =~ /^(6)$/){
- $arch = 'WinChip-based';
+ $arch = 'Via Cyrix III (WinChip 5)';
$process = '150nm'; # guess
$year = '';}
elsif ($model =~ /^(7|8)$/){
- $arch = 'C3';
+ $arch = 'Via C3';
$process = '150nm';
$year = '';}
elsif ($model =~ /^(9)$/){
- $arch = 'C3-2';
+ $arch = 'Via C3-2';
$process = '130nm';
$year = '';}
elsif ($model =~ /^(A|D)$/){
- $arch = 'C7';
+ $arch = 'Via C7';
$process = '90nm';
$year = '';}
elsif ($model =~ /^(F)$/){
- $arch = 'Isaiah';
+ if ($stepping <= 1){
+ $arch = 'Via CN Nano (Isaah)';}
+ elsif ($stepping <= 2){
+ $arch = 'Via Nano (Isaah)';}
+ elsif ($stepping <= 10){
+ $arch = 'Via Nano (Isaah)';}
+ elsif ($stepping <= 12){
+ $arch = 'Via Isaah';}
+ elsif ($stepping <= 13){
+ $arch = 'Via Eden';}
+ elsif ($stepping <= 14){
+ $arch = 'Zhaoxin ZX';}
$process = '90nm'; # guess
$year = '';}
}
+ elsif ($family eq '7'){
+ if ($model =~ /^(1.|3.)$/){
+ $arch = 'Zhaoxin ZX';
+ $process = '90nm'; # guess
+ $year = '';
+ }
+ }
}
# note, to test uncoment $cpu{'type'} = Elbrus in proc/cpuinfo logic
# ExpLicit Basic Resources Utilization Scheduling
@@ -11513,18 +11949,14 @@ sub cp_cpu_arch {
$process = 'Intel 14nm';
$year = '~2018-20';}
}
- elsif ($model =~ /^(8F)$/){
+ elsif ($model =~ /^(8F|95)$/){
$arch = 'Sapphire Rapids';
$process = 'Intel 7 (10nm ESF)';
- $year = '2021+';} # server
- elsif ($model =~ /^(97|9A|BE)$/){
+ $year = '2023+';} # server
+ elsif ($model =~ /^(97|9A|9C|BE)$/){
$arch = 'Alder Lake'; # socket LG 1700
$process = 'Intel 7 (10nm ESF)';
$year = '2021+';}
- elsif ($model =~ /^(9A|9C)$/){
- $arch = 'Tremont Jasper Lake';
- $process = 'Intel 10nm';
- $year = '2021+';} # ?
elsif ($model =~ /^(9E)$/){
if ($stepping == 9){
$arch = 'Kaby Lake';
@@ -11566,13 +11998,38 @@ sub cp_cpu_arch {
elsif ($model =~ /^(B7|BA|BF)$/){
$arch = 'Raptor Lake'; # 13 gen, socket LG 1700,1800
$process = 'Intel 7 (10nm)';
- $year = '2022+';}
+ $year = '2022+';}
+ elsif ($model =~ /^(BC|BD)$/){
+ $arch = 'Lunar Lake'; # 15 gn
+ $process = 'Intel 18a (1.8nm)';
+ $year = '2024+';} # seen APU IDs, so out there
+ # Meteor Lake-S maybe cancelled, replaced by arrow
+ elsif ($model =~ /^(C5|C6)$/){
+ $arch = 'Arrow Lake'; # 15 gen; igpu battleimage 3/4nm
+ # gfx tile is TSMC 3nm
+ $process = 'Intel 20a (2nm)';# TSMC 3nm (corei3-5)/Intel 20A 2nm (core i5-9)
+ $year = '2024+';} # check when actually in production
+ elsif ($model =~ /^(CC)$/){
+ $arch = 'Panther Lake'; # 17 gen
+ $process = 'Intel 18a (1.8nm)';
+ $year = '2025+';}
+ elsif ($model =~ /^(CF)$/){
+ $arch = 'Emerald Rapids'; # 5th gen xeon
+ $process = 'Intel 7 (10nm)';
+ $year = '2023+';}
+ ## roadmaps: check and update, since Intel misses their targets often
+ # Sapphire Rapids: 13 gen (?), Intel 7 (10nm), 2023
# Emerald Rapids: Intel 7 (10nm), 2023
# Granite Rapids: Intel 3 (7nm+), 2024
# Diamond Rapids: Intel 3 (7nm+), 2025
- # Arrow Lake - 15 gen, Intel 20A (2nm), 2024
- # Lunar Lake - 16 gen, Intel 18A (1.8nm), 2025
- # Nova Lake - 17 gen, Intel 18A (1.8nm), 2026
+ # Raptor Lake: 13 gen, Intel 7 (10nm), 2022
+ # Meteor Lake: 14 gen, Intel 4 (7nm+)
+ # Arrow Lake: 15 gen, TSMC 3nm (corei3-5)/Intel 20A 2nm (core i5-9), 2024
+ # Arrow Lake: 16 gen, TSMC 3nm (corei3-5)/Intel 20A 2nm (core i5-9), 2024, refresh
+ # Lunar Lake: 15 gen, TSMC’s 3nm (N3B), 2024-5
+ # Panther Lake:17 gen, ?, late 2025, cougar cove Xe3 Celestial GPU architecture
+ # Beast Lake: 16 gen, ?, 2026?
+ # Nova Lake: 18 gen, Intel 14A (1.4nm), 2026
}
# itanium 1 family 7 all recalled
elsif ($family eq 'B'){
@@ -11686,6 +12143,7 @@ sub cp_cpu_level {
eval $end if $b_log;
return $level;
}
+
sub cp_cpu_topology {
my ($counts,$topology) = @_;
my @alpha = qw(Single Dual Triple Quad);
@@ -11773,6 +12231,7 @@ sub cp_cpu_topology {
}
$topology->{'string'} ||= '';
}
+
sub cp_cpu_alpha {
my $cores = $_[0];
my $string = '';
@@ -11788,6 +12247,7 @@ sub cp_cpu_alpha {
}
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)
@@ -11856,8 +12316,10 @@ sub cp_cpu_type {
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
+
+# Legacy: this data should be comfing from the /sys tool now.
+# Was 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) = @_;
@@ -11888,6 +12350,7 @@ sub cp_elbrus_data {
eval $end if $b_log;
return $return;
}
+
sub cp_speed_data {
eval $start if $b_log;
my ($cpu,$cpu_sys) = @_;
@@ -11978,6 +12441,7 @@ sub cp_speed_data {
eval $end if $b_log;
return $info;
}
+
sub cp_speed_min_max {
my ($min,$max,$type) = @_;
my ($min_max,$key);
@@ -11996,7 +12460,8 @@ sub cp_speed_min_max {
$key = $type . '-' . $key if $type && $key;
return ($min_max,$key);
}
-# update $tests by reference
+
+# args: 0: cpu, by ref; 1: update $tests by reference
sub cp_test_types {
my ($cpu,$tests) = @_;
if ($cpu->{'type'} eq 'intel'){
@@ -12029,21 +12494,22 @@ sub cpu_vendor {
my ($vendor) = ('');
$string = lc($string);
if ($string =~ /intel/){
- $vendor = "intel"
+ $vendor = "intel";
}
elsif ($string =~ /amd/){
- $vendor = "amd"
+ $vendor = "amd";
}
- # via
- elsif ($string =~ /centaur/){
- $vendor = "centaur"
+ # via/centaur/zhaoxin branding
+ elsif ($string =~ /centaur|zhaoxin/){
+ $vendor = "centaur";
}
elsif ($string eq 'elbrus'){
- $vendor = "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 {
${$_[0]} = {
@@ -12068,6 +12534,7 @@ sub set_cpu_data {
'type' => '',
};
}
+
sub system_cpu_name {
eval $start if $b_log;
my ($compat,@working);
@@ -12109,6 +12576,7 @@ sub clean_speed {
$speed = sprintf("%.0f", $speed);
return $speed;
}
+
sub clean_cpu {
my ($cpu) = @_;
return if !$cpu;
@@ -12120,6 +12588,7 @@ sub clean_cpu {
$cpu =~ s/^\s+|\s+$//g;
return $cpu;
}
+
sub hex_and_decimal {
my ($data) = @_;
$data = '' if !defined $data;
@@ -12145,6 +12614,7 @@ my ($hddtemp,$nvme) = ('','');
my (@by_id,@by_path);
my ($debugger_dir);
# main::writer("$debugger_dir/system-repo-data-urpmq.txt",\@data2) if $debugger_dir;
+
sub get {
eval $start if $b_log;
my ($type) = @_;
@@ -12198,6 +12668,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub storage_output {
eval $start if $b_log;
my ($rows,$disks) = @_;
@@ -12233,11 +12704,12 @@ sub storage_output {
shift @$disks;
eval $end if $b_log;
}
+
sub drive_output {
eval $start if $b_log;
my ($rows,$disks) = @_;
# print Data::Dumper::Dumper $disks;
- my ($b_smart_permissions,$smart_age,$smart_basic,$smart_fail);
+ my ($b_smart_permissions,$block,$smart_age,$smart_basic,$smart_fail);
my ($num,$j) = (0,0);
my ($id,$model,$size) = ('','','');
# note: specific smartctl non-missing errors handled inside loop
@@ -12268,9 +12740,7 @@ sub drive_output {
if ($b_admin && $row->{'maj-min'}){
$rows->[$j]{main::key($num++,0,2,'maj-min')} = $row->{'maj-min'};
}
- if ($row->{'type'}){
- $rows->[$j]{main::key($num++,0,2,'type')} = $row->{'type'};
- }
+
if ($row->{'vendor'}){
$rows->[$j]{main::key($num++,0,2,'vendor')} = $row->{'vendor'};
}
@@ -12287,8 +12757,31 @@ sub drive_output {
$rows->[$j]{main::key($num++,0,2,'size')} = $size;
if ($b_admin && $row->{'block-physical'}){
$rows->[$j]{main::key($num++,1,2,'block-size')} = '';
- $rows->[$j]{main::key($num++,0,3,'physical')} = $row->{'block-physical'} . ' B';
- $rows->[$j]{main::key($num++,0,3,'logical')} = ($row->{'block-logical'}) ? $row->{'block-logical'} . ' B' : 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'physical')} = "$row->{'block-physical'} B";
+ $block = ($row->{'block-logical'}) ? "$row->{'block-logical'} B" : 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'logical')} = $block;
+ }
+ if ($row->{'type'}){
+ $rows->[$j]{main::key($num++,1,2,'type')} = $row->{'type'};
+ if ($extra > 1 && $row->{'type'} eq 'USB' && $row->{'abs-path'} &&
+ $usb{'disk'}){
+ foreach my $device (@{$usb{'disk'}}){
+ if ($device->[8] && $device->[26] &&
+ $row->{'abs-path'} =~ /^$device->[26]/){
+ $rows->[$j]{main::key($num++,0,3,'rev')} = $device->[8];
+ if ($device->[17]){
+ $rows->[$j]{main::key($num++,0,3,'spd')} = $device->[17];
+ }
+ if ($device->[24]){
+ $rows->[$j]{main::key($num++,0,3,'lanes')} = $device->[24];
+ }
+ if ($b_admin && $device->[22]){
+ $rows->[$j]{main::key($num++,0,3,'mode')} = $device->[22];
+ }
+ last;
+ }
+ }
+ }
}
if ($extra > 1 && $row->{'speed'}){
if ($row->{'sata'}){
@@ -12298,8 +12791,8 @@ sub drive_output {
$rows->[$j]{main::key($num++,0,2,'lanes')} = $row->{'lanes'} if $row->{'lanes'};
}
if ($extra > 2){
- $row->{'drive-type'} ||= 'N/A';
- $rows->[$j]{main::key($num++,0,2,'type')} = $row->{'drive-type'};
+ $row->{'tech'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,1,2,'tech')} = $row->{'tech'};
if ($row->{'rotation'}){
$rows->[$j]{main::key($num++,0,2,'rpm')} = $row->{'rotation'};
}
@@ -12317,10 +12810,10 @@ sub drive_output {
$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'};
+ $rows->[$j]{main::key($num++,0,2,'fw-rev')} = $row->{'firmware'};
}
if ($row->{'drive-firmware'}){
- $rows->[$j]{main::key($num++,0,2,'drive rev')} = $row->{'drive-firmware'};
+ $rows->[$j]{main::key($num++,0,2,'drive-rev')} = $row->{'drive-firmware'};
}
}
if ($extra > 0 && $row->{'temp'}){
@@ -12334,11 +12827,10 @@ sub drive_output {
$rows->[$j]{main::key($num++,0,2,'duid')} = main::filter($row->{'duid'});
}
}
- # extra level tests already done
+ # Extra level tests already done
if (defined $row->{'partition-table'}){
$rows->[$j]{main::key($num++,0,2,'scheme')} = $row->{'partition-table'};
}
-
if ($row->{'smart'} || $row->{'smart-error'}){
$j = scalar @$rows;
## Basic SMART and drive info ##
@@ -12351,7 +12843,8 @@ sub drive_output {
}
eval $end if $b_log;
}
-# $num and $rows passed by reference
+
+# args: $num and $rows passed by reference
sub smart_output {
eval $start if $b_log;
my ($type,$smart_data,$row,$j,$num,$rows) = @_;
@@ -12397,8 +12890,8 @@ sub drive_data {
my ($used) = (0);
PartitionItem::set_partitions() if !$loaded{'set-partitions'};
RaidItem::raid_data() if !$loaded{'raid'};
- # see docs/inxi-data.txt PARTITION DATA for more on remote/fuse fs
- my $fs_skip = PartitionItem::fs_excludes('disk-used');
+ # see docs/inxi-partitions.txt > FILE SYSTEMS for more on remote/fuse fs
+ my $fs_skip = PartitionItem::get_filters('fs-exclude');
foreach my $row (@partitions){
# don't count remote/distributed/union type fs towards used
next if ($row->{'fs'} && $row->{'fs'} =~ /^$fs_skip$/);
@@ -12434,6 +12927,7 @@ sub drive_data {
eval $end if $b_log;
return $data;
}
+
sub proc_data {
eval $start if $b_log;
my ($used) = @_;
@@ -12559,6 +13053,9 @@ sub proc_data_advanced {
$working_path = Cwd::abs_path("/sys/block/$drives->[$i]{'id'}");
$working_path =~ s/nvme[^\/]*$//;
}
+ if ($working_path){
+ $drives->[$i]{'abs-path'} = Cwd::abs_path($working_path);
+ }
main::log_data('data',"working path: $working_path") if $b_log;
if ($b_admin && -e "/sys/block/"){
($drives->[$i]{'block-logical'},$drives->[$i]{'block-physical'}) = @{block_data($drives->[$i]{'id'})};
@@ -12611,7 +13108,9 @@ sub proc_data_advanced {
}
if ($working_path){
$path = "${working_path}removable";
- $drives->[$i]{'type'} = 'Removable' if -r $path && main::reader($path,'strip',0); # 0/1 value
+ if (-r $path && main::reader($path,'strip',0)){
+ $drives->[$i]{'type'} = 'Removable' ; # 0/1 value
+ }
}
my $peripheral = peripheral_data($drives->[$i]{'id'});
# note: we only want to update type if we found a peripheral, otherwise preserve value
@@ -12652,14 +13151,14 @@ sub proc_data_advanced {
$drives->[$i]{'partition-table'} = uc($result->[1]) if $result->[1];
if ($result->[2]){
$drives->[$i]{'rotation'} = $result->[2];
- $drives->[$i]{'drive-type'} = 'HDD';
+ $drives->[$i]{'tech'} = 'HDD';
}
elsif (($block_type && $block_type ne 'sdx') ||
# note: this case could conceivabley be wrong for a spun down HDD
(defined $result->[2] && $result->[2] eq '0') ||
($drives->[$i]{'model'} &&
$drives->[$i]{'model'} =~ /(flash|mmc|msata|\bm[\.-]?2\b|nvme|ssd|solid\s?state)/i)){
- $drives->[$i]{'drive-type'} = 'SSD';
+ $drives->[$i]{'tech'} = 'SSD';
}
}
}
@@ -12668,6 +13167,7 @@ sub proc_data_advanced {
eval $end if $b_log;
return $drives;
}
+
# camcontrol identify <device> |grep ^serial (this might be (S)ATA specific)
# smartcl -i <device> |grep ^Serial
# see smartctl; camcontrol devlist; gptid status;
@@ -12857,7 +13357,7 @@ sub smartctl_data {
# openbsd needs the 'c' partition, which is the entire disk
$id .= 'c' if $bsd_type && $bsd_type eq 'openbsd';
$cmd = $alerts{'smartctl'}->{'path'} . " -AHi /dev/" . $id . ' 2>/dev/null';
- @result = main::grabber("$cmd", '', 'strip');
+ @result = main::grabber($cmd, '', 'strip');
main::log_data('dump','@result', \@result) if $b_log; # log before cleanup
@result = grep {!/^(smartctl|Copyright|==)/} @result;
print 'Drive:/dev/' . $id . ":\n", Data::Dumper::Dumper\@result if $dbg[12];
@@ -12941,10 +13441,10 @@ sub smartctl_data {
if ($split[$r] !~ /^Solid/){
$data->[$i]{'rotation'} = $split[$r];
$data->[$i]{'rotation'} =~ s/\s*rpm$//i;
- $data->[$i]{'drive-type'} = 'HDD';
+ $data->[$i]{'tech'} = 'HDD';
}
else {
- $data->[$i]{'drive-type'} = 'SSD';
+ $data->[$i]{'tech'} = 'SSD';
}
}
elsif ($split[$a] eq 'Serial Number'){
@@ -13100,7 +13600,7 @@ sub smartctl_data {
}
elsif ($split[$a] eq 'Media_Wearout_Indicator'){
# $data->[$i]{'smart-media-wearout'} = $split[$r];
- # seen case where they used hex numbers becaause values
+ # seen case where they used hex numbers because values
# were in 47 billion range in hex. You can't hand perl an unquoted
# hex number that is > 2^32 without tripping a perl warning
if ($b_attributes && $split[$r] && !main::is_hex("$split[$r]") && $split[$r] > 0){
@@ -13276,6 +13776,7 @@ sub peripheral_data {
eval $end if $b_log;
return $type;
}
+
sub disk_data_advanced {
eval $start if $b_log;
my ($set_cmd,$id) = @_;
@@ -13338,6 +13839,7 @@ sub disk_data_advanced {
eval $end if $b_log;
return $advanced;
}
+
sub scsi_data {
eval $start if $b_log;
my ($file) = @_;
@@ -13367,6 +13869,7 @@ sub scsi_data {
eval $end if $b_log;
return $scsi;
}
+
# @b_id has already been cleaned of partitions, wwn-, nvme-eui
sub disk_data_by_id {
eval $start if $b_log;
@@ -13395,6 +13898,7 @@ sub disk_data_by_id {
eval $end if $b_log;
return $disk_data;
}
+
## START DISK VENDOR BLOCK ##
# 0 - match pattern; 1 - replace pattern; 2 - vendor print; 3 - serial pattern
sub set_disk_vendors {
@@ -13404,40 +13908,44 @@ sub set_disk_vendors {
['(Crucial|^(C[34]00$|(C300-)?CTF|(FC)?CT|DDAC|M4(\b|SSD))|-CT|Gizmo!)','Crucial','Crucial',''],
# H10 HBRPEKNX0202A NVMe INTEL 512GB
['(\bINTEL\b|^(SSD(PAM|SA2)|HBR|(MEM|SSD)PEB?K|SSD(MCE|S[AC])))','\bINTEL\b','Intel',''],
+ ['^(Intel[\s_-]?)?SRCSAS?','^Intel','Intel RAID',''],
# note: S[AV][1-9]\d can trigger false positives
['(K(ING)?STON|^(OM8P|RBU|S[AV][1234]00|S[HMN]S|SK[CY]|SQ5|SS200|SVP|SS0|SUV|SNV|T52|T[AB]29|Ultimate CF)|V100|DataTraveler|DT\s?(DUO|Microduo|101)|HyperX|13fe\b)','(KINGSTON|13fe)','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 HM
- ['(SAMSUNG|^(AWMB|[BC]DS20|[BC]WB|BJ[NT]|[BC]GND|CJN|CUT|[DG]3 Station|DUO\b|DUT|CKT|[GS]2 Portable|GN|HD\d{3}[A-Z]{2}$|(HM|SP)\d{2}|HS\d|M[AB]G\d[FG]|MCC|MCBOE|MCG\d+GC|[CD]JN|MZ|^G[CD][1-9][QS]|P[BM]\d|(SSD\s?)?SM\s?841)|^SSD\s?[89]\d{2}\s(DCT|PRO|QVD|\d+[GT]B)|\bEVO\b|SV\d|[BE][A-Z][1-9]QT|YP\b|[CH]N-M|MMC[QR]E)','SAMSUNG','Samsung',''], # maybe ^SM, ^HM
+ ['(SAMSUNG|^(AWMB|[BC]DS20|[BC]WB|BJ[NT]|[BC]GND|CJ[NT]|CKT|CUT|[DG]3 Station|DUO\b|DUT|EB\dMW|E[CS]\d[A-Z]\d|FD\d[A-Z]\dGE4S5|[GS]2 Portable|GN|HD\d{3}[A-Z]{2}$|(HM|SP)\d{2}|HS\d|M[AB]G\d[FG]|MCC|MCBOE|MCG\d+GC|[CD]JN|MZ|^G[CD][1-9][QS]|P[BM]\d|(SSD\s?)?SM\s?841)|^SSD\s?[89]\d{2}\s(DCT|PRO|QVD|\d+[GT]B)|\bEVO\b|SV\d|[BE][A-Z][1-9]QT|YP\b|[CH]N-M|MMC[QR]E)','SAMSUNG','Samsung',''], # maybe ^SM, ^HM
# Android UMS Composite?U1
- ['(SanDisk|0781|^(A[BCD]LC[DE]|AFGCE|D[AB]4|DX[1-9]|Extreme|Firebird|S[CD]\d{2}G|SD(S[S]?[ADQ]|SL\d+G|SU\d)|SDW[1-9]|SE\d{2}|SEM[1-9]|\d[STU]|U(3\b|1\d0))|Clip Sport|Cruzer|iXpand|SSD (Plus|U1[01]0) [1-9]|ULTRA\s(FIT|trek|II)|X[1-6]\d{2})','(SanDisk|0781)','SanDisk',''],
+ ['(SanDisk|0781|^(A[BCD]LC[DE]|AFGCE|D[AB]4|DX[1-9]|Extreme|Firebird|S[CD]\d{2}G|SC\d{3,4}|SD(CF|S[S]?[ADQ]|SL\d+G|SU\d|U\d|\sUltra)|SDW[1-9]|SE\d{2}|SEM\d{2}|\d[STU]|U(3\b|1\d0))|Clip Sport|Cruzer|iXpand|SN(\d+G|128|256)|SSD (Plus|U1[01]0) [1-9]|ULTRA\s(FIT|trek|II)|X[1-6]\d{2})','(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
# ST[numbers] excludes other ST starting devices
- ['([S]?SEAGATE|^((Barra|Fire)Cuda|BUP|Expansion|(ATA\s|HDD\s)?ST\d{2}|5AS|X[AFP])|Expansion Desk|FreeAgent|GoFlex|INIC|Backup(\+|\s?Plus)\s?(Hub)?|OneTouch|Slim\s?BK)','[S]?SEAGATE','Seagate',''],
- ['^(WD|WL[0]9]|Western Digital|My (Book|Passport)|\d*LPCX|Elements|easystore|EA[A-Z]S|EARX|EFRX|EZRX|\d*EAVS|G[\s-]Drive|i HTS|0JD|JP[CV]|MD0|M000|\d+(BEV|(00)?AAK|AAV|AZL|EA[CD]S)|PC\sSN|SPZX|3200[AB]|2500[BJ]|20G2|5000[AB]|6400[AB]|7500[AB]|00[ABL][A-Z]{2}|SSC\b)','(^WDC|Western\s?Digital)','Western Digital',''],
+ ['([S]?SEAGATE|^((Barra|Fire)Cuda|BUP|EM\d{3}|Expansion|(ATA\s|HDD\s)?ST\d{2}|5AS|X[AFP])|Backup(\+|\s?Plus)\s?(Hub)?|DS2\d|Expansion Desk|FreeAgent|GoFlex|INIC|IronWolf|OneTouch|Slim\s?BK)','[S]?SEAGATE','Seagate',''],
+ ['^(WD|WL[0]9]|Western Digital|My (Book|Passport)|\d*LPCX|Elements|easystore|EA[A-Z]S|EARX|EFRX|EZRX|\d*EAVS|G[\s-]Drive|i HTS|0JD|JP[CV]|MD0|M000|\d+(BEV|(00)?AAK|AAV|AZL|EA[CD]S)|PC\sSN|SN530|SPZX|3200[AB]|2500[BJ]|20G2|5000[AB]|6400[AB]|7500[AB]|00[ABL][A-Z]{2}|SSC\b)','(^WDC|Western\s?Digital)','Western Digital',''],
# rare cases WDC is in middle of string
['(\bWDC\b|1002FAEX)','','Western Digital',''],
- ## THEN BETTER KNOWN ONESs ##
+
+ ## THEN BETTER KNOWN ONES ##
+ ['^(AccelStor|GS\d{3,})','^AccelStor','AccelStor',''],
['^Acer','^Acer','Acer',''],
# A-Data can be in middle of string
- ['^(.*\bA-?DATA|ASP\d|AX[MN]|CH11|HV[1-9]|IM2|HD[1-9]|HDD\s?CH|IUM|SX\d|Swordfish)','A-?DATA','A-Data',''],
+ ['^(.*\bA-?DATA|ASP\d|AX[MN]|CH11|FX63|HV[1-9]|IM2|HD[1-9]|HDD\s?CH|IUM|SX\d|Swordfish)','A-?DATA','A-Data',''],
['^(ASUS|ROG)','^ASUS','ASUS',''], # ROG ESD-S1C
# ATCS05 can be hitachi travelstar but not sure
['^ATP','^ATP\b','ATP',''],
+ ['^(BlueRay|SSD\d+GM)','^BlueRay','BlueRay',''],
# Force MP500
['^(Corsair|Force\s|(Flash\s*)?(Survivor|Voyager)|Neutron|Padlock)','^Corsair','Corsair',''],
- ['^(FUJITSU|MJA|MH[TVWYZ]\d|MP|MAP\d|F\d00s?-)','^FUJITSU','Fujitsu',''],
+ ['^(FUJITSU|MJA|MH[RTVWYZ]\d|MP|MAP\d|F\d00s?-)','^FUJITSU','Fujitsu',''],
# MAB3045SP shows as HP or Fujitsu, probably HP branded fujitsu
['^(MAB\d)','^(HP\b|FUJITSU)','Fujitsu/HP',''],
# note: 2012: wdc bought hgst
['^(DKR|HGST|Touro|54[15]0|7250|HC[CT]\d)','^HGST','HGST (Hitachi)',''], # HGST HUA
['^((ATA\s)?Hitachi|HCS|HD[PST]|DK\d|IC|(HDD\s)?HT|HU|HMS|HDE|0G\d|IHAT)','Hitachi','Hitachi',''],
# vb: VB0250EAVER but clashes with vbox; HP_SSD_S700_120G ;GB0500EAFYL GB starter too generic?
- ['^(HP\b|[MV]B[0-6]|G[BJ]\d|DF\d|F[BK]|0-9]|MM\d{4}|PSS|XR\d{4}|c350|v\d{3}[bgorw]$|x\d{3}[w]$|VK0|HC[CPY]\d|EX9\d\d|VO0)','^HP','HP',''],
+ ['^(HP\b|c350|DF\d|EG0\d{3}|EX9\d\d|G[BJ]\d|F[BK]|0-9]|HC[CPY]\d|MM\d{4}|[MV]B[0-6]|PSS|VO0|VK0|v\d{3}[bgorw]$|x\d{3}[w]$|XR\d{4})','^HP','HP',''],
['^(Lexar|LSD|JumpDrive|JD\s?Firefly|LX\d|WorkFlow)','^Lexar','Lexar',''], # mmc-LEXAR_0xb016546c; JD Firefly;
# these must come before maxtor because STM
['^STmagic','^STmagic','STmagic',''],
@@ -13453,6 +13961,7 @@ sub set_disk_vendors {
# note: get rid of: M[DGK] becasue mushkin starts with MK
# note: seen: KXG50ZNV512G NVMe TOSHIBA 512GB | THNSN51T02DUK NVMe TOSHIBA 1024GB
['(TOSHIBA|TransMemory|KBG4|^((A\s)?DT01A|M[GKQ]\d|HDW|SA\d{2}G$|(008|016|032|064|128)G[379E][0-9A]$|[S]?TOS|THN)|0930|KSG\d)','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
@@ -13464,19 +13973,26 @@ sub set_disk_vendors {
['^Acasis','^Acasis','Acasis (hub)',''],
['^Acclamator','^Acclamator','Acclamator',''],
['^(Actions|HS USB Flash|10d6)','^(Actions|10d6)','Actions',''],
+ ['^(A-?DATA|ED\d{3}|NH01|Swordfish|SU\d{3}|SX\d{3}|XM\d{2})','^A-?DATA','ADATA',''],
['^Addlink','^Addlink','Addlink',''],
['^(ADplus|SuperVer\b)','^ADplus','ADplus',''],
['^ADTRON','^ADTRON','Adtron',''],
['^(Advantech|SQF)','^Advantech','Advantech',''],
['^AEGO','^AEGO','AEGO',''],
['^AFOX','^AFOX','AFOX',''],
+ ['^AFTERSHOCK','^AFTERSHOCK','AFTERSHOCK',''],
['^(Agile|AGI)','^(AGI|Agile\s?Gear\s?Int[a-z]*)','AGI',''],
+ ['^Aigo','^Aigo','Aigo',''],
+ ['^AirDisk','^AirDisk','AirDisk',''],
['^Aireye','^Aireye','Aireye',''],
['^Alcatel','^Alcatel','Alcatel',''],
['^(Alcor(\s?Micro)?|058F)','^(Alcor(\s?Micro)?|058F)','Alcor Micro',''],
['^Alfawise','^Alfawise','Alfawise',''],
- ['^Android','^Android','Android',''],
+ ['(^ALKETRON|FireWizard)','^ALKETRON','ALKETRON',''],
['^ANACOMDA','^ANACOMDA','ANACOMDA',''],
+ ['^Android','^Android','Android',''],
+ ['^ANK','^Anker','Anker',''],
+ ['^Ant[\s_-]?Esports','^Ant[\s_-]?Esports','Ant Esports',''],
['^Anucell','^Anucell','Anucell',''],
['^Apotop','^Apotop','Apotop',''],
# must come before AP|Apacer
@@ -13487,8 +14003,11 @@ sub set_disk_vendors {
['^Arch','^Arch(\s*Memory)?','Arch Memory',''],
['^(Asenno|AS[1-9])','^Asenno','Asenno',''],
['^Asgard','^Asgard','Asgard',''],
+ ['^ASint','^ASint','ASint',''],
+ ['^(ASL|\d+[A-Z]{1,2}\d+-ASL\b)','^ASL','ASL',''], # 99IB3321-ASL
['^(ASM|2115)','^ASM','ASMedia',''],#asm1153e
['^ASolid','^ASolid','ASolid',''],
+ # ASTC (Advanced Storage Technology Consortium)
['^(AVEXIR|AVSSD)','^AVEXIR','Avexir',''],
['^Axiom','^Axiom','Axiom',''],
['^(Baititon|BT\d)','^Baititon','Baititon',''],
@@ -13496,6 +14015,7 @@ sub set_disk_vendors {
['^(Beckhoff)','^Beckhoff','Beckhoff',''],
['^Bell\b','^Bell','Packard Bell',''],
['^(BelovedkaiAE|GhostPen)','^BelovedkaiAE','BelovedkaiAE',''],
+ ['^BHM\b','^BHM','BHM',''],
['^(BHT|WR20)','^BHT','BHT',''],
['^(Big\s?Reservoir|B[RG][_\s-])','^Big\s?Reservoir','Big Reservoir',''],
['^BIOSTAR','^BIOSTAR','Biostar',''],
@@ -13506,25 +14026,31 @@ sub set_disk_vendors {
['^Bory','^Bory','Bory',''],
['^Braveeagle','^Braveeagle','BraveEagle',''],
['^(BUFFALO|BSC)','^BUFFALO','Buffalo',''], # usb: BSCR05TU2
+ ['^Bugatek','^Bugatek','Bugatek',''],
['^Bulldozer','^Bulldozer','Bulldozer',''],
['^BUSlink','^BUSlink','BUSlink',''],
['^(Canon|MP49)','^Canon','Canon',''],
['^Centerm','^Centerm','Centerm',''],
['^(Centon|DS pro)','^Centon','Centon',''],
['^(CFD|CSSD)','^CFD','CFD',''],
+ ['^CHIPAL','^CHIPAL','CHIPAL',''],
['^(Chipsbank|CHIPSBNK)','^Chipsbank','Chipsbank',''],
+ ['^(Chipfancie)','^Chipfancier','Chipfancier',''],
['^Clover','^Clover','Clover',''],
['^CODi','^CODi','CODi',''],
['^Colorful\b','^Colorful','Colorful',''],
+ ['^CONSISTENT','^CONSISTENT','Consistent',''],
# note: www.cornbuy.com is both a brand and also sells other brands, like newegg
# addlink; colorful; goldenfir; kodkak; maxson; netac; teclast; vaseky
['^Corn','^Corn','Corn',''],
['^CnMemory|Spaceloop','^CnMemory','CnMemory',''],
['^(Creative|(Nomad\s?)?MuVo)','^Creative','Creative',''],
['^CSD','^CSD','CSD',''],
+ ['^CYX\b','^CYX','CYX',''],
['^(Dane-?Elec|Z Mate)','^Dane-?Elec','DaneElec',''],
['^DATABAR','^DATABAR','DataBar',''],
# Daplink vfs is an ARM software thing
+ ['^(Data\s?Memory\s?Systems|DMS)','^Data\s?Memory\s?Systems','Data Memory Systems',''],
['^Dataram','^Dataram','Dataram',''],
['^DELAIHE','^DELAIHE','DELAIHE',''],
# DataStation can be Trekstore or I/O gear
@@ -13532,23 +14058,30 @@ sub set_disk_vendors {
['^DeLOCK','^Delock(\s?products)?','Delock',''],
['^Derler','^Derler','Derler',''],
['^detech','^detech','DETech',''],
+ ['^DEXP','^DEXP','DEXP',''],
['^DGM','^DGM\b','DGM',''],
['^(DICOM|MAESTRO)','^DICOM','DICOM',''],
['^Digifast','^Digifast','Digifast',''],
['^DIGITAL\s?FILM','DIGITAL\s?FILM','Digital Film',''],
+ ['^(Digma|Run(\sY2)?\b)','^Digma','Digma',''],
['^Dikom','^Dikom','Dikom',''],
+ ['^DINGGE','^DINGGE','DINGGE',''],
['^Disain','^Disain','Disain',''],
+ ['^(Disco|Go-Infinity)','^Disco','Disco',''],
+ ['^(Disk2go|Three[\s_-]?O)','^Disk2go','Disk2go',''],
['^(Disney|PIX[\s]?JR)','^Disney','Disney',''],
['^(Doggo|DQ-|Sendisk|Shenchu)','^(doggo|Sendisk(.?Shenchu)?|Shenchu(.?Sendisk)?)','Doggo (SENDISK/Shenchu)',''],
['^(Dogfish|M\.2 2242|Shark)','^Dogfish(\s*Technology)?','Dogfish Technology',''],
['^DragonDiamond','^DragonDiamond','DragonDiamond',''],
['^(DREVO\b|X1\s\d+[GT])','^DREVO','Drevo',''],
['^DSS','^DSS DAHUA','DSS DAHUA',''],
+ ['^(Duex|DX\b)','^Duex','Duex',''], # DX\d may be starter for sandisk string
['^(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',''],
['^(Easy[\s-]?Memory)','^Easy[\s-]?Memory','Easy Memory',''],
['^EDGE','^EDGE','EDGE Tech',''],
+ ['^(EDILOCA|ES\d+\b)','^EDILOCA','Ediloca',''],
['^Elecom','^Elecom','Elecom',''],
['^Eluktro','^Eluktronics','Eluktronics',''],
['^Emperor','^Emperor','Emperor',''],
@@ -13558,10 +14091,14 @@ sub set_disk_vendors {
['^eNova','^eNOVA','eNOVA',''],
['^Epson','^Epson','Epson',''],
['^(Etelcom|SSD051)','^Etelcom','Etelcom',''],
+ ['^(Shenzhen\s)?Etopso(\sTechnology)?','^(Shenzhen\s)?Etopso(\sTechnology)?','Etopso',''],
['^EURS','^EURS','EURS',''],
['^eVAULT','^eVAULT','eVAULT',''],
+ ['^EVM','^EVM','EVM',''],
+ ['^eVtran','^eVtran','eVtran',''],
# NOTE: ESA3... may be IBM PCIe SAD card/drives
['^(EXCELSTOR|r technology)','^EXCELSTOR( TECHNO(LOGY)?)?','ExcelStor',''],
+ ['^EXRAM','^EXRAM','EXRAM',''],
['^EYOTA','^EYOTA','EYOTA',''],
['^EZCOOL','^EZCOOL','EZCOOL',''],
['^EZLINK','^EZLINK','EZLINK',''],
@@ -13571,51 +14108,67 @@ sub set_disk_vendors {
['^FASTDISK','^FASTDISK','FASTDISK',''],
['^Festtive','^Festtive','Festtive',''],
['^FiiO','^FiiO','FiiO',''],
+ ['^FixMeStick','^FixMeStick','FixMeStick',''],
+ ['^(FIKWOT|FS\d{3})','^FIKWOT','Kikwot',''],
['^Fordisk','^Fordisk','Fordisk',''],
# FK0032CAAZP/FB160C4081 FK or FV can be HP but can be other things
['^(FORESEE|B[123]0)|P900F|S900M','^FORESEE','Foresee',''],
['^Founder','^Founder','Founder',''],
['^(FOXLINE|FLD)','^FOXLINE','Foxline',''], # russian vendor?
- ['^(GALAX\b|Gamer\s?L|TA\dD|Gamer[\s-]?V)','^GALAX','GALAX',''],
+ ['^(Gateway|W800S)','^Gateway','Gateway',''],
['^Freecom','^Freecom(\sFreecom)?','Freecom',''],
+ ['^(FronTech)','^FronTech','Frontech',''],
+ ['^(Fuhler|FL-D\d{3})','^Fuhler','Fuhler',''],
+ ['^Gaiver','^Gaiver','Gaiver',''],
+ ['^(GALAX\b|Gamer\s?L|TA\dD|Gamer[\s-]?V)','^GALAX','GALAX',''],
['^Galaxy\b','^Galaxy','Galaxy',''],
['^Gamer[_\s-]?Black','^Gamer[_\s-]?Black','Gamer Black',''],
['^(Garmin|Fenix|Nuvi|Zumo)','^Garmin','Garmin',''],
['^Geil','^Geil','Geil',''],
['^GelL','^GelL','GelL',''], # typo for Geil? GelL ZENITH R3 120GB
- ['^(Generic|G1J3|SCA128|SLD|UY[67])','^Generic','Generic',''],
+ ['^(Generic|A3A|G1J3|M0S00|SCA\d{2}|SCY|SLD|S0J\d|UY[567])','^Generic','Generic',''],
['^(Genesis(\s?Logic)?|05e3)','(Genesis(\s?Logic)?|05e3)','Genesis Logic',''],
['^Geonix','^Geonix','Geonix',''],
['^Getrich','^Getrich','Getrich',''],
['^(Gigabyte|GP-G)','^Gigabyte','Gigabyte',''], # SSD
['^Gigastone','^Gigastone','Gigastone',''],
['^Gigaware','^Gigaware','Gigaware',''],
+ ['^GJN','^GJN\b','GJN',''],
['^(Gloway|FER\d)','^Gloway','Gloway',''],
['^GLOWY','^GLOWY','Glowy',''],
['^Goldendisk','^Goldendisk','Goldendisk',''],
['^Goldenfir','^Goldenfir','Goldenfir',''],
+ ['^(Goldkey|GKH\d)','^Goldkey','Goldkey',''],
['^Golden[\s_-]?Memory','^Golden[\s_-]?Memory','Golden Memory',''],
['^(Goldkey|GKP)','^Goldkey','GoldKey',''],
+ ['^(Goline)','^Goline','Goline',''],
# Wilk Elektronik SA, poland
- ['^(Wilk\s*)?(GOODRAM|GOODDRIVE|IR[\s-]?SSD|IRP|SSDPR|Iridium)','^GOODRAM','GOODRAM',''],
+ ['^((Wilk|WE)\s*)?(GOODRAM|GOODDRIVE|IR[\s-]?SSD|IRP|SSDPR|Iridium)','^GOODRAM','GOODRAM',''],
+ ['^(GreatWall|GW\d{3})','^GreatWall','GreatWall',''],
+ ['^(GreenHouse|GH\b)','^GreenHouse','GreenHouse',''],
['^Gritronix','^Gritronixx?','Gritronix',''],
# supertalent also has FM: |FM
['^(G[\.]?SKILL)','^G[\.]?SKILL','G.SKILL',''],
['^G[\s-]*Tech','^G[\s-]*Tech(nology)?','G-Technology',''],
- ['^Gaiver','^Gaiver','Gaiver',''],
+ ['^(Gudga|GIM\d+|G[NV](R\d|\d{2,4}\b))','^Gudga','Gudga',''],
['^(Hajaan|HS[1-9])','^Haajan','Haajan',''],
['^Haizhide','^Haizhide','Haizhide',''],
['^(Hama|FlashPen\s?Fancy)','^Hama','Hama',''],
+ ['^(Hanye|Q60)','^Hanye','Hanye',''],
['^HDC','^HDC\b','HDC',''],
['^Hectron','^Hectron','Hectron',''],
['^HEMA','^HEMA','HEMA',''],
['(HEORIADY|^HX-0)','^HEORIADY','HEORIADY',''],
['^(Hikvision|HKVSN|HS-SSD)','^Hikvision','Hikvision',''],
+ ['^Hi[\s-]?Level ','^Hi[\s-]?Level ','Hi-Level',''], # ^HI\b with no Level?
+ ['^(Hisense|H8G)','^Hisense','Hisense',''],
['^Hoodisk','^Hoodisk','Hoodisk',''],
- ['^HUAWEI','^HUAWEI','Huawei',''],
+ ['^(HUAWEI|HWE)','^HUAWEI','Huawei',''],
['^Hypertec','^Hypertec','Hypertec',''],
['^HyperX','^HyperX','HyperX',''],
- ['^(Hyundai|Sapphire)','^Hyundai','Hyundai',''],
+ ['^(HYSSD|HY-)','^HYSSD','HYSSD',''],
+ ['^(Hyundai|C2S\d|Sapphire)','^Hyundai','Hyundai',''],
+ ['^iMRAM','^iMRAM','iMRA',''],
['^(IBM|DT|ESA[1-9]|ServeRaid)','^IBM','IBM',''], # M5110 too common
['^IEI Tech','^IEI Tech(\.|nology)?( Corp(\.|oration)?)?','IEI Technology',''],
['^(IGEL|UD Pocket)','^IGEL','IGEL',''],
@@ -13628,11 +14181,12 @@ sub set_disk_vendors {
['^(Infokit)','^Infokit','Infokit',''],
# note: Initio default controller, means master/slave jumper is off/wrong, not a vendor
['^Inland','^Inland','Inland',''],
- ['^(InnoDisk|Innolite|SATA\s?Slim|DRPS)','^InnoDisk( Corp.)?','InnoDisk',''],
+ ['^(InnoDisk|DEM\d|Innolite|SATA\s?Slim|DRPS)','^InnoDisk( Corp.)?','InnoDisk',''],
['(Innostor|1f75)','(Innostor|1f75)','Innostor',''],
['(^Innovation|Innovation\s?IT)','Innovation(\s*IT)?','Innovation IT',''],
['^Innovera','^Innovera','Innovera',''],
- ['^(I\.?norys|INO-?IH])','^I\.?norys','I.norys',''],
+ ['^(I\.?norys|INO-?IH])','^I\.?norys','I.norys','']
+ ,['(^Insignia|NS[\s-]?PCNV)','^Insignia','Insignia',''],
['^Intaiel','^Intaiel','Intaiel',''],
['^(INM|Integral|V\s?Series)','^Integral(\s?Memory)?','Integral Memory',''],
['^(lntenso|Intenso|(Alu|Basic|Business|Micro|c?Mobile|Premium|Rainbow|Slim|Speed|Twister|Ultra) Line|Rainbow)','^Intenso','Intenso',''],
@@ -13640,6 +14194,7 @@ sub set_disk_vendors {
['^(INO-|i\.?norys)','^i\.?norys','i.norys',''],
['^(Integrated[\s-]?Technology|IT\d+)','^Integrated[\s-]?Technology','Integrated Technology',''],
['^(Iomega|ZIP\b|Clik!)','^Iomega','Iomega',''],
+ ['^(i[\s_-]?portable\b|ATCS)','^i[\s_-]?portable','i-Portable',''],
['^ISOCOM','^ISOCOM','ISOCOM (Shenzhen Longsys Electronics)',''],
['^iTE[\s-]*Tech','^iTE[\s-]*Tech(nology)?','iTE Tech',''],
['^(James[\s-]?Donkey|JD\d)','^James[\s-]?Donkey','James Donkey',''],
@@ -13648,58 +14203,72 @@ sub set_disk_vendors {
['^Jingyi','^Jingyi','Jingyi',''],
# NOTE: ITY2 120GB hard to find
['^JMicron','^JMicron(\s?Tech(nology)?)?','JMicron Tech',''], #JMicron H/W raid
+ ['^JSYERA','^JSYERA','Jsyera',''],
['^(Jual|RX7)','^Jual','Jual',''],
+ ['^(J\.?ZAO|JZ)','^J\.?ZAO','J.ZAO',''],
['^Kazuk','^Kazuk','Kazuk',''],
['(\bKDI\b|^OM3P)','\bKDI\b','KDI',''],
+ ['^KEEPDATA','^KEEPDATA','KeepData',''],
['^KLLISRE','^KLLISRE','KLLISRE',''],
['^KimMIDI','^KimMIDI','KimMIDI',''],
['^Kimtigo','^Kimtigo','Kimtigo',''],
['^Kingbank','^Kingbank','Kingbank',''],
+ ['^(KingCell|KC\b)','^KingCell','KingCell',''],
['^Kingchux[\s-]?ing','^Kingchux[\s-]?ing','Kingchuxing',''],
+ ['^(KINGCOMP|KCSSD)','^KINGCOMP','KingComp',''],
['(KingDian|^NGF|S(280|400))','KingDian','KingDian',''],
['^(Kingfast|TYFS)','^Kingfast','Kingfast',''],
['^KingMAX','^KingMAX','KingMAX',''],
['^Kingrich','^Kingrich','Kingrich',''],
['^Kingsand','^Kingsand','Kingsand',''],
['KING\s?SHA\s?RE','KING\s?SHA\s?RE','KingShare',''],
- ['^(KingSpec|ACSC|C3000|KS[DQ]|N[ET]-\d|P3$|P4\b|PA[_-]?(18|25)|Q-180|T-(3260|64|128)|Z(\d\s|F\d))','^KingSpec','KingSpec',''],
+ ['^(KingSpec|ACSC|C3000|KS[DQ]|MSH|N[ET]-\d|NX-\d{2,4}|P3$|P4\b|PA[_-]?(18|25)|Q-180|SPK|T-(3260|64|128)|Z(\d\s|F\d))','^KingSpec','KingSpec',''],
['^KingSSD','^KingSSD','KingSSD',''],
# kingwin docking, not actual drive
['^(EZD|EZ-Dock)','','Kingwin Docking Station',''],
['^Kingwin','^Kingwin','Kingwin',''],
+ ['^KLLISRE','^KLLISRE','KLLISRE',''],
['(KIOXIA|^K[BX]G\d)','KIOXIA','KIOXIA',''], # company name comes after product ID
['^(KLEVV|NEO\sN|CRAS)','^KLEVV','KLEVV',''],
- ['^Kodak','^Kodak','Kodak',''],
+ ['^(Kodak|Memory\s?Saver)','^Kodak','Kodak',''],
+ ['^(KOOTION)','^KOOTION','KOOTION',''],
['^(KUAIKAI|MSAM)','^KUAIKAI','KuaKai',''],
['(KUIJIA|DAHUA)','^KUIJIA','KUIJIA',''],
['^KUNUP','^KUNUP','KUNUP',''],
['^KUU','^KUU\b','KUU',''], # KUU-128GB
['^(Lacie|P92|itsaKey|iamaKey)','^Lacie','LaCie',''],
['^LANBO','^LANBO','LANBO',''],
+ ['^LankXin','^LankXin','LankXin',''],
['^LANTIC','^LANTIC','Lantic',''],
['^Lapcare','^Lapcare','Lapcare',''],
['^(Lazos|L-?ISS)','^Lazos','Lazos',''],
['^LDLC','^LDLC','LDLC',''],
# LENSE30512GMSP34MEAT3TA / UMIS RPITJ256PED2MWX
- ['^(LEN|UMIS)','^Lenovo','Lenovo',''],
+ ['^(LEN|UMIS|Think)','^Lenovo','Lenovo',''],
['^RPFT','','Lenovo O.E.M.',''],
# JAJS300M120C JAJM600M256C JAJS600M1024C JAJS600M256C JAJMS600M128G
['^(Leven|JAJ[MS])','^Leven','Leven',''],
+ ['^(LEQIXIANG)','^LEQIXIANG','Leqixiang',''],
['^(LG\b|Xtick)','^LG','LG',''],
+ ['^Lidermix','Lidermix','Lidermix',''],
['(LITE[-\s]?ON[\s-]?IT)','LITE[-]?ON[\s-]?IT','LITE-ON IT',''], # LITEONIT_LSS-24L6G
# PH6-CE240-L; CL1-3D256-Q11 NVMe LITEON 256GB
['(LITE[-\s]?ON|^PH[1-9]|^DMT|^CV\d-|L(8[HT]|AT|C[HST]|JH|M[HST]|S[ST])-|^S900)','LITE[-]?ON','LITE-ON',''],
['^LONDISK','^LONDISK','LONDISK',''],
['^Longline','^Longline','Longline',''],
['^LuminouTek','^LuminouTek','LuminouTek',''],
- ['^(LSI|MegaRAID)','^LSI\b','LSI',''],
+ ['^Lunatic','^Lunatic','Lunatic',''],
+ ['^(LSI|MegaRAID|MR\d{3,4}\b)','^LSI\b','LSI',''],
['^(M-Systems|DiskOnKey)','^M-Systems','M-Systems',''],
['^(Mach\s*Xtreme|MXSSD|MXU|MX[\s-])','^Mach\s*Xtreme','Mach Xtreme',''],
+ ['^(MacroVIP|MV(\d|GLD))','^MacroVIP','MacroVIP',''], # maybe MV alone
['^Mainic','^Mainic','Mainic',''],
+ ['^(MARSHAL\b|MAL\d)','^MARSHAL','Marshal',''],
+ ['^Maxell','^Maxell','Maxell',''],
['^Maximus','^Maximus','Maximus',''],
+ ['^MAXIO','^MAXIO','Maxio',''],
+ ['^Maxmem','^Maxmem','Maxmem',''],
['^Maxone','^Maxone','Maxone',''],
- ['^(Memorex|TravelDrive|TD\s?Classic)','^Memorex','Memorex',''],
- ['^(MARSHAL\b|MAL\d)','^MARSHAL','Marshal',''],
['^MARVELL','^MARVELL','Marvell',''],
['^Maxsun','^Maxsun','Maxsun',''],
['^MDT\b','^MDT','MDT (rebuilt WD/Seagate)',''], # mdt rebuilds wd/seagate hdd
@@ -13707,7 +14276,9 @@ sub set_disk_vendors {
['^MD[1-9]','^Max\s*Digital','MaxDigital',''],
['^Medion','^Medion','Medion',''],
['^(MEDIAMAX|WL\d{2})','^MEDIAMAX','MediaMax',''],
+ ['^(Memorex|TravelDrive|TD\s?Classic)','^Memorex','Memorex',''],
['^Mengmi','^Mengmi','Mengmi',''],
+ ['^MicroFrom','^MicroFrom','MicroFrom',''],
['^MGTEC','^MGTEC','MGTEC',''],
# must come before micron
['^(Mtron|MSP)','^Mtron','Mtron',''],
@@ -13726,26 +14297,33 @@ sub set_disk_vendors {
['^Morebeck','^Morebeck','Morebeck',''],
['^(Moser\s?Bear|MBIL)','^Moser\s?Bear','Moser Bear',''],
['^(Motile|SSM\d)','^Motile','Motile',''],
- ['^(Motorola|XT\d{4})','^Motorola','Motorola',''],
+ ['^(Motorola|XT\d{4}|Moto[\s-]?[EG])','^Motorola','Motorola',''],
['^Moweek','^Moweek','Moweek',''],
+ ['^(Move[\s-]?Speed|YSSD)','^Move[\s-]?Speed','Move Speed',''],
#MRMAD4B128GC9M2C
['^(MRMA|Memoright)','^Memoright','Memoright',''],
['^MSI\b','^MSI\b','MSI',''],
['^MTASE','^MTASE','MTASE',''],
['^MTRON','^MTRON','MTRON',''],
['^(MyDigitalSSD|BP[4X])','^MyDigitalSSD','MyDigitalSSD',''], # BP4 = BulletProof4
+ ['^MyMedia','^MyMedia','MyMedia',''],
['^(Myson)','^Myson([\s-]?Century)?([\s-]?Inc\.?)?','Myson Century',''],
+ ['^(Natusun|i-flashdisk)','^Natusun','Natusun',''],
['^(Neo\s*Forza|NFS\d)','^Neo\s*Forza','Neo Forza',''],
- ['^(Netac|OnlyDisk|S535N)','^Netac','Netac',''],
+ ['^(Netac|NS\d{3}|OnlyDisk|S535N)','^Netac','Netac',''],
+ ['^Newsmy','^Newsmy','Newsmy',''],
['^NFHK','^NFHK','NFHK',''],
# NGFF is a type, like msata, sata
['^Nik','^Nikimi','Nikimi',''],
['^NOREL','^NOREL(SYS)?','NorelSys',''],
+ ['^(N[\s-]?Tech|NT\d)','^N[\s-]?Tec','N Tech',''], # coudl be ^NT alone
+ ['^NXTech','^NXTech','NXTech',''],
['^ODYS','^ODYS','ODYS',''],
['^Olympus','^Olympus','Olympus',''],
['^Orico','^Orico','Orico',''],
['^Ortial','^Ortial','Ortial',''],
['^OSC','^OSC\b','OSC',''],
+ ['^(Ovation)','^Ovation','Ovation',''],
['^oyunkey','^oyunkey','Oyunkey',''],
['^PALIT','PALIT','Palit',''], # ssd
['^Panram','^Panram','Panram',''], # ssd
@@ -13753,30 +14331,41 @@ sub set_disk_vendors {
['^(Pasoul|OASD)','^Pasoul','Pasoul',''],
['^(Patriot|PS[8F]|P2\d{2}|PBT|VPN|Viper|Burst|Blast|Blaze|Pyro|Ignite)','^Patriot([-\s]?Memory)?','Patriot',''],#Viper M.2 VPN100
['^PERC\b','','Dell PowerEdge RAID Card',''], # ssd
- ['(PHISON[\s-]?|ESR\d)','PHISON[\s-]?','Phison',''],# E12-256G-PHISON-SSD-B3-BB1
+ ['(PHISON[\s-]?|ESR\d|PSE)','PHISON[\s-]?','Phison',''],# E12-256G-PHISON-SSD-B3-BB1
['^(Pichau[\s-]?Gaming|PG\d{2})','^Pichau[\s-]?Gaming','Pichau Gaming',''],
['^Pioneer','Pioneer','Pioneer',''],
['^Platinet','Platinet','Platinet',''],
['^(PLEXTOR|PX-)','^PLEXTOR','Plextor',''],
+ ['^(Polion)','^Polion','Polion',''],
['^(PQI|Intelligent\s?Stick|Cool\s?Drive)','^PQI','PQI',''],
['^(Premiertek|QSSD|Quaroni)','^Premiertek','Premiertek',''],
['^(-?Pretec|UltimateGuard)','-?Pretec','Pretec',''],
['^(Prolific)','^Prolific( Technolgy Inc\.)?','Prolific',''],
- # PS3109S9 is the result of an error condition with ssd drive
+ # PS3109S9 is the result of an error condition with ssd controller: Phison PS3109
+ ['^PUSKILL','^PUSKILL','Puskill',''],
['QEMU','^\d*QEMU( QEMU)?','QEMU',''], # 0QUEMU QEMU HARDDISK
['(^Quantum|Fireball)','^Quantum','Quantum',''],
- ['^QUMO','^QUMO','Qumo',''],
+ ['(^QOOTEC|QMT)','^QOOTEC','QOOTEC',''],
+ ['^(QUMO|Q\dDT)','^QUMO','Qumo',''],
+ ['^QOPP','^QOPP','Qopp',''],
+ ['^Qunion','^Qunion','Qunion',''],
['^(R[3-9]|AMD\s?(RADEON)?|Radeon)','AMD\s?(RADEON)?','AMD Radeon',''], # ssd
['^(Ramaxel|RT|RM|RPF|RDM)','^Ramaxel','Ramaxel',''],
+ ['^(Ramsta|RT|SSD\d+GBS8)','^Ramsta','Ramsta',''],
+ ['^RAMOS','^RAMOS','RAmos',''],
['^(Ramsta|R[1-9])','^Ramsta','Ramsta',''],
+ ['^RCESSD','^RCESSD','RCESSD',''],
['^(Realtek|RTL)','^Realtek','Realtek',''],
['^(Reletech)','^Reletech','Reletech',''], # id: P400 but that's too short
['^RENICE','^RENICE','Renice',''],
['^RevuAhn','^RevuAhn','RevuAhn',''],
['^(Ricoh|R5)','^Ricoh','Ricoh',''],
['^RIM[\s]','^RIM','RIM',''],
+ ['^(Rococo|ITE\b|IT\d{4})','^Rococo','Rococo',''],
#RTDMA008RAV2BWL comes with lenovo but don't know brand
['^Runcore','^Runcore','Runcore',''],
+ ['^Rundisk','^Rundisk','RunDisk',''],
+ ['^RZX','^RZX\b','RZX',''],
['^(S3Plus|S3\s?SSD)','^S3Plus','S3Plus',''],
['^(Sabrent|Rocket)','^Sabrent','Sabrent',''],
['^Sage','^Sage(\s?Micro)?','Sage Micro',''],
@@ -13786,6 +14375,7 @@ sub set_disk_vendors {
['^(Sansa|fuse\b)','^Sansa','Sansa',''],
# SATADOM can be innodisk or supermirco: dom == disk on module
# SATAFIRM is an ssd failure message
+ ['^SCUDA','^SCUDA','SCUDA',''],
['^(Sea\s?Tech|Transformer)','^Sea\s?Tech','Sea Tech',''],
['^SigmaTel','^SigmaTel','SigmaTel',''],
# DIAMOND_040_GB
@@ -13793,18 +14383,23 @@ sub set_disk_vendors {
['(Silicon[\s-]?Power|^SP[CP]C|^Silicon|^Diamond|^HasTopSunlightpeed)','Silicon[\s-]?Power','Silicon Power',''],
# simple drive could also maybe be hgst
['^(Simple\s?Tech|Simple[\s-]?Drive)','^Simple\s?Tech','SimpleTech',''],
+ ['^(Simmtronics?|S[79]\d{2}|ZipX)','^Simmtronics?','Simmtronics',''],
['^SINTECHI?','^SINTECHI?','SinTech (adapter)',''],
['^SiS\b','^SiS','SiS',''],
['Smartbuy','\s?Smartbuy','Smartbuy',''], # SSD Smartbuy 60GB; mSata Smartbuy 3
# HFS128G39TND-N210A; seen nvme with name in middle
- ['(SK\s?HYNIX|^HF[MS]|^H[BC]G|^BC\d{3}|^SC[234]\d\d\sm?SATA)','\s?SK\s?HYNIX','SK Hynix',''],
+ ['(SK\s?HYNIX|^HF[MS]|^H[BC]G|^HFB|^BC\d{3}|^SC[234]\d\d\sm?SATA|^SK[\s-]?\d{2,4})','\s?SK\s?HYNIX','SK Hynix',''],
['(hynix|^HAG\d|h[BC]8aP|PC\d{3})','hynix','Hynix',''],# nvme middle of string, must be after sk hynix
['^SH','','Smart Modular Tech.',''],
['^Skill','^Skill','Skill',''],
['^(SMART( Storage Systems)?|TX)','^(SMART( Storage Systems)?)','Smart Storage Systems',''],
['^Sobetter','^Sobetter','Sobetter',''],
- ['^(S[FR]-|Sony|IM9)','^Sony','Sony',''],
+ ['^Solidata','^Solidata','Solidata',''],
+ ['^(SOLIDIGM|SSDPFK)','^SOLIDIGM\b','solidgm',''],
+ ['^(Sony|IM9|Microvalut|S[FR]-)','^Sony','Sony',''],
+ ['^SSK\b','^SSK','SSK',''],
['^(SSSTC|CL1-)','^SSSTC','SSSTC',''],
+ ['^(SST|SG[AN])','^SST\b','SST',''],
['^STE[CK]','^STE[CK]','sTec',''], # wd bought this one
['^STORFLY','^STORFLY','StorFly',''],
['\dSUN\d','^SUN(\sMicrosystems)?','Sun Microsystems',''],
@@ -13818,6 +14413,7 @@ sub set_disk_vendors {
['^(Super\s*Talent|STT|F[HTZ]M\d|PicoDrive|Teranova)','','Super Talent',''],
['^(SF|Swissbit)','^Swissbit','Swissbit',''],
# ['^(SUPERSPEED)','^SUPERSPEED','SuperSpeed',''], # superspeed is a generic term
+ ['^(SXMicro|NF8)','^SXMicro','SXMicro',''],
['^Taisu','^Taisu','Taisu',''],
['^(TakeMS|ColorLine)','^TakeMS','TakeMS',''],
['^Tammuz','^Tammuz','Tammuz',''],
@@ -13825,39 +14421,50 @@ sub set_disk_vendors {
['^(TC[\s-]*SUNBOW|X3\s\d+[GT])','^TC[\s-]*SUNBOW','TCSunBow',''],
['^(TDK|TF[1-9]\d|LoR)','^TDK','TDK',''],
['^TEAC','^TEAC','TEAC',''],
- ['^(TEAM|T[\s-]?Create|L\d\s?Lite|T\d{3,}[A-Z]|TM\d|(Dark\s?)?L3\b|T[\s-]?Force)','^TEAM(\s*Group)?','TeamGroup',''],
+ ['^(TEAM|T[\s-]?Create|CX[12]\b|L\d\s?Lite|T\d{3,}[A-Z]|TM\d|(Dark\s?)?L3\b|T[\s-]?Force)','^TEAM(\s*Group)?','TeamGroup',''],
['^(Teclast|CoolFlash)','^Teclast','Teclast',''],
+ ['^(tecmiyo)','^tecmiyo','TECMIYO',''],
['^Teelkoou','^Teelkoou','Teelkoou',''],
['^Tele2','^Tele2','Tele2',''],
['^Teleplan','^Teleplan','Teleplan',''],
['^TEUTONS','^TEUTONS','TEUTONS',''],
['^(Textorm)','^Textorm','Textorm',''], # B5 too short
+ ['^(T(&|\s?and\s?)?G\d{3})','^T&G\b','T&G',''],
['^THU','^THU','THU',''],
+ ['^Tiger[\s_-]?Jet','^Tiger[\s_-]?Jet','TigerJet',''],
['^Tigo','^Tigo','Tigo',''],
['^(Timetec|35TT)','^Timetec','Timetec',''],
['^TKD','^TKD','TKD',''],
['^TopSunligt','^TopSunligt','TopSunligt',''], # is this a typo? hard to know
['^TopSunlight','^TopSunlight','TopSunlight',''],
['^TOROSUS','^TOROSUS','Torosus',''],
- ['(Transcend|^((SSD\s|F)?TS|EZEX|USDU)|1307|JetDrive|JetFlash)','\b(Transcend|1307)\b','Transcend',''],
+ ['(Transcend|^((SSD\s|F)?TS|ESD\d|EZEX|USDU)|1307|JetDrive|JetFlash)','\b(Transcend|1307)\b','Transcend',''],
['^(TrekStor|DS (maxi|pocket)|DataStation)','^TrekStor','TrekStor',''],
['^Turbox','^Turbox','Turbox',''],
+ ['^TurXun','^TurXun','TurXun',''],
['^(TwinMOS|TW\d)','^TwinMOS','TwinMOS',''],
# note: udisk means usb disk, it's not a vendor ID
['^UDinfo','^UDinfo','UDinfo',''],
['^UMAX','^UMAX','UMAX',''],
+ ['^UpGamer','^UpGamer','UpGamer',''],
['^(UMIS|RP[IJ]TJ)','^UMIS','UMIS',''],
['^USBTech','^USBTech','USBTech',''],
['^(UNIC2)','^UNIC2','UNIC2',''],
['^(UG|Unigen)','^Unigen','Unigen',''],
+ ['^(UNIREX)','^UNIREX','UNIREX',''],
+ ['^(UNITEK)','^UNITEK','UNITEK',''],
['^(USBest|UT16)','^USBest','USBest',''],
['^(OOS[1-9]|Utania)','Utania','Utania',''],
['^U-TECH','U-TECH','U-Tech',''],
+ ['^(Value\s?Tech|VTP\d)','^Value\s?Tech','ValueTech',''],
['^VBOX','','VirtualBox',''],
+ ['^(Veno|Scorp)','^Veno','Veno',''],
['^(Verbatim|STORE\s?\'?N\'?\s?(FLIP|GO)|Vi[1-9]|OTG\s?Tiny)','^Verbatim','Verbatim',''],
- ['^V-GEN','^V-GEN','V-Gen',''],
+ ['^V-?GEN','^V-?GEN','V-Gen',''],
+ ['^VICK','VICK','VICK',''],
['^V[\s-]?(7|Seven)','^V[\s-]?(7|Seven)\b','VSeven',''],
['^(Victorinox|Swissflash)','^Victorinox','Victorinox',''],
+ ['^(Virtium|VTD)','^Virtium','Virtium',''],
['^(Visipro|SDVP)','^Visipro','Visipro',''],
['^VISIONTEK','^VISIONTEK','VisionTek',''],
['^VMware','^VMware','VMware',''],
@@ -13867,31 +14474,38 @@ sub set_disk_vendors {
['^Walton','^Walton','Walton',''],
['^(Wearable|Air-?Stash)','^Wearable','Wearable',''],
['^Wellcomm','^Wellcomm','Wellcomm',''],
- ['^(wicgtyp|N900)','^wicgtyp','wicgtyp',''],
+ ['^(wicgtyp|[MN][V]?900)','^wicgtyp','wicgtyp',''],
['^Wilk','^Wilk','Wilk',''],
['^(WinMemory|SWG\d)','^WinMemory','WinMemory',''],
['^(Winton|WT\d{2})','^Winton','Winton',''],
+ ['^(WISE)','^WISE','WISE',''],
['^WPC','^WPC','WPC',''], # WPC-240GB
['^(Wortmann(\sAG)?|Terra\s?US)','^Wortmann(\sAG)?','Wortmann AG',''],
+ ['^(XDisk|X9\b)','^XDisk','XDisk',''],
['^(XinTop|XT-)','^XinTop','XinTop',''],
['^Xintor','^Xintor','Xintor',''],
['^XPG','^XPG','XPG',''],
['^XrayDisk','^XrayDisk','XrayDisk',''],
['^Xstar','^Xstar','Xstar',''],
+ ['^(Xtigo)','^Xtigo','Xtigo',''],
['^(XUM|HX\d)','^XUM','XUM',''],
['^XUNZHE','^XUNZHE','XUNZHE',''],
['^(Yangtze|ZhiTai|PC00[5-9]|SC00[1-9])','^Yangtze(\s*Memory)?','Yangtze Memory',''],
['^(Yeyian|valk)','^Yeyian','Yeyian',''],
['^(YingChu|YGC)','^YingChu','YingChu',''],
+ ['^YongzhenWeiye','^YongzhenWeiye','YongzhenWeiye',''],
['^(YUCUN|R880)','^YUCUN','YUCUN',''],
['^(ZALMAN|ZM\b)','^ZALMAN','Zalman',''],
+ # Zao/J.Zau: marvell ssd controller
['^ZXIC','^ZXIC','ZXIC',''],
['^(Zebronics|ZEB)','^Zebronics','Zebronics',''],
['^Zenfast','^Zenfast','Zenfast',''],
['^Zenith','^Zenith','Zenith',''],
['^ZEUSLAP','^ZEUSLAP','ZEUSLAP',''],
+ ['^ZEUSS','^ZEUSS','Zeuss',''],
['^(Zheino|CHN|CNM)','^Zheino','Zheino',''],
['^(Zotac|ZTSSD)','^Zotac','Zotac',''],
+ ['^ZOZT','^ZOZT','ZOZT',''],
['^ZSPEED','^ZSPEED','ZSpeed',''],
['^ZTC','^ZTC','ZTC',''],
['^ZTE','^ZTE','ZTE',''],
@@ -13901,6 +14515,7 @@ sub set_disk_vendors {
eval $end if $b_log;
}
## END DISK VENDOR BLOCK ##
+
# receives space separated string that may or may not contain vendor data
sub disk_vendor {
eval $start if $b_log;
@@ -13910,7 +14525,7 @@ sub disk_vendor {
# 0 - match pattern; 1 - replace pattern; 2 - vendor print; 3 - serial pattern
# Data URLs: inxi-resources.txt Section: DriveItem device_vendor()
# $model = 'H10 HBRPEKNX0202A NVMe INTEL 512GB';
- # $model = 'Patriot Memory';
+ # $model = 'SD Ultra 3D 1TB';
set_disk_vendors() if !$vendors;
# prefilter this one, some usb enclosurs and wrong master/slave hdd show default
$model =~ s/^Initio[\s_]//i;
@@ -13936,7 +14551,7 @@ sub disk_vendor {
}
# Normally hddtemp requires root, but you can set user rights in /etc/sudoers.
-# args: $1 - /dev/<disk> to be tested for
+# args: 0: /dev/<disk> to be tested for
sub hdd_temp {
eval $start if $b_log;
my ($device) = @_;
@@ -13983,6 +14598,7 @@ sub hdd_temp {
eval $end if $b_log;
return $hdd_temp;
}
+
sub hdd_temp_sys {
eval $start if $b_log;
my ($device) = @_;
@@ -14054,7 +14670,8 @@ sub hdd_temp_sys {
eval $end if $b_log;
return $hdd_temp;
}
-# args: 1: block id
+
+# args: 0: block id
sub block_data {
eval $start if $b_log;
my ($id) = @_;
@@ -14075,6 +14692,7 @@ sub block_data {
eval $end if $b_log;
return $blocks;
}
+
sub drive_speed {
eval $start if $b_log;
my ($device) = @_;
@@ -14142,8 +14760,10 @@ sub drive_speed {
## GraphicItem
{
package GraphicItem;
-my ($b_primary,$b_wayland_data,%graphics,$monitor_ids,$monitor_map);
+my ($b_primary,$b_wayland_data,%graphics,%mesa_drivers,
+$monitor_ids,$monitor_map);
my ($gpu_amd,$gpu_intel,$gpu_nv);
+
sub get {
eval $start if $b_log;
my $rows = [];
@@ -14178,7 +14798,7 @@ sub get {
# note: not perfect, but we need usb gfx to show for all types, soc, pci, etc
usb_output($rows);
display_output($rows);
- display_api_output($rows);
+ display_api($rows);
(%graphics,$monitor_ids,$monitor_map) = ();
eval $end if $b_log;
return $rows;
@@ -14294,6 +14914,7 @@ sub device_output {
}
eval $end if $b_log;
}
+
sub usb_output {
eval $start if $b_log;
my $rows = $_[0];
@@ -14312,7 +14933,7 @@ sub usb_output {
$product ||= 'N/A';
# note: for real usb video out, no generic drivers? webcams may have one though
if (!$driver){
- if ($row->[14] eq 'Audio-Video'){
+ if ($row->[14] eq 'audio-video'){
$driver = 'N/A';
}
else {
@@ -14321,30 +14942,46 @@ sub usb_output {
}
push(@$rows, {
main::key($num++,1,1,'Device') => $product,
- main::key($num++,0,2,'type') => 'USB',
main::key($num++,0,2,'driver') => $driver,
+ main::key($num++,1,2,'type') => 'USB',
},);
if ($extra > 0){
+ if ($extra > 1){
+ $row->[8] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'rev')} = $row->[8];
+ if ($row->[17]){
+ $rows->[$j]{main::key($num++,0,3,'speed')} = $row->[17];
+ }
+ if ($row->[24]){
+ $rows->[$j]{main::key($num++,0,3,'lanes')} = $row->[24];
+ }
+ if ($b_admin && $row->[22]){
+ $rows->[$j]{main::key($num++,0,3,'mode')} = $row->[22];
+ }
+ }
my $bus_id = "$path_id:$row->[1]";
- if ($extra > 1 && $monitor_ids){
+ if ($monitor_ids){
port_output($bus_id,$j,$rows,\$num);
}
$rows->[$j]{main::key($num++,0,2,'bus-ID')} = $bus_id;
- }
- if ($extra > 1){
- $row->[7] ||= 'N/A';
- $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
- }
- if ($extra > 2 && defined $row->[5] && $row->[5] ne ''){
- $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::filter($row->[16]);
+ if ($extra > 1){
+ $row->[7] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
+ }
+ if ($extra > 2){
+ if (defined $row->[5] && $row->[5] ne ''){
+ $rows->[$j]{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]";
+ }
+ if ($row->[16]){
+ $rows->[$j]{main::key($num++,0,2,'serial')} = main::filter($row->[16]);
+ }
+ }
}
}
eval $end if $b_log;
}
-# $rows, $num by ref
+
+# args: $rows, $num by ref
sub port_output {
my ($bus_id,$j,$rows,$num) = @_;
my (@connected,@disabled,@empty);
@@ -14420,15 +15057,16 @@ sub display_output(){
# print Data::Dumper::Dumper \%graphics;
if (%graphics){
my ($driver_note,$resolution,$server_string) = ('','','');
- my ($b_screen_monitors,$x_drivers);
- $x_drivers = display_drivers_x() if !$force{'wayland'};
+ my ($b_screen_monitors);
+ my $x_drivers = (!$force{'wayland'}) ? display_drivers_x() : [];
+ # print 'result: ', Data::Dumper::Dumper $x_drivers;
# print "$graphics{'x-server'} $graphics{'x-version'} $graphics{'x-vendor-release'}","\n";
if ($graphics{'x-server'}){
$server_string = $graphics{'x-server'}->[0][0];
# print "$server_string\n";
}
if (!$graphics{'protocol'} && !$server_string && !$graphics{'x-server'} &&
- !@$x_drivers){
+ !@$x_drivers && !$graphics{'compositors'}){
$server_string = main::message('display-server');
push(@$rows,{
main::key($num++,1,1,'Display') => '',
@@ -14470,36 +15108,32 @@ sub display_output(){
}
}
# note: if no xorg log, and if wayland, there will be no xorg drivers,
- # obviously, so we use the last driver found on the card section in that case.
- # those come from lscpi kernel drivers so there should be no xorg/wayland issues.
+ # obviously, so we use the driver(s) found in the card section.
+ # Those come from lspci kernel drivers so should be no xorg/wayland issues.
if (!@$x_drivers || !$x_drivers->[0]){
- # Fallback: specific case: in Arch/Manjaro gdm run systems, their Xorg.0.log is
+ # Fallback: specific case: in Arch/Manjaro gdm run systems, Xorg.0.log is
# located inside this directory, which is not readable unless you are root
# Normally Arch gdm log is here: ~/.local/share/xorg/Xorg.1.log
- # $driver comes from the Device lines, and is just last fallback.
if (!$graphics{'protocol'} || $graphics{'protocol'} ne 'wayland'){
- if ($graphics{'gpu-drivers'}){
- if (-e '/var/lib/gdm' && !$b_root){
- $driver_note = main::message('display-driver-na');
- $driver_note .= ' - ' . main::message('root-suggested');
+ # Problem: as root, wayland has no info anyway, including wayland detection.
+ if (-e '/var/lib/gdm' && !$b_root){
+ if ($graphics{'gpu-drivers'}){
+ $driver_note = main::message('display-driver-na-try-root');
}
else {
- $driver_note = main::message('display-driver-na');
+ $driver_note = main::message('root-suggested');
}
}
- elsif (-e '/var/lib/gdm' && !$b_root) {
- $driver_note = main::message('root-suggested');
- }
}
}
- # if xvesa, will always have display-driver set
- if ($graphics{'xvesa'} && $graphics{'display-driver'}){
+ # if TinyX, will always have display-driver set
+ if ($graphics{'tinyx'} && $graphics{'display-driver'}){
$rows->[$j]{main::key($num++,0,2,'driver')} = join(',',@{$graphics{'display-driver'}});
}
else {
my $gpu_drivers = gpu_drivers_sys('all');
my $note_indent = 4;
- if (@$gpu_drivers || $graphics{'dri-drivers'} && @$x_drivers){
+ if (@$gpu_drivers || $graphics{'dri-drivers'} || @$x_drivers){
$rows->[$j]{main::key($num++,1,2,'driver')} = '';
# The only wayland setups with x drivers have xorg, transitional that is.
if (@$x_drivers){
@@ -14554,8 +15188,9 @@ sub display_output(){
$rows->[$j]{main::key($num++,0,2,'default screen')} = $graphics{'display-default-screen'};
}
}
+ # TinyX may pack actual resolution data into no-screens if it was found
if ($graphics{'no-screens'}){
- my $res = (!$show{'graphic-basic'} && $extra > 1 && !$graphics{'xvesa'}) ? 'note' : 'resolution';
+ my $res = (!$show{'graphic-basic'} && $extra > 1 && !$graphics{'tinyx'}) ? 'note' : 'resolution';
$rows->[$j]{main::key($num++,0,2,$res)} = $graphics{'no-screens'};
}
elsif ($graphics{'screens'}){
@@ -14614,7 +15249,7 @@ sub display_output(){
}
else {
monitors_output_full('screen',$main->{'monitors'},
- $j,$rows,\$num);
+ \$j,$rows,\$num);
}
}
elsif (!$show{'graphic-basic'} && $graphics{'no-monitors'}){
@@ -14633,12 +15268,13 @@ sub display_output(){
monitors_output_basic('monitor',$monitor_ids,'',$j,$rows,\$num);
}
else {
- monitors_output_full('monitor',$monitor_ids,$j,$rows,\$num);
+ monitors_output_full('monitor',$monitor_ids,\$j,$rows,\$num);
}
}
}
eval $end if $b_log;
}
+
sub monitors_output_basic {
eval $start if $b_log;
my ($type,$monitors,$s_dpi,$j,$row,$num) = @_;
@@ -14675,7 +15311,8 @@ sub monitors_output_basic {
}
eval $end if $b_log;
}
-# $j, $row, $num passed by ref
+
+# args: $j, $row, $num passed by ref
sub monitors_output_full {
eval $start if $b_log;
my ($type,$monitors,$j,$rows,$num) = @_;
@@ -14683,28 +15320,28 @@ sub monitors_output_full {
my ($m1,$m2,$m3,$m4) = ($type eq 'screen') ? (3,4,5,6) : (2,3,4,5);
# note: in case where mapped id != sys id, the key will not match 'monitor'
foreach my $key (sort keys %{$monitors}){
- $j++;
- $rows->[$j]{main::key($$num++,1,$m1,'Monitor')} = $monitors->{$key}{'monitor'};
+ $$j++;
+ $rows->[$$j]{main::key($$num++,1,$m1,'Monitor')} = $monitors->{$key}{'monitor'};
if ($monitors->{$key}{'monitor-mapped'}){
- $rows->[$j]{main::key($$num++,0,$m2,'mapped')} = $monitors->{$key}{'monitor-mapped'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'mapped')} = $monitors->{$key}{'monitor-mapped'};
}
if ($monitors->{$key}{'disabled'}){
- $rows->[$j]{main::key($$num++,0,$m2,'note')} = $monitors->{$key}{'disabled'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'note')} = $monitors->{$key}{'disabled'};
}
if ($monitors->{$key}{'position'}){
- $rows->[$j]{main::key($$num++,0,$m2,'pos')} = $monitors->{$key}{'position'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'pos')} = $monitors->{$key}{'position'};
}
if ($monitors->{$key}{'model'}){
- $rows->[$j]{main::key($$num++,0,$m2,'model')} = $monitors->{$key}{'model'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'model')} = $monitors->{$key}{'model'};
}
elsif ($monitors->{$key}{'model-id'}){
- $rows->[$j]{main::key($$num++,0,$m2,'model-id')} = $monitors->{$key}{'model-id'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'model-id')} = $monitors->{$key}{'model-id'};
}
if ($extra > 2 && $monitors->{$key}{'serial'}){
- $rows->[$j]{main::key($$num++,0,$m2,'serial')} = main::filter($monitors->{$key}{'serial'});
+ $rows->[$$j]{main::key($$num++,0,$m2,'serial')} = main::filter($monitors->{$key}{'serial'});
}
if ($b_admin && $monitors->{$key}{'build-date'}){
- $rows->[$j]{main::key($$num++,0,$m2,'built')} = $monitors->{$key}{'build-date'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'built')} = $monitors->{$key}{'build-date'};
}
if ($monitors->{$key}{'res-x'} || $monitors->{$key}{'res-y'} ||
$monitors->{$key}{'hz'} || $monitors->{$key}{'size-x'} ||
@@ -14713,7 +15350,7 @@ sub monitors_output_full {
$resolution = $monitors->{$key}{'res-x'} . 'x' . $monitors->{$key}{'res-y'};
}
$resolution ||= 'N/A';
- $rows->[$j]{main::key($$num++,0,$m2,'res')} = $resolution;
+ $rows->[$$j]{main::key($$num++,0,$m2,'res')} = $resolution;
}
else {
if ($b_display){
@@ -14723,50 +15360,50 @@ sub monitors_output_full {
$resolution = main::message('monitor-console');
}
$b_no_size = 1;
- $rows->[$j]{main::key($$num++,0,$m2,'size-res')} = $resolution;
+ $rows->[$$j]{main::key($$num++,0,$m2,'size-res')} = $resolution;
}
if ($extra > 2 && $monitors->{$key}{'hz'}){
- $rows->[$j]{main::key($$num++,0,$m2,'hz')} = $monitors->{$key}{'hz'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'hz')} = $monitors->{$key}{'hz'};
}
if ($monitors->{$key}{'dpi'}){
- $rows->[$j]{main::key($$num++,0,$m2,'dpi')} = $monitors->{$key}{'dpi'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'dpi')} = $monitors->{$key}{'dpi'};
}
if ($b_admin && $monitors->{$key}{'gamma'}){
- $rows->[$j]{main::key($$num++,0,$m2,'gamma')} = $monitors->{$key}{'gamma'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'gamma')} = $monitors->{$key}{'gamma'};
}
if ($show{'edid'} && $monitors->{$key}{'colors'}){
- $rows->[$j]{main::key($$num++,1,$m2,'chroma')} = '';
- $rows->[$j]{main::key($$num++,1,$m3,'red')} = '';
- $rows->[$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'red_x'};
- $rows->[$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'red_y'};
- $rows->[$j]{main::key($$num++,1,$m3,'green')} = '';
- $rows->[$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'green_x'};
- $rows->[$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'green_y'};
- $rows->[$j]{main::key($$num++,1,$m3,'blue')} = '';
- $rows->[$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'blue_x'};
- $rows->[$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'blue_y'};
- $rows->[$j]{main::key($$num++,1,$m3,'white')} = '';
- $rows->[$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'white_x'};
- $rows->[$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'white_y'};
+ $rows->[$$j]{main::key($$num++,1,$m2,'chroma')} = '';
+ $rows->[$$j]{main::key($$num++,1,$m3,'red')} = '';
+ $rows->[$$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'red_x'};
+ $rows->[$$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'red_y'};
+ $rows->[$$j]{main::key($$num++,1,$m3,'green')} = '';
+ $rows->[$$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'green_x'};
+ $rows->[$$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'green_y'};
+ $rows->[$$j]{main::key($$num++,1,$m3,'blue')} = '';
+ $rows->[$$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'blue_x'};
+ $rows->[$$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'blue_y'};
+ $rows->[$$j]{main::key($$num++,1,$m3,'white')} = '';
+ $rows->[$$j]{main::key($$num++,0,$m4,'x')} = $monitors->{$key}{'colors'}{'white_x'};
+ $rows->[$$j]{main::key($$num++,0,$m4,'y')} = $monitors->{$key}{'colors'}{'white_y'};
}
if ($extra > 2 && $monitors->{$key}{'scale'}){
- $rows->[$j]{main::key($$num++,0,$m2,'scale')} = $monitors->{$key}{'scale'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'scale')} = $monitors->{$key}{'scale'};
}
if ($extra > 2 && $monitors->{$key}{'size-x'} && $monitors->{$key}{'size-y'}){
my $size = $monitors->{$key}{'size-x'} . 'x' . $monitors->{$key}{'size-y'} .
'mm ('. $monitors->{$key}{'size-x-i'} . 'x' . $monitors->{$key}{'size-y-i'} . '")';
- $rows->[$j]{main::key($$num++,0,$m2,'size')} = $size;
+ $rows->[$$j]{main::key($$num++,0,$m2,'size')} = $size;
}
if ($monitors->{$key}{'diagonal'}){
my $diag = $monitors->{$key}{'diagonal-m'} . 'mm ('. $monitors->{$key}{'diagonal'} . '")';
- $rows->[$j]{main::key($$num++,0,$m2,'diag')} = $diag;
+ $rows->[$$j]{main::key($$num++,0,$m2,'diag')} = $diag;
}
elsif ($b_display && !$b_no_size && !$monitors->{$key}{'size-x'} &&
!$monitors->{$key}{'size-y'}){
- $rows->[$j]{main::key($$num++,0,$m2,'size')} = main::message('monitor-na');;
+ $rows->[$$j]{main::key($$num++,0,$m2,'size')} = main::message('monitor-na');;
}
if ($b_admin && $monitors->{$key}{'ratio'}){
- $rows->[$j]{main::key($$num++,0,$m2,'ratio')} = $monitors->{$key}{'ratio'};
+ $rows->[$$j]{main::key($$num++,0,$m2,'ratio')} = $monitors->{$key}{'ratio'};
}
if ($extra > 2){
if (!$monitors->{$key}{'modes'} || !@{$monitors->{$key}{'modes'}}){
@@ -14774,30 +15411,30 @@ sub monitors_output_full {
}
my $cnt = scalar @{$monitors->{$key}{'modes'}};
if ($cnt == 1 || ($cnt > 2 && $show{'edid'})){
- $rows->[$j]{main::key($$num++,0,$m2,'modes')} = join(', ', @{$monitors->{$key}{'modes'}});
+ $rows->[$$j]{main::key($$num++,0,$m2,'modes')} = join(', ', @{$monitors->{$key}{'modes'}});
}
else {
- $rows->[$j]{main::key($$num++,1,$m2,'modes')} = '';
- $rows->[$j]{main::key($$num++,0,$m3,'max')} = ${$monitors->{$key}{'modes'}}[0];
- $rows->[$j]{main::key($$num++,0,$m3,'min')} = ${$monitors->{$key}{'modes'}}[-1];
+ $rows->[$$j]{main::key($$num++,1,$m2,'modes')} = '';
+ $rows->[$$j]{main::key($$num++,0,$m3,'max')} = ${$monitors->{$key}{'modes'}}[0];
+ $rows->[$$j]{main::key($$num++,0,$m3,'min')} = ${$monitors->{$key}{'modes'}}[-1];
}
}
if ($show{'edid'}){
if ($monitors->{$key}{'edid-errors'}){
- $j++;
+ $$j++;
my $cnt = 1;
- $rows->[$j]{main::key($$num++,1,$m2,'EDID-Errors')} = '';
+ $rows->[$$j]{main::key($$num++,1,$m2,'EDID-Errors')} = '';
foreach my $err (@{$monitors->{$key}{'edid-errors'}}){
- $rows->[$j]{main::key($$num++,0,$m3,$cnt)} = $err;
+ $rows->[$$j]{main::key($$num++,0,$m3,$cnt)} = $err;
$cnt++;
}
}
if ($monitors->{$key}{'edid-warnings'}){
- $j++;
+ $$j++;
my $cnt = 1;
- $rows->[$j]{main::key($$num++,1,$m2,'EDID-Warnings')} = '';
+ $rows->[$$j]{main::key($$num++,1,$m2,'EDID-Warnings')} = '';
foreach my $warn (@{$monitors->{$key}{'edid-warnings'}}){
- $rows->[$j]{main::key($$num++,0,$m3,$cnt)} = $warn;
+ $rows->[$$j]{main::key($$num++,0,$m3,$cnt)} = $warn;
$cnt++;
}
}
@@ -14812,202 +15449,375 @@ sub monitors_output_full {
eval $end if $b_log;
}
-## DISPLAY API OUTPUT ##
-# as soon as EGL data source for Wayland appears add it!
-sub display_api_output {
+## DISPLAY API ##
+
+# API Output #
+
+# GLX/OpenGL EGL Vulkan XVesa
+sub display_api {
eval $start if $b_log;
my $rows = $_[0];
- my $num = 0;
- my ($api,$program,$type);
# print ("$b_display : $b_root\n");
# xvesa is absolute, if it's there, it works in or out of display
if ($graphics{'xvesa'}){
- xvesa_output($rows,\$num);
+ xvesa_output($rows);
+ return;
}
- else {
+ my ($b_egl,$b_egl_print,$b_glx,$b_glx_print,$b_vulkan,$api,$program,$type);
+ my $gl = {};
+ if ($fake{'egl'} || ($program = main::check_program('eglinfo'))){
+ gl_data('egl',$program,$rows,$gl);
+ $b_egl = 1;
+ }
+ if ($fake{'glx'} || ($program = main::check_program('glxinfo'))){
+ gl_data('glx',$program,$rows,$gl) if $b_display;
+ $b_glx = 1;
+ }
+ # Note: we let gl/egl output handle null or root null data issues
+ if ($gl->{'glx'}){
+ process_glx_data($gl->{'glx'},$b_glx);
+ }
+ # egl/vulkan give data out of display, and for root
+ # if ($b_egl}){
+ if ($b_egl && ($show{'graphic-full'} || !$gl->{'glx'})){
+ egl_output($rows,$gl);
+ $b_egl_print = 1;
+ }
+ # fill in whatever was missing from eglinfo, or if legacy system/no eglinfo
+ # if ($b_glx || $gl->{'glx'}){
+ if (($show{'graphic-full'} && ($b_glx || $gl->{'glx'})) ||
+ (!$show{'graphic-full'} && !$b_egl_print && ($b_glx || $gl->{'glx'}))){
+ opengl_output($rows,$gl);
+ $b_glx = 1;
+ $b_glx_print = 1;
+ }
+ # if ($fake{'vulkan'} || ($program = main::check_program('vulkaninfo'))){
+ if (($fake{'vulkan'} || ($program = main::check_program('vulkaninfo'))) &&
+ ($show{'graphic-full'} || (!$b_egl_print && !$b_glx_print))){
+ vulkan_output($program,$rows);
+ $b_vulkan = 1;
+ }
+ if ($show{'graphic-full'} || (!$b_egl_print && !$b_glx_print)){
+ # remember, sudo/root usually has empty $DISPLAY as well
if ($b_display){
- if (!$force{'wayland'} && ($program = main::check_program('glxinfo'))){
- opengl_output($program,$rows,\$num);
+ # first do positive tests, won't be set for sudo/root
+ if (!$b_glx && $graphics{'protocol'} eq 'x11'){
+ $api = 'OpenGL';
+ $type = 'glx-missing';
}
- # handles no data until we find one for wayland egl data
- elsif ($graphics{'protocol'} eq 'wayland'){
- egl_output($rows,\$num);
+ elsif (!$b_egl && $graphics{'protocol'} eq 'wayland'){
+ $api = 'EGL'; # /GBM
+ $type = 'egl-missing';
}
- else {
- if (main::check_program('X') || main::check_program('Xorg')){
- $api = 'OpenGL';
- $type = 'glxinfo-missing';
- }
- # has to come after X tests, since X can have Xwayland installed.
- elsif (main::check_program('Xwayland')){
- $api = 'EGL/GBM';
- $type = 'egl-wayland';
- }
- else {
- $api = 'N/A';
- $type = 'gfx-api';
- }
- push(@$rows,{
- main::key($num++,1,1,'API') => $api,
- main::key($num++,0,2,'Message') => main::message($type)
- });
+ elsif (!$b_glx &&
+ (main::check_program('X') || main::check_program('Xorg'))){
+ $api = 'OpenGL';
+ $type = 'glx-missing';
}
- }
- else {
- if ($graphics{'protocol'} eq 'wayland'){
- $api = 'EGL/GBM';
- $type = 'egl-wayland-console';
+ elsif (!$b_egl && main::check_program('Xwayland')){
+ $api = 'EGL';
+ $type = 'egl-missing';
}
- elsif (main::check_program('glxinfo')){
- $api = 'OpenGL';
- $type = ($b_root) ? 'gl-console-root' : 'gl-console-try';
+ elsif (!$b_egl && !$b_glx && !$b_vulkan) {
+ $api = 'N/A';
+ $type = 'gfx-api';
}
- elsif (main::check_program('X') || main::check_program('Xorg')){
+ }
+ else {
+ if (!$b_glx &&
+ (main::check_program('X') || main::check_program('Xorg'))){
$api = 'OpenGL';
- $type = 'gl-console-glxinfo-missing';
+ $type = 'glx-missing-console';
}
- # has to come after X tests, since X can have Xwayland installed.
- elsif (main::check_program('Xwayland')){
- $api = 'EGL/GBM';
- $type = 'egl-wayland-console';
+ elsif (!$b_egl && main::check_program('Xwayland')){
+ $api = 'EGL';
+ $type = 'egl-missing-console';
}
# we don't know what it is, headless system, non xwayland wayland
- else {
+ elsif (!$b_egl && !$b_glx && !$b_vulkan) {
$api = 'N/A';
$type = 'gfx-api-console';
}
- push(@$rows,{
- main::key($num++,1,1,'API') => $api,
- main::key($num++,0,2,'Message') => main::message($type)
- });
}
+ no_data_output($api,$type,$rows) if $type;
}
eval $end if $b_log;
}
-sub egl_output {
+
+sub no_data_output {
eval $start if $b_log;
- my ($rows,$num) = @_;
- push(@$rows,{
- main::key($num++,1,1,'API') => 'EGL/GBM',
- main::key($num++,0,2,'Message') => main::message('egl-wayland')
+ my ($api,$type,$rows) = @_;
+ my $num = 0;
+ push(@$rows, {
+ main::key($num++,1,1,'API') => $api,
+ main::key($num++,0,2,'Message') => main::message($type)
});
eval $end if $b_log;
}
-sub opengl_output {
+
+sub egl_output {
eval $start if $b_log;
- my ($program,$rows,$num) = @_;
- # NOTE: glxinfo -B is not always available, unfortunately
- my $glxinfo = main::grabber("$program $display_opt 2>/dev/null",'','','ref');
- # my $file = "$fake_data_dir/graphics/glxinfo/glxinfo-ssh-centos.txt";
- # my @glxinfo = main::reader($file);
- if (!@$glxinfo){
- my $type;
- if ($b_root){
- $type = 'gl-display-root';
+ my ($rows,$gl) = @_;
+ if (!$gl->{'egl'}){
+ my $api = 'EGL';
+ my $type = 'egl-null';
+ no_data_output($api,$type,$rows);
+ return 0;
+ }
+ my ($i,$j,$num) = (0,scalar @$rows,0);
+ my ($value);
+ my $ref;
+ my $data = $gl->{'egl'}{'data'};
+ my $plat = $gl->{'egl'}{'platforms'};
+ push(@$rows, {
+ main::key($num++,1,1,'API') => 'EGL',
+ });
+ if ($extra < 2){
+ $value = ($data->{'versions'}) ? join(',',sort keys %{$data->{'versions'}}): 'N/A';
+ }
+ else {
+ $value = ($data->{'version'}) ? $data->{'version'}: 'N/A';
+ }
+ $rows->[$j]{main::key($num++,0,2,'v')} = $value;
+ if ($extra < 2){
+ $value = ($data->{'drivers'}) ? join(',',sort keys %{$data->{'drivers'}}): 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'drivers')} = $value;
+ $value = ($data->{'platforms'}{'active'}) ? join(',',@{$data->{'platforms'}{'active'}}) : 'N/A';
+ if ($extra < 1){
+ $rows->[$j]{main::key($num++,0,2,'platforms')} = $value;
}
else {
- $type = 'gl-null';
+ $rows->[$j]{main::key($num++,1,2,'platforms')} = '';
+ $rows->[$j]{main::key($num++,0,3,'active')} = $value;
+ $value = ($data->{'platforms'}{'inactive'}) ? join(',',@{$data->{'platforms'}{'inactive'}}) : 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'inactive')} = $value;
}
- push(@$rows, {
- main::key($$num++,1,1,'API') => 'OpenGL',
- main::key($$num++,0,2,'Message') => main::message($type)
- });
- return;
}
- # print join("\n", @$glxinfo),"\n";
- my $compat_version = '';
- my ($b_compat,$b_nogl,@core_profile_version,@direct_render,@renderer,
- @opengl_version,@working);
- foreach (@$glxinfo){
- next if /^\s/;
- if (/^opengl renderer/i){
- @working = split(/:\s*/, $_, 2);
- if ($working[1]){
- $working[1] = main::clean($working[1]);
+ else {
+ if ($extra > 2 && $data->{'hw'}){
+ $i = 0;
+ $rows->[$j]{main::key($num++,1,2,'hw')} = '';
+ foreach my $key (sort keys %{$data->{'hw'}}){
+ $value = ($key ne $data->{'hw'}{$key}) ? $data->{'hw'}{$key} . ' ' . $key: $key;
+ $rows->[$j]{main::key($num++,0,3,'drv')} = $value;
+ }
+ }
+ $rows->[$j]{main::key($num++,1,2,'platforms')} = '';
+ $data->{'version'} ||= 0;
+ $i = 0;
+ foreach my $key (sort keys %$plat){
+ next if !$plat->{$key}{'status'} || $plat->{$key}{'status'} eq 'inactive';
+ if ($key eq 'device'){
+ foreach my $id (sort keys %{$plat->{$key}}){
+ next if ref $plat->{$key}{$id} ne 'HASH';
+ $rows->[$j]{main::key($num++,1,3,$key)} = $id;
+ $ref = $plat->{$key}{$id}{'egl'};
+ egl_advanced_output($rows,$ref,\$num,$j,4,$data->{'version'});
+ }
}
- # note: seen cases where gl drivers are missing, with empty field value.
else {
- $b_nogl = 1;
- $working[1] = main::message('gl-value-empty');
+ $rows->[$j]{main::key($num++,1,3,$key)} = '';
+ $ref = $plat->{$key}{'egl'};
+ egl_advanced_output($rows,$ref,\$num,$j,4,$data->{'version'});
}
- push(@renderer, $working[1]);
}
- # dropping all conditions from this test to just show full mesa information
- # there is a user case where not f and mesa apply, atom mobo
- # /opengl version/ && ( f || $2 !~ /mesa/){
- elsif (/^opengl version/i){
- @working = split(/:\s*/, $_, 2);
- if ($working[1]){
- # fglrx started appearing with this extra string, does not appear
- # to communicate anything of value
- $working[1] =~ s/(Compatibility Profile Context|\(Compatibility Profile\))//;
- $working[1] =~ s/\s\s/ /g;
- $working[1] =~ s/^\s+|\s+$//;
- push(@opengl_version, $working[1]);
- # note: this is going to be off if ever multi opengl versions appear,
- # never seen one
- @working = split(/\s+/, $working[1]);
- $compat_version = $working[0];
- }
- elsif (!$b_nogl){
- push(@opengl_version, main::message('gl-value-empty'));
- }
- }
- elsif (/^opengl core profile version/i){
- @working = split(/:\s*/, $_, 2);
- # note: no need to apply empty message here since we don't have the data
- # anyway
- if ($working[1]){
- # fglrx started appearing with this extra string, does not appear
- # to communicate anything of value
- $working[1] =~ s/(Compatibility Profile Context|\((Compatibility|Core) Profile\))//;
- $working[1] =~ s/\s\s/ /g;
- $working[1] =~ s/^\s+|\s+$//;
- push(@core_profile_version, $working[1]);
- }
+ if (!$data->{'platforms'}{'active'}){
+ $rows->[$j]{main::key($num++,0,3,'active')} = 'N/A';
}
- elsif (/direct rendering/){
- @working = split(/:\s*/, $_, 2);
- push(@direct_render, $working[1]);
+ if ($data->{'platforms'}{'inactive'}){
+ $rows->[$j]{main::key($num++,0,3,'inactive')} = join(',',@{$data->{'platforms'}{'inactive'}});
}
- # if -B was always available, we could skip this, but it is not
- elsif (/GLX Visuals/){
- last;
+ }
+ eval $end if $b_log;
+}
+
+# args: 0: $rows; 1: data ref; 2: \$num; 3: $j; 4: indent; 5: $b_plat_v
+sub egl_advanced_output {
+ my ($rows,$ref,$num,$j,$ind,$version) = @_;
+ my $value;
+ # version is set to 0 for math
+ if ($version && (!$ref->{'version'} || $version != $ref->{'version'})){
+ $value = ($ref->{'version'}) ? $ref->{'version'} : 'N/A';
+ $rows->[$j]{main::key($$num++,0,$ind,'egl')} = $value;
+ undef $value;
+ }
+ if ($ref->{'driver'}){
+ $value = $ref->{'driver'};
+ }
+ else {
+ if ($ref->{'vendor'} && $ref->{'vendor'} ne 'mesa'){
+ $value = $ref->{'vendor'};
}
+ $value ||= 'N/A';
}
- my ($direct_render,$renderer,$version) = ('N/A','N/A','N/A');
- $direct_render = join(', ', @direct_render) if @direct_render;
- # non free drivers once filtered and cleaned show the same for core and compat
- # but this stopped for some reason at 4.5/4.6 nvidia
- if (@core_profile_version && @opengl_version &&
- join('', @core_profile_version) ne join('', @opengl_version) &&
- !(grep {/nvidia/i} @opengl_version)){
- @opengl_version = @core_profile_version;
- $b_compat = 1;
+ $rows->[$j]{main::key($$num++,0,$ind,'drv')} = $value;
+}
+
+sub opengl_output {
+ eval $start if $b_log;
+ my ($rows,$gl) = @_;
+ # egl will have set $glx if present
+ if (!$gl->{'glx'}){
+ my $api = 'OpenGL';
+ my $type;
+ if ($b_display){
+ $type = ($b_root) ? 'glx-display-root': 'glx-null';
+ }
+ else {
+ $type = ($b_root) ? 'glx-console-root' : 'glx-console-try';
+ }
+ no_data_output($api,$type,$rows);
+ return 0;
}
- $version = join(', ', @opengl_version) if @opengl_version;
- $renderer = join(', ', @renderer) if @renderer;
- my $j = scalar @$rows;
+ my ($j,$num) = (scalar @$rows,0);
+ my $value;
+ # print join("\n", %$gl),"\n";
+ my $glx = $gl->{'glx'};
+ $glx->{'opengl'}{'version'} ||= 'N/A';
push(@$rows, {
- main::key($$num++,1,1,'API') => 'OpenGL',
- main::key($$num++,0,2,'v') => ($version) ? $version : 'N/A',
- main::key($$num++,1,2,'renderer') => ($renderer) ? $renderer : 'N/A',
+ main::key($num++,1,1,'API') => 'OpenGL',
+ main::key($num++,0,2,'v') => $glx->{'opengl'}{'version'},
+ });
+ if ($glx->{'opengl'}{'compatibility'}{'version'}){
+ $rows->[$j]{main::key($num++,0,2,'compat-v')} = $glx->{'opengl'}{'compatibility'}{'version'};
+ }
+ if ($glx->{'opengl'}{'vendor'}){
+ $rows->[$j]{main::key($num++,1,2,'vendor')} = $glx->{'opengl'}{'vendor'};
+ $glx->{'opengl'}{'driver'}{'version'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'v')} = $glx->{'opengl'}{'driver'}{'version'};
+ }
+ if ($extra > 0 && $glx->{'glx-version'}){
+ $rows->[$j]{main::key($num++,0,2,'glx-v')} = $glx->{'glx-version'};
+ }
+ if ($extra > 1 && $glx->{'es'}{'version'}){
+ $rows->[$j]{main::key($num++,0,2,'es-v')} = $glx->{'es'}{'version'};;
+ }
+ if ($glx->{'note'}){
+ $rows->[$j]{main::key($num++,0,2,'note')} = $glx->{'note'};
+ }
+ if ($extra > 0 && (!$glx->{'note'} || $glx->{'direct-render'})){
+ $glx->{'direct-render'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'direct-render')} = $glx->{'direct-render'};
+ }
+ if (!$glx->{'note'} || $glx->{'opengl'}{'renderer'}){
+ $glx->{'opengl'}{'renderer'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'renderer')} = $glx->{'opengl'}{'renderer'};
+ }
+ if ($extra > 1 && $glx->{'info'}){
+ if ($glx->{'info'}{'vendor-id'} && $glx->{'info'}{'device-id'}){
+ $value = $glx->{'info'}{'vendor-id'} . ':' . $glx->{'info'}{'device-id'};
+ $rows->[$j]{main::key($num++,0,2,'device-ID')} = $value;
+ }
+ if ($b_admin && $glx->{'info'}{'device-memory'}){
+ $rows->[$j]{main::key($num++,1,2,'memory')} = $glx->{'info'}{'device-memory'};
+ if ($glx->{'info'}{'unified-memory'}){
+ $rows->[$j]{main::key($num++,0,3,'unified')} = $glx->{'info'}{'unified-memory'};
+ }
+ }
+ # display id depends on xdpyinfo in Display line, which may not be present,
+ if (!$graphics{'display-id'} && $glx->{'display-id'} && $extra > 1){
+ $rows->[$j]{main::key($num++,0,2,'display-ID')} = $glx->{'display-id'};
+ }
+ }
+ eval $end if $b_log;
+}
+
+sub vulkan_output {
+ eval $start if $b_log;
+ my ($program,$rows) = @_;
+ my $vulkan = {};
+ vulkan_data($program,$vulkan);
+ if (!%$vulkan){
+ my $api = 'Vulkan';
+ my $type = 'vulkan-null';
+ no_data_output($api,$type,$rows);
+ return 0;
+ }
+ my $num = 0;
+ my $j = scalar @$rows;
+ my ($value);
+ my $data = $vulkan->{'data'};
+ my $devices = $vulkan->{'devices'};
+ $data->{'version'} ||= 'N/A';
+ push(@$rows,{
+ main::key($num++,1,1,'API') => 'Vulkan',
+ main::key($num++,0,2,'v') => $data->{'version'},
});
- if ($b_compat && $extra > 1 && $compat_version){
- $rows->[$j]{main::key($$num++,0,2,'compat-v')} = $compat_version;
+ # this will be expanded with -a to a full device report
+ if ($extra < 2){
+ $value = ($data->{'drivers'}) ? join(',',@{$data->{'drivers'}}): 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'drivers')} = $value;
+ }
+ if ($extra > 2){
+ $data->{'layers'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'layers')} = $data->{'layers'};
+ }
+ if (!$b_admin){
+ $value = ($data->{'surfaces'}) ? join(',',@{$data->{'surfaces'}}) : 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'surfaces')} = $value;
}
if ($extra > 0){
- $rows->[$j]{main::key($$num++,0,2,'direct render')} = $direct_render;
+ if (!$devices){
+ $rows->[$j]{main::key($num++,0,2,'devices')} = 'N/A';
+ }
+ else {
+ if ($extra < 2){
+ $value = scalar keys %{$devices};
+ $rows->[$j]{main::key($num++,0,2,'devices')} = $value;
+ }
+ else {
+ foreach my $id (sort keys %$devices){
+ $rows->[$j]{main::key($num++,1,2,'device')} = $id;
+ $devices->{$id}{'device-type'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'type')} = $devices->{$id}{'device-type'};
+ if ((($extra == 3 && !$b_admin) ||
+ ($extra > 2 && !$devices->{$id}{'device-name'})) &&
+ $devices->{$id}{'hw'} && $devices->{$id}{'hw'} ne 'nvidia'){
+ $rows->[$j]{main::key($num++,0,3,'hw')} = $devices->{$id}{'hw'};
+ }
+ if ($b_admin){
+ $value = ($devices->{$id}{'device-name'}) ?
+ $devices->{$id}{'device-name'}: 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'name')} = $value;
+ }
+ if ($extra > 1){
+ if ($devices->{$id}{'driver-name'}){
+ $value = $devices->{$id}{'driver-name'};
+ if ($devices->{$id}{'mesa'} && $value ne 'mesa'){
+ $value = 'mesa ' . $value;
+ }
+ $rows->[$j]{main::key($num++,1,3,'driver')} = $value;
+ if ($b_admin && $devices->{$id}{'driver-info'}){
+ $rows->[$j]{main::key($num++,0,4,'v')} = $devices->{$id}{'driver-info'};
+ }
+ }
+ else {
+ $rows->[$j]{main::key($num++,0,3,'driver')} = 'N/A';
+ }
+ $value = ($devices->{$id}{'device-id'} && $devices->{$id}{'vendor-id'}) ?
+ $devices->{$id}{'vendor-id'} . ':' . $devices->{$id}{'device-id'} : 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'device-ID')} = $value;
+ if ($b_admin){
+ $value = ($devices->{$id}{'surfaces'}) ?
+ join(',',@{$devices->{$id}{'surfaces'}}): 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'surfaces')} = $value;
+ }
+ }
+ }
+ }
+ }
}
eval $end if $b_log;
}
+
sub xvesa_output {
eval $start if $b_log;
- my ($rows,$num) = @_;
+ my ($rows) = @_;
my ($controller,$dac,$interface,$ram,$source,$version);
# note: goes to stderr, not stdout
my @data = main::grabber($graphics{'xvesa'} . ' -listmodes 2>&1');
my $j = scalar @$rows;
+ my $num = 0;
# gop replaced uga, both for uefi
# WARNING! Never seen a GOP type UEFI, needs more data
if ($data[0] && $data[0] =~ /^(VBE|GOP|UGA)\s+version\s+(\S+)\s\(([^)]+)\)/i){
@@ -15024,24 +15834,711 @@ sub xvesa_output {
$ram = main::get_size($ram,'string');
}
if (!$interface){
- $rows->[$j]{main::key($$num++,1,1,'API')} = 'VBE/GOP';
- $rows->[$j]{main::key($$num++,0,2,'Message')} = main::message('gfx-api-xvesa');
+ $rows->[$j]{main::key($num++,1,1,'API')} = 'VBE/GOP';
+ $rows->[$j]{main::key($num++,0,2,'Message')} = main::message('xvesa-null');
}
else {
- $rows->[$j]{main::key($$num++,1,1,'API')} = $interface;
- $rows->[$j]{main::key($$num++,0,2,'v')} = ($version) ? $version : 'N/A';
- $rows->[$j]{main::key($$num++,0,2,'source')} = ($source) ? $source : 'N/A';
+ $rows->[$j]{main::key($num++,1,1,'API')} = $interface;
+ $rows->[$j]{main::key($num++,0,2,'v')} = ($version) ? $version : 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'source')} = ($source) ? $source : 'N/A';
if ($dac){
- $rows->[$j]{main::key($$num++,0,2,'dac')} = $dac;
- $rows->[$j]{main::key($$num++,0,2,'controller')} = $controller;
+ $rows->[$j]{main::key($num++,0,2,'dac')} = $dac;
+ $rows->[$j]{main::key($num++,0,2,'controller')} = $controller;
}
if ($ram){
- $rows->[$j]{main::key($$num++,0,2,'ram')} = $ram;
+ $rows->[$j]{main::key($num++,0,2,'ram')} = $ram;
}
}
eval $end if $b_log;
}
+# API Data #
+sub gl_data {
+ eval $start if $b_log;
+ my ($source,$program,$rows,$gl) = @_;
+ my ($b_opengl,$msg);
+ my ($gl_data,$results) = ([],[]);
+ # only check these if no eglinfo or eglinfo had no opengl data
+ $b_opengl = 1 if ($source eq 'egl' || !$gl->{'glx'});
+ # NOTE: glxinfo -B is not always available, unfortunately
+ if ($dbg[56] || $b_log){
+ $msg = "${line1}GL Source: $source\n${line3}";
+ print $msg if $dbg[56];
+ push(@$results,$msg) if $b_log;
+ }
+ if ($source eq 'glx'){
+ if (!$fake{'glx'}){
+ $gl_data = main::grabber("$program $display_opt 2>/dev/null",'','','ref');
+ }
+ else {
+ my $file;
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-2012-nvidia-glx1.4.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-ssh-centos.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxiinfo-t420-intel-1.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-mali-allwinner-lima-1.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-partial-intel-5500-1.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-vbox-debian-etch-1.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-x11-neomagic-lenny-1.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-nvidia-gl4.6-chr.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-intel-atom-dell_studio-bm.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-asus_1025c-atom-bm.txt";
+ # $file = "$fake_data_dir/graphics/glxinfo/glxinfo-2011-nvidia-glx1.4.txt";
+ $gl_data= main::reader($file,'','ref');
+ }
+ }
+ else {
+ if (!$fake{'egl'}){
+ $gl_data = main::grabber("$program 2>/dev/null",'','','ref');
+ }
+ else {
+ my $file;
+ # $file = "$fake_data_dir/graphics/egl-es/eglinfo-x11-3.txt";
+ # $file = "$fake_data_dir/graphics/egl-es/eglinfo-wayland-intel-c30.txt";
+ # $file = "$fake_data_dir/grapOhics/egl-es/eglinfo-2022-x11-nvidia-egl1.5.txt";
+ # $file = "$fake_data_dir/graphics/egl-es/eglinfo-wayland-intel-nvidia-radu.txt";
+ # $file = "$fake_data_dir/graphics/egl-es/eglinfo-intel-atom-dell_studio-bm.txt";
+ # $file = "$fake_data_dir/graphics/egl-es/eglinfo-asus_1025c-atom-bm.txt";
+ # $file = "$fake_data_dir/graphics/egl-es/eglinfo-x11-amd-raphael-1.txt";
+ $file = "$fake_data_dir/graphics/egl-es/eglinfo-x11-vm-version-odd.txt";
+ $gl_data = main::reader($file,'','ref');
+ }
+ }
+ # print join("\n", @$gl_data),"\n";
+ if (!$gl_data || !@$gl_data){
+ if ($dbg[56] || $b_log){
+ $msg = "No data found for GL Source: $source" if $dbg[56];
+ print "$msg\n" if $dbg[56];
+ push(@$results,$msg) if $b_log;
+ }
+ return 0;
+ }
+ # some error cases have only a few top value but not empty
+ elsif ($source eq 'glx' && scalar @$gl_data > 5){
+ $gl->{'glx'}{'source'} = $source;
+ }
+ set_mesa_drivers() if $source eq 'egl' && !%mesa_drivers;
+ my ($b_device,$b_platform,$b_mem_info,$b_rend_info,$device,$platform,
+ $value,$value2,@working);
+ foreach my $line (@$gl_data){
+ next if (!$b_rend_info && !$b_mem_info) && $line =~ /^(\s|0x)/;
+ if (($b_rend_info || $b_mem_info) && $line =~ /^\S/){
+ ($b_mem_info,$b_rend_info) = ();
+ }
+ @working = split(/\s*:\s*/,$line,2);
+ next if !@working;
+ if ($dbg[56] || $b_log){
+ $msg = $line;
+ print "$msg\n" if $dbg[56];
+ push(@$results,$msg) if $b_log;
+ }
+ if ($source eq 'egl'){
+ # eglinfo: eglInitialize failed
+ # This is first line after platform fail for devices, but for Device
+ # it would be the second or later line. The Device platform can fail, or
+ # specific device can fail
+ if ($b_platform){
+ $value = ($line =~ /Initialize failed/) ? 'inactive': 'active';
+ push(@{$gl->{'egl'}{'data'}{'platforms'}{$value}},$platform);
+ $gl->{'egl'}{'platforms'}{$platform}{'status'} = $value;
+ $b_platform = 0;
+ }
+ # note: can be sub item: Platform Device platform:; Platform Device:
+ elsif ($working[0] =~ /^(\S+) platform/i){
+ $platform = lc($1);
+ undef $device;
+ $b_platform = 1;
+ }
+ if ($platform && defined $device && $working[0] eq 'eglinfo'){
+ push(@{$gl->{'egl'}{'data'}{'platforms'}{'inactive'}},"$platform-$device");
+ undef $device;
+ }
+ if ($platform && $platform eq 'device' && $working[0] =~ /^Device #(\d+)/){
+ $device = $1;
+ }
+ if ($working[0] eq 'EGL API version'){
+ if (!defined $platform){
+ $gl->{'egl'}{'data'}{'api-version'} = $working[1];
+ }
+ elsif (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'api-version'} = $working[1];
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'api-version'} = $working[1];
+ }
+ }
+ elsif ($working[0] eq 'EGL version string'){
+ # seen case of: 1.4 (DRI2)
+ $working[1] =~ s/^([\d\.]+)(\s.*)?/$1/;
+ if (!defined $platform){
+ $gl->{'egl'}{'data'}{'version'} = $working[1];
+ }
+ elsif (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'version'} = $working[1];
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'version'} = $working[1];
+ }
+ $value = (defined $device) ? "$platform-$device": $platform;
+ push(@{$gl->{'egl'}{'data'}{'versions'}{$working[1]}},$value);
+ if (!$gl->{'egl'}{'data'}{'version'} ||
+ $working[1] > $gl->{'egl'}{'data'}{'version'}){
+ $gl->{'egl'}{'data'}{'version'} = $working[1];
+ }
+ }
+ elsif ($working[0] eq 'EGL vendor string'){
+ $working[1] = lc($working[1]);
+ $working[1] =~ s/^(\S+)(\s.+|$)/$1/;
+ if (!defined $platform){
+ $gl->{'egl'}{'data'}{'vendor'} = $working[1];
+ }
+ elsif (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'vendor'} = $working[1];
+ if ($working[1] eq 'nvidia'){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'driver'} = $working[1];
+ }
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'vendor'} = $working[1];
+ if ($working[1] eq 'nvidia'){
+ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'driver'} = $working[1];
+ }
+ }
+ push(@{$gl->{'egl'}{'data'}{'vendors'}},$working[1]);
+ if ($platform && $working[1] eq 'nvidia'){
+ $value = (defined $device) ? "$platform-$device": $platform;
+ push(@{$gl->{'egl'}{'data'}{'drivers'}{$working[1]}},$value);
+ $gl->{'egl'}{'data'}{'hw'}{$working[1]} = $working[1];
+ }
+ }
+ elsif ($platform && $working[0] eq 'EGL driver name'){
+ if (!defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'driver'} = $working[1];
+ if ($mesa_drivers{$working[1]}){
+ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'hw'} = $mesa_drivers{$working[1]};
+ }
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'driver'} = $working[1];
+ if ($mesa_drivers{$working[1]}){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'hw'} = $mesa_drivers{$working[1]};
+ }
+ }
+ $value = (defined $device) ? "$platform-$device": $platform;
+ push(@{$gl->{'egl'}{'data'}{'drivers'}{$working[1]}},$value);
+ if ($mesa_drivers{$working[1]}){
+ $gl->{'egl'}{'data'}{'hw'}{$working[1]} = $mesa_drivers{$working[1]};
+ }
+ }
+ if ($platform && $working[0] eq 'EGL client APIs'){
+ if (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'client-apis'} = [split(/\s+/,$working[1])];
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'client-apis'} = [split(/\s+/,$working[1])];
+ }
+ }
+ }
+ # glx specific values, only found in glxinfo
+ else {
+ if (lc($working[0]) eq 'direct rendering'){
+ $working[1] = lc($working[1]);
+ if (!$gl->{'glx'}{'direct-renderers'} ||
+ !(grep {$_ eq $working[1]} @{$gl->{'glx'}{'direct-renders'}})){
+ push(@{$gl->{'glx'}{'direct-renders'}}, $working[1]);
+ }
+ }
+ # name of display: does not always list the screen number
+ elsif (lc($working[0]) eq 'display'){
+ if ($working[1] =~ /^(:\d+)\s+screen:\s+(\d+)/){
+ $gl->{'glx'}{'display-id'} = $1 . '.' . $2;
+ }
+ }
+ elsif (lc($working[0]) eq 'glx version'){
+ if (!$gl->{'glx'}{'glx-version'}){
+ $gl->{'glx'}{'glx-version'} = $working[1];
+ }
+ }
+ elsif (!$b_rend_info && $working[0] =~ /^Extended renderer info/i){
+ $b_rend_info = 1;
+ }
+ # only check Memory info if no prior device memory found
+ elsif (!$b_mem_info && $working[0] =~ /^Memory info/i){
+ $b_mem_info = (!$gl->{'glx'}{'info'} || !$gl->{'glx'}{'info'}{'device-memory'}) ? 1 : 0;
+ }
+ elsif ($b_rend_info){
+ if ($line =~ /^\s+Vendor:\s+.*?\(0x([\da-f]+)\)$/){
+ $gl->{'glx'}{'info'}{'vendor-id'} = sprintf("%04s",$1);
+ }
+ elsif ($line =~ /^\s+Device:\s+.*?\(0x([\da-f]+)\)$/){
+ $gl->{'glx'}{'info'}{'device-id'} = sprintf("%04s",$1);
+ }
+ elsif ($line =~ /^\s+Video memory:\s+(\d+\s?[MG]B)$/){
+ my $size = main::translate_size($1);
+ $gl->{'glx'}{'info'}{'device-memory'} = main::get_size($size,'string');
+ }
+ elsif ($line =~ /^\s+Unified memory:\s+(\S+)$/){
+ $gl->{'glx'}{'info'}{'unified-memory'} = lc($1);
+ }
+ }
+ elsif ($b_mem_info){
+ # fallback, nvidia does not seem to have Extended renderer info
+ if ($line =~ /^\s+Dedicated video memory:\s+(\d+\s?[MG]B)$/){
+ my $size = main::translate_size($1);
+ $gl->{'glx'}{'info'}{'device-memory'} = main::get_size($size,'string');
+ $b_mem_info = 0;
+ }
+ # we're in the wrong memory block!
+ elsif ($line =~ /^\s+(VBO|Texture)/){
+ $b_mem_info = 0;
+ }
+ }
+ elsif (lc($working[0]) eq 'opengl vendor string'){
+ if ($working[1] =~ /^([^\s]+)(\s+\S+)?/){
+ my $vendor = lc($1);
+ $vendor =~ s/(^mesa\/|[\.,]$)//; # Seen Mesa/X.org
+ if (!$gl->{'glx'}{'opengl'}{'vendor'}){
+ $gl->{'glx'}{'opengl'}{'vendor'} = $vendor;
+ }
+ }
+ }
+ elsif (lc($working[0]) eq 'opengl renderer string'){
+ if ($working[1]){
+ $working[1] = main::clean($working[1]);
+ }
+ # note: seen cases where gl drivers are missing, with empty field value.
+ else {
+ $gl->{'glx'}{'no-gl'} = 1;
+ $working[1] = main::message('glx-value-empty');
+ }
+ if (!$gl->{'glx'}{'opengl'}{'renderers'} ||
+ !(grep {$_ eq $working[1]} @{$gl->{'glx'}{'opengl'}{'renderers'}})){
+ push(@{$gl->{'glx'}{'opengl'}{'renderers'}}, $working[1]) ;
+ }
+ }
+ # Dropping all conditions from this test to just show full mesa information
+ # there is a user case where not f and mesa apply, atom mobo
+ # This can be the compatibility version, or just the version the hardware
+ # supports. Core version will override always if present.
+ elsif (lc($working[0]) eq 'opengl version string'){
+ if ($working[1]){
+ # first grab the actual gl version
+ # non free drivers like nvidia may only show their driver version info
+ if ($working[1] =~ /^(\S+)(\s|$)/){
+ push(@{$gl->{'glx'}{'opengl'}{'versions'}}, $1);
+ }
+ # handle legacy format: 1.2 (1.5 Mesa 6.5.1) as well as more current:
+ # 4.5 (Compatibility Profile) Mesa 22.3.6
+ # Note: legacy: fglrx starting adding compat strings but they don't
+ # change this result:
+ # 4.5 Compatibility Profile Context Mesa 15.3.6
+ if ($working[1] =~ /(Mesa|NVIDIA)\s(\S+?)\)?$/i){
+ if ($1 && $2 && !$gl->{'glx'}{'opengl'}{'driver'}){
+ $gl->{'glx'}{'opengl'}{'driver'}{'vendor'} = lc($1);
+ $gl->{'glx'}{'opengl'}{'driver'}{'version'} = $2;
+ }
+ }
+ }
+ elsif (!$gl->{'glx'}{'no-gl'}){
+ $gl->{'glx'}{'no-gl'} = 1;
+ push(@{$gl->{'glx'}{'opengl'}{'versions'}},main::message('glx-value-empty'));
+ }
+ }
+ # if -B was always available, we could skip this, but it is not
+ elsif ($line =~ /GLX Visuals/){
+ last;
+ }
+ }
+ # eglinfo/glxinfo share these
+ if ($b_opengl){
+ if ($working[0] =~ /^OpenGL (compatibility|core) profile version( string)?$/){
+ $value = lc($1);
+ # note: no need to apply empty message here since we don't have the data
+ # anyway
+ if ($working[1]){
+ # non free drivers like nvidia only show their driver version info
+ if ($working[1] =~ /^(\S+)(\s|$)/){
+ push(@{$gl->{'glx'}{'opengl'}{$value}{'versions'}}, $1);
+ }
+ # fglrx started appearing with this extra string, does not appear
+ # to communicate anything of value
+ if ($working[1] =~ /\s+(Mesa|NVIDIA)\s+(\S+)$/){
+ if ($1 && $2 && !$gl->{'glx'}{'opengl'}{$value}{'vendor'}){
+ $gl->{'glx'}{'opengl'}{$value}{'driver'}{'vendor'} = lc($1);
+ $gl->{'glx'}{'opengl'}{$value}{'driver'}{'version'} = $2;
+ }
+ if ($source eq 'egl' && $platform){
+ if (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'opengl'}{$value}{'vendor'} = lc($1);
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'opengl'}{$value}{'version'} = $2;
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'opengl'}{$value}{'vendor'} = lc($1);
+ $gl->{'egl'}{'platforms'}{$platform}{'opengl'}{$value}{'version'} = $2;
+ }
+ }
+ }
+ }
+ }
+ elsif ($working[0] =~ /^OpenGL (compatibility|core) profile renderer?$/){
+ $value = lc($1);
+ if ($working[1]){
+ $working[1] = main::clean($working[1]);
+ }
+ # note: seen cases where gl drivers are missing, with empty field value.
+ else {
+ $gl->{'glx'}{'no-gl'} = 1;
+ $working[1] = main::message('glx-value-empty');
+ }
+ if (!$gl->{'glx'}{'opengl'}{$value}{'renderers'} ||
+ !(grep {$_ eq $working[1]} @{$gl->{'glx'}{'opengl'}{$value}{'renderers'}})){
+ push(@{$gl->{'glx'}{'opengl'}{$value}{'renderers'}}, $working[1]) ;
+ }
+ if ($source eq 'egl' && $platform){
+ if ($value eq 'core'){
+ $value2 = (defined $device) ? "$platform-$device": $platform;
+ push(@{$gl->{'egl'}{'data'}{'renderers'}{$working[1]}},$value2);
+ }
+ if (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'opengl'}{$value}{'renderer'} = $working[1];
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'opengl'}{$value}{'renderer'} = $working[1];
+ }
+ }
+ }
+ elsif ($working[0] =~ /^OpenGL (compatibility|core) profile vendor$/){
+ $value = lc($1);
+ if (!$gl->{'glx'}{'opengl'}{$value}{'vendors'} ||
+ !(grep {$_ eq $working[1]} @{$gl->{'glx'}{'opengl'}{$value}{'vendors'}})){
+ push(@{$gl->{'glx'}{'opengl'}{$value}{'vendors'}}, $working[1]) ;
+ }
+ if ($source eq 'egl' && $platform){
+ if (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'opengl'}{$value}{'vendor'} = $working[1];
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'opengl'}{$value}{'vendor'} = $working[1];
+ }
+
+ }
+ }
+ elsif (lc($working[0]) eq 'opengl es profile version string'){
+ if ($working[1] && !$gl->{'glx'}{'es-version'}){
+ # OpenGL ES 3.2 Mesa 23.0.3
+ if ($working[1] =~ /^OpenGL ES (\S+) Mesa (\S+)/){
+ $gl->{'glx'}{'es'}{'version'} = $1;
+ if ($2 && !$gl->{'glx'}{'es'}{'mesa-version'}){
+ $gl->{'glx'}{'es'}{'mesa-version'} = $2;
+ }
+ if ($source eq 'egl' && $platform){
+ if (defined $device){
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'opengl'}{'es'}{'vendor'} = 'mesa';
+ $gl->{'egl'}{'platforms'}{$platform}{$device}{'opengl'}{'es'}{'version'} = $working[1];
+ }
+ else {
+ $gl->{'egl'}{'platforms'}{$platform}{'opengl'}{'es'}{'vendor'} = 'mesa';
+ $gl->{'egl'}{'platforms'}{$platform}{'opengl'}{'es'}{'version'} = $working[1];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ main::log_data('dump',"$source \$results",$results) if $b_log;
+ if ($source eq 'egl'){
+ print "GL Data: $source: ", Data::Dumper::Dumper $gl if $dbg[57];
+ main::log_data('dump',"GL data: $source:",$gl) if $b_log;
+ }
+ else {
+ print "GL Data: $source: ", Data::Dumper::Dumper $gl->{'glx'} if $dbg[57];
+ main::log_data('dump',"GLX data: $source:",$gl->{'glx'}) if $b_log;
+ }
+ eval $end if $b_log;
+}
+
+sub process_glx_data {
+ eval $start if $b_log;
+ my ($glx,$b_glx) = @_;
+ my $value;
+ # Remember: if you test for a hash ref hash ref, you create the first hash ref!
+ if ($glx->{'direct-renders'}){
+ $glx->{'direct-render'} = join(', ', @{$glx->{'direct-renders'}});
+ }
+ if (!$glx->{'opengl'}{'renderers'} && $glx->{'opengl'}{'compatibility'} &&
+ $glx->{'opengl'}{'compatibility'}{'renderers'}){
+ $glx->{'opengl'}{'renderers'} = $glx->{'opengl'}{'compatibility'}{'renderers'};
+ }
+ # This is tricky, GLX OpenGL version string can be compatibility version,
+ # but usually they are the same. Just in case, try this. Note these are
+ # x.y.z type numbering formats generally so use string compare
+ if ($glx->{'opengl'}{'core'} && $glx->{'opengl'}{'core'}{'versions'}){
+ $glx->{'opengl'}{'version'} = (sort @{$glx->{'opengl'}{'core'}{'versions'}})[-1];
+ }
+ elsif ($glx->{'opengl'}{'versions'}){
+ $glx->{'opengl'}{'version'} = (sort @{$glx->{'opengl'}{'versions'}})[-1];
+ }
+ if ($glx->{'opengl'}{'version'} &&
+ ($glx->{'opengl'}{'compatibility'} || $glx->{'opengl'}{'versions'})){
+ # print "v: $glx->{'opengl'}{'version'}\n";
+ # print Data::Dumper::Dumper $glx->{'opengl'}{'versions'};
+ # print 'v1: ', (sort @{$glx->{'opengl'}{'versions'}})[0], "\n";
+ # here we look for different versions, and determine most likely compat one
+ if ($glx->{'opengl'}{'compatibility'} &&
+ $glx->{'opengl'}{'compatibility'}{'versions'} &&
+ (sort @{$glx->{'opengl'}{'compatibility'}{'versions'}})[0] ne $glx->{'opengl'}{'version'}){
+ $value = (sort @{$glx->{'opengl'}{'compatibility'}{'versions'}})[0];
+ $glx->{'opengl'}{'compatibility'}{'version'} = $value;
+ }
+ elsif ($glx->{'opengl'}{'versions'} &&
+ (sort @{$glx->{'opengl'}{'versions'}})[0] ne $glx->{'opengl'}{'version'}){
+ $value = (sort @{$glx->{'opengl'}{'versions'}})[0];
+ $glx->{'opengl'}{'compatibility'}{'version'} = $value;
+ }
+ }
+ if ($glx->{'opengl'}{'renderers'}){
+ $glx->{'opengl'}{'renderer'} = join(', ', @{$glx->{'opengl'}{'renderers'}});
+ }
+ # likely eglinfo or advanced glxinfo
+ if ($glx->{'opengl'}{'vendor'} &&
+ $glx->{'opengl'}{'core'} &&
+ $glx->{'opengl'}{'core'}{'driver'} &&
+ $glx->{'opengl'}{'core'}{'driver'}{'vendor'} &&
+ $glx->{'opengl'}{'core'}{'driver'}{'vendor'} eq 'mesa' &&
+ $glx->{'opengl'}{'vendor'} ne $glx->{'opengl'}{'core'}{'driver'}{'vendor'}){
+ $value = $glx->{'opengl'}{'vendor'} . ' ';
+ $value .= $glx->{'opengl'}{'core'}{'driver'}{'vendor'};
+ $glx->{'opengl'}{'vendor'} = $value;
+ }
+ # this can be glxinfo only case, no eglinfo
+ elsif ($glx->{'opengl'}{'vendor'} &&
+ $glx->{'opengl'}{'driver'} &&
+ $glx->{'opengl'}{'driver'}{'vendor'} &&
+ $glx->{'opengl'}{'driver'}{'vendor'} eq 'mesa' &&
+ $glx->{'opengl'}{'vendor'} ne $glx->{'opengl'}{'driver'}{'vendor'}){
+ $value = $glx->{'opengl'}{'vendor'} . ' ';
+ $value .= $glx->{'opengl'}{'driver'}{'vendor'};
+ $glx->{'opengl'}{'vendor'} = $value;
+ }
+ elsif (!$glx->{'opengl'}{'vendor'} &&
+ $glx->{'opengl'}{'core'} && $glx->{'opengl'}{'core'}{'driver'} &&
+ $glx->{'opengl'}{'core'}{'driver'}{'vendor'}){
+ $glx->{'opengl'}{'vendor'} = $glx->{'opengl'}{'core'}{'driver'}{'vendor'};
+ }
+ if ((!$glx->{'opengl'}{'driver'} ||
+ !$glx->{'opengl'}{'driver'}{'version'}) &&
+ $glx->{'opengl'}{'core'} &&
+ $glx->{'opengl'}{'core'}{'driver'} &&
+ $glx->{'opengl'}{'core'}{'driver'}{'version'}){
+ $value = $glx->{'opengl'}{'core'}{'driver'}{'version'};
+ $glx->{'opengl'}{'driver'}{'version'} = $value;
+ }
+ # only tripped when glx filled by eglinfo
+ if (!$glx->{'source'}){
+ my $type;
+ if (!$b_glx){
+ $type = 'glx-egl-missing';
+ }
+ elsif ($b_display){
+ $type = 'glx-egl';
+ }
+ else {
+ $type = 'glx-egl-console';
+ }
+ $glx->{'note'} = main::message($type);
+ }
+ print "GLX Data: ", Data::Dumper::Dumper $glx if $dbg[57];
+ main::log_data('dump',"GLX data:",$glx) if $b_log;
+ eval $end if $b_log;
+}
+
+sub vulkan_data {
+ eval $start if $b_log;
+ my ($program,$vulkan) = @_;
+ my ($data,$msg,@working);
+ my ($results) = ([]);
+ if ($dbg[56] || $b_log){
+ $msg = "${line1}Vulkan Data\n${line3}";
+ print $msg if $dbg[56];
+ push(@$results,$msg) if $b_log;
+ }
+ if (!$fake{'vulkan'}){
+ $data = main::grabber("$program 2>/dev/null",'','','ref');
+ }
+ else {
+ my $file;
+ $file = "$fake_data_dir/graphics/vulkan/vulkaninfo-intel-llvm-1.txt";
+ $file = "$fake_data_dir/graphics/vulkan/vulkaninfo-nvidia-1.txt";
+ $file = "$fake_data_dir/graphics/vulkan/vulkaninfo-intel-1.txt";
+ $file = "$fake_data_dir/graphics/vulkan/vulkaninfo-amd-dz.txt";
+ $file = "$fake_data_dir/graphics/vulkan/vulkaninfo-mali-3.txt";
+ $data = main::reader($file,'','ref');
+ }
+ if (!$data){
+ if ($dbg[56] || $b_log){
+ $msg = "No Vulkan data found" if $dbg[56];
+ print "$msg\n" if $dbg[56];
+ push(@$results,$msg) if $b_log;
+ }
+ return 0;
+ }
+ set_mesa_drivers() if !%mesa_drivers;
+ my ($id,%active);
+ foreach my $line (@$data){
+ next if $line =~ /^(\s*|-+|=+)$/;
+ @working = split(/\s*:\s*/,$line,2);
+ next if !@working;
+ if ($line =~ /^\S/){
+ if ($active{'start'}){undef $active{'start'}}
+ if ($active{'layers'}){undef $active{'layers'}}
+ if ($active{'groups'}){undef $active{'groups'}}
+ if ($active{'limits'}){undef $active{'limits'}}
+ if ($active{'features'}){undef $active{'features'}}
+ if ($active{'extensions'}){undef $active{'extensions'}}
+ if ($active{'format'}){undef $active{'format'}}
+ if ($active{'driver'}){($active{'driver'},$id) = ()}
+ }
+ next if $active{'start'};
+ next if $active{'groups'};
+ next if $active{'limits'};
+ next if $active{'features'};
+ next if $active{'extensions'};
+ next if $active{'format'};
+ if ($dbg[56] || $b_log){
+ $msg = $line;
+ print "$msg\n" if $dbg[56];
+ push(@$results,$msg) if $b_log;
+ }
+ if ($working[0] eq 'Vulkan Instance Version'){
+ $vulkan->{'data'}{'version'} = $working[1];
+ $active{'start'} = 1;
+ }
+ elsif ($working[0] eq 'Layers'){
+ if ($working[1] =~ /count\s*=\s*(\d+)/){
+ $vulkan->{'data'}{'layers'} = $1;
+ }
+ $active{'layers'} = 1;
+ }
+ # note: can't close this because Intel didn't use proper indentation
+ elsif ($working[0] eq 'Presentable Surfaces'){
+ $active{'surfaces'} = 1;
+ }
+ elsif ($working[0] eq 'Device Groups'){
+ $active{'groups'} = 1;
+ $active{'surfaces'} = 0;
+ }
+ elsif ($working[0] eq 'Device Properties and Extensions'){
+ $active{'devices'} = 1;
+ $active{'surfaces'} = 0;
+ undef $id;
+ }
+ elsif ($working[0] eq 'VkPhysicalDeviceProperties'){
+ $active{'props'} = 1;
+ }
+ elsif ($working[0] eq 'VkPhysicalDeviceDriverProperties'){
+ $active{'driver'} = 1;
+ }
+ elsif ($working[0] =~ /^\S+Features/i){
+ $active{'features'} = 1;
+ }
+ # seen as line starter string or inner VkPhysicalDeviceProperties
+ elsif ($working[0] =~ /^\s*\S+Limits/i){
+ $active{'limits'} = 1;
+ }
+ elsif ($working[0] =~ /^FORMAT_/){
+ $active{'format'} = 1;
+ }
+ elsif ($working[0] =~ /^(Device|Instance) Extensions/){
+ $active{'extensions'} = 1;
+ }
+ if ($active{'surfaces'}){
+ if ($working[0] eq 'GPU id'){
+ if ($working[1] =~ /^(\d+)\s+\((.*?)\):?$/){
+ $id = $1;
+ $vulkan->{'devices'}{$id}{'model'} = main::clean($2);
+ }
+ }
+ if (defined $id){
+ # seen leading space, no leading space
+ if ($line =~ /^\s*Surface type/){
+ $active{'surface-type'} = 1;
+ }
+ if ($active{'surface-type'} && $line =~ /\S+_(\S+)_surface$/){
+ if (!$vulkan->{'devices'}{$id}{'surfaces'} ||
+ !(grep {$_ eq $1} @{$vulkan->{'devices'}{$id}{'surfaces'}})){
+ push(@{$vulkan->{'devices'}{$id}{'surfaces'}},$1);
+ }
+ if (!$vulkan->{'data'}{'surfaces'} ||
+ !(grep {$_ eq $1} @{$vulkan->{'data'}{'surfaces'}})){
+ push(@{$vulkan->{'data'}{'surfaces'}},$1);
+ }
+ }
+ if ($working[0] =~ /^\s*Formats/){
+ undef $active{'surface-type'};
+ }
+ }
+ }
+ if ($active{'devices'}){
+ if ($working[0] =~ /^GPU(\d+)/){
+ $id = $1;
+ }
+ elsif (defined $id){
+ # apiVersion=4194528 (1.0.224); 1.3.246 (4206838); 79695971 (0x4c01063)
+ if ($line =~ /^\s+apiVersion\s*=\s*(\S+)(\s+\(([^)]+)\))?/i){
+ my ($a,$b) = ($1,$3);
+ my $api = (!$b || $b =~ /^(0x)?\d+$/) ? $a : $b;
+ $vulkan->{'devices'}{$id}{'device-api-version'} = $api;
+ }
+ elsif ($line =~ /^\s+driverVersion\s*=\s*(\S+)/i){
+ $vulkan->{'devices'}{$id}{'device-driver-version'} = $1;
+ }
+ elsif ($line =~ /^\s+vendorID\s*=\s*0x(\S+)/i){
+ $vulkan->{'devices'}{$id}{'vendor-id'} = $1;
+ }
+ elsif ($line =~ /^\s+deviceID\s*=\s*0x(\S+)/i){
+ $vulkan->{'devices'}{$id}{'device-id'} = $1;
+ }
+ # deviceType=DISCRETE_GPU; PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
+ elsif ($line =~ /^\s+deviceType\s*=\s*(\S+?_TYPE_)?(\S+)$/i){
+ $vulkan->{'devices'}{$id}{'device-type'} = lc($2);
+ $vulkan->{'devices'}{$id}{'device-type'} =~ s/_/-/g;
+ }
+ # deviceName=AMD Radeon RX 6700 XT (RADV NAVI22); AMD RADV HAWAII
+ # lvmpipe (LLVM 15.0.6, 256 bits); NVIDIA GeForce GTX 1650 Ti
+ elsif ($line =~ /^\s+deviceName\s*=\s*(\S+)(\s.*|$)/i){
+ $vulkan->{'devices'}{$id}{'device-vendor'} = main::clean(lc($1));
+ $vulkan->{'devices'}{$id}{'device-name'} = main::clean($1 . $2);
+ }
+ }
+ }
+ if ($active{'driver'}){
+ if (defined $id){
+ # driverName=llvmpipe; radv;
+ if ($line =~ /^\s+driverName\s*=\s*(\S+)(\s|$)/i){
+ my $driver = lc($1);
+ if ($mesa_drivers{$driver}){
+ $vulkan->{'devices'}{$id}{'hw'} = $mesa_drivers{$driver};
+ }
+ $vulkan->{'devices'}{$id}{'driver-name'} = $driver;
+ if (!$vulkan->{'data'}{'drivers'} ||
+ !(grep {$_ eq $driver} @{$vulkan->{'data'}{'drivers'}})){
+ push(@{$vulkan->{'data'}{'drivers'}},$driver);
+ }
+ }
+ # driverInfo=Mesa 23.1.3 (LLVM 15.0.7); 525.89.02; Mesa 23.1.3
+ elsif ($line =~ /^\s+driverInfo\s*=\s*((Mesa)\s)?(.*)/i){
+ $vulkan->{'devices'}{$id}{'mesa'} = lc($2) if $2;
+ $vulkan->{'devices'}{$id}{'driver-info'} = $3;
+ }
+ }
+ }
+ }
+ main::log_data('dump','$results',$results) if $b_log;
+ print 'Vulkan Data: ', Data::Dumper::Dumper $vulkan if $dbg[57];
+ main::log_data('dump','$vulkan',$vulkan) if $b_log;
+ eval $end if $b_log;
+}
+
## DISPLAY DATA WAYLAND ##
sub display_data_wayland {
eval $start if $b_log;
@@ -15074,7 +16571,8 @@ sub display_data_wayland {
main::log_data('dump','$monitor_ids',$monitor_ids) if $b_log;
eval $end if $b_log;
}
-# if we didn't get explicit tool for wayland data, check to see if we got most
+
+# If we didn't get explicit tool for wayland data, check to see if we got most
# of the data from /sys/class/drm edid and then skip xrandr to avoid gunking up
# the data, in that case, all we get from xrandr would be the position, which is
# nice but not a must-have. We've already cleared out all disabled ports.
@@ -15097,6 +16595,7 @@ sub check_wayland_data {
eval $end if $b_log;
return $b_skip_pos;
}
+
# Set Display rect size for > 1 monitors, monitor positions, size-i, diag
sub wayland_data_advanced {
eval $start if $b_log;
@@ -15157,7 +16656,6 @@ sub wayland_data_advanced {
}
## WAYLAND COMPOSITOR DATA TOOLS ##
-
# NOTE: These patterns are VERY fragile, and depend on no changes at all to
# the data structure, and more important, the order. Something I would put
# almost no money on being able to count on.
@@ -15171,7 +16669,8 @@ sub wlinfo_data {
$data = main::grabber("$program 2>/dev/null",'','strip','ref');
}
else {
- $file = "$fake_data_dir/wayland/weston-info-2-mon-1.txt";
+ $file = "$fake_data_dir/graphics/wayland/weston-info-2-mon-1.txt";
+ $file = "$fake_data_dir/graphics/wayland/wayland-info-weston-vm-sparky.txt";
$data = main::reader($file,'strip','ref');
}
print 'wayland/weston-info raw: ', Data::Dumper::Dumper $data if $dbg[46];
@@ -15282,7 +16781,8 @@ sub wlinfo_data {
print 'wayland/weston-info: monitor_ids: ', Data::Dumper::Dumper $monitor_ids if $dbg[46];
eval $end if $b_log;
}
-# note; since not all systems will have /sys data, we'll repack it if it's
+
+# Note; since not all systems will have /sys data, we'll repack it if it's
# missing here.
sub swaymsg_data {
eval $start if $b_log;
@@ -15305,7 +16805,7 @@ sub swaymsg_data {
}
else {
undef $monitor_ids;
- $file = "$fake_data_dir/wayland/swaymsg-2-monitor-1.txt";
+ $file = "$fake_data_dir/graphics/wayland/swaymsg-2-monitor-1.txt";
@data = main::reader($file,'strip');
}
print 'swaymsg: ', Data::Dumper::Dumper \@data if $dbg[46];
@@ -15406,7 +16906,8 @@ sub swaymsg_data {
print 'swaymsg: ', Data::Dumper::Dumper $monitor_ids if $dbg[46];
eval $end if $b_log;
}
-# like a basic stripped down swaymsg -t get_outputs -p, less data though
+
+# Like a basic stripped down swaymsg -t get_outputs -p, less data though
# This is EXTREMELY LIKELY TO FAIL! Any tiny syntax change will break this.
sub wlrrandr_data {
eval $start if $b_log;
@@ -15418,7 +16919,7 @@ sub wlrrandr_data {
}
else {
undef $monitor_ids;
- $file = "$fake_data_dir/wayland/wlr-randr-2-monitor-1.txt";
+ $file = "$fake_data_dir/graphics/wayland/wlr-randr-2-monitor-1.txt";
$data = main::reader($file,'strip','ref');
}
foreach (@$data){
@@ -15470,7 +16971,8 @@ sub wlrrandr_data {
print 'wlr-randr: ', Data::Dumper::Dumper $monitor_ids if $dbg[46];
eval $end if $b_log;
}
-# return model/serial for those horrible string type values we have to process
+
+# Return model/serial for those horrible string type values we have to process
# in swaymsg -t get_outputs -p and wlr-randr default output
sub get_model_serial {
eval $start if $b_log;
@@ -15525,6 +17027,7 @@ sub display_data_x {
main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log;
eval $end if $b_log;
}
+
sub xdriinfo_data {
eval $start if $b_log;
my $program = $_[0];
@@ -15533,7 +17036,7 @@ sub xdriinfo_data {
$xdriinfo = main::grabber("$program $display_opt 2>/dev/null",'','strip','ref');
}
else {
- # $xdriinfo = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-1.txt",'strip','ref');
+ # $xdriinfo = main::reader("$fake_data_dir/xrandr/xrandr-test-1.txt",'strip','ref');
}
foreach $screen (@$xdriinfo){
if ($screen =~ /^Screen (\d+):\s+(\S+)/){
@@ -15559,13 +17062,21 @@ sub xdriinfo_data {
main::log_data('dump','%dri_drivers',\%dri_drivers) if $b_log;
eval $end if $b_log;
}
+
sub xdpyinfo_data {
eval $start if $b_log;
my ($program) = @_;
my ($diagonal,$diagonal_m,$dpi) = ('','','');
- my ($screen_id,$screen,@working);
+ my ($screen_id,$xdpyinfo,@working);
my ($res_x,$res_y,$size_x,$size_x_i,$size_y,$size_y_i);
- my $xdpyinfo = main::grabber("$program $display_opt 2>/dev/null","\n",'strip','ref');
+ if (!$fake{'xdpyinfo'}){
+ $xdpyinfo = main::grabber("$program $display_opt 2>/dev/null","\n",'strip','ref');
+ }
+ else {
+ # my $file;
+ # $file = "$fake_data_dir/xdpyinfo/xdpyinfo-1-screen-2-in-inxi.txt";
+ # $xdpyinfo = main::reader($file,'strip','ref');
+ }
# @$xdpyinfo = map {s/^\s+//;$_} @$xdpyinfo if @$xdpyinfo;
# print join("\n",@$xdpyinfo), "\n";
# X vendor and version detection.
@@ -15607,7 +17118,7 @@ sub xdpyinfo_data {
elsif ($working[0] eq 'number of screens'){
$graphics{'display-screens'} = $working[1];
}
- elsif ($working[0] =~ /^screen #([0-9]+):/){
+ elsif ($working[0] =~ /^screen #([0-9]+):/){
$screen_id = $1;
}
elsif ($working[0] eq 'resolution'){
@@ -15632,73 +17143,89 @@ sub xdpyinfo_data {
$diagonal = ($size_x && $size_y) ? sprintf("%.2f", (sqrt($size_x**2 + $size_y**2)/25.4)) + 0 : '';
$diagonal_m = ($size_x && $size_y) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : '';
}
- $screen = {
- 'screen' => $screen_id,
+ push(@{$graphics{'screens'}}, {
+ 'diagonal' => $diagonal,
+ 'diagonal-m' => $diagonal_m,
'res-x' => $res_x,
'res-y' => $res_y,
+ 'screen' => $screen_id,
+ 's-dpi' => $dpi,
'size-x' => $size_x,
'size-x-i' => $size_x_i,
'size-y' => $size_y,
'size-y-i' => $size_y_i,
- 's-dpi' => $dpi,
- 'diagonal' => $diagonal,
- 'diagonal-m' => $diagonal_m,
- };
- push(@{$graphics{'screens'}}, $screen);
+ 'source' => 'xdpyinfo',
+ });
}
}
print 'Data: xdpyinfo: ', Data::Dumper::Dumper $graphics{'screens'} if $dbg[17];
main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log;
eval $end if $b_log;
}
+
sub xrandr_data {
eval $end if $b_log;
my ($program) = @_;
my ($diagonal,$diagonal_m,$dpi,$monitor_id,$pos_x,$pos_y,$primary);
my ($res_x,$res_x_max,$res_y,$res_y_max);
- my ($screen_id,$set_as,$size_x,$size_x_i,$size_y,$size_y_i,$x_screen);
- my (@ids,%monitors,@xrandr_screens,$xrandr);
+ my ($screen_id,$set_as,$size_x,$size_x_i,$size_y,$size_y_i);
+ my (@ids,%monitors,@xrandr,@xrandr_screens);
if (!$fake{'xrandr'}){
- $xrandr = main::grabber("$program $display_opt 2>/dev/null",'','strip','ref');
+ # @xrandr = main::grabber("$program $display_opt 2>/dev/null",'','strip','arr');
+ # note: --prop support added v 1.2, ~2009 in distros
+ @xrandr = qx($program --prop $display_opt 2>&1);
+ if ($? > 0){
+ # we only want to rerun if unsupported option
+ if (grep {/unrecognized/} @xrandr){
+ @xrandr = qx($program $display_opt 2>/dev/null);
+ }
+ else {
+ @xrandr = ();
+ }
+ }
+ chomp(@xrandr) if @xrandr;
}
else {
- # $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-4-displays-1.txt",'strip','ref');
- $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-3-display-primary-issue.txt",'strip','ref');
- # $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-1.txt",'strip','ref');
- # $xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-2.txt",'strip','ref');
+ # my $file;
+ # $file = "$fake_data_dir/xrandr/xrandr-4-displays-1.txt";
+ # $file = "$fake_data_dir/xrandr/xrandr-3-display-primary-issue.txt";
+ # $file = "$fake_data_dir/xrandr/xrandr-test-1.txt";
+ # $file = "$fake_data_dir/xrandr/xrandr-test-2.txt";
+ # $file = "$fake_data_dir/xrandr/xrandr-1-screen-2-in-inxi.txt";
+ # @xrandr = main::reader($file,'strip','arr');
}
# $graphics{'dimensions'} = (\@dimensions);
# we get a bit more info from xrandr than xdpyinfo, but xrandr fails to handle
# multiple screens from different video cards
- foreach (@$xrandr){
+ # $graphics{'screens'} = undef;
+ foreach (@xrandr){
# note: no mm as with xdpyinfo
# Screen 0: minimum 320 x 200, current 2560 x 1024, maximum 8192 x 8192
if (/^Screen ([0-9]+):/){
$screen_id = $1;
- # handle no xdpyinfo Screen data
- if ((!$graphics{'screens'} ||
- scalar @{$graphics{'screens'}} != (scalar @xrandr_screens + 1)) &&
- /:\s.*?current\s+(\d+)\s*x\s*(\d+),\smaximum\s+(\d+)\s*x\s*(\d+)/){
+ # handle no xdpyinfo Screen data, multiple xscreens, etc
+ if (check_screens($screen_id) &&
+ /:\s.*?current\s+(\d+)\s*x\s*(\d+),\smaximum\s+(\d+)\s*x\s*(\d+)/){
$res_x = $1;
$res_y = $2;
$res_x_max = $3;
$res_y_max = $4;
- $x_screen = {
- 'screen' => $screen_id,
+ push(@{$graphics{'screens'}}, {
+ 'diagonal' => undef,
+ 'diagonal-m' => undef,
'res-x' => $res_x,
'res-y' => $res_y,
+ 'screen' => $screen_id,
+ 's-dpi' => undef,
'size-x' => undef,
'size-x-i' => undef,
'size-y' => undef,
'size-y-i' => undef,
- 's-dpi' => undef,
- 'diagonal' => undef,
- 'diagonal-m' => undef,
- };
- push(@{$graphics{'screens'}}, $x_screen);
+ 'source' => 'xrandr',
+ });
}
if (%monitors){
- push(@xrandr_screens,\%monitors);
+ push(@xrandr_screens,{%monitors});
%monitors = ();
}
}
@@ -15706,7 +17233,7 @@ sub xrandr_data {
# DP-1 connected primary 2560x1440+1080+1200 (normal left inverted right x axis y axis) 598mm x 336mm
# HDMI-1 connected 1080x1920+0+0 left (normal left inverted right x axis y axis) 160mm x 90mm
# disabled but connected: VGA-1 connected (normal left inverted right x axis y axis)
- elsif (/^([^\s]+)\s+connected\s(primary\s)?/){
+ elsif (/^([\S]+)\s+connected\s(primary\s)?/){
$monitor_id = $1;
$set_as = $2;
if (/^[^\s]+\s+connected\s(primary\s)?([0-9]+)\s*x\s*([0-9]+)\+([0-9]+)\+([0-9]+)(\s[^(]*\([^)]+\))?(\s([0-9]+)mm\sx\s([0-9]+)mm)?/){
@@ -15730,7 +17257,7 @@ sub xrandr_data {
($res_x,$res_y,$pos_x,$pos_y,$size_x,$size_x_i,$size_y,$size_y_i,$dpi,$diagonal,$diagonal_m) = ()
}
undef $primary;
- push(@ids,$monitor_id);
+ push(@ids,[$monitor_id]);
if ($set_as){
$primary = $monitor_id;
$set_as =~ s/\s$//;
@@ -15756,24 +17283,41 @@ sub xrandr_data {
# print "x:$size_x y:$size_y rx:$res_x ry:$res_y dpi:$dpi\n";
($res_x,$res_y,$size_x,$size_x_i,$size_y,$size_y_i,$set_as) = (0,0,0,0,0,0,0,0,undef);
}
- my @working = split(/\s+/,$_);
- # this is the monitor current dimensions
- if ($working[1] =~ /\*/){
- $working[1] =~ s/\*|\+//g;
- $working[1] = sprintf("%.0f",$working[1]);
- if ($monitor_id && %monitors){
- $monitors{$monitor_id}->{'hz'} = $working[1];
+ elsif (/^([\S]+)\s+disconnected\s/){
+ undef $monitor_id;
+ }
+ elsif ($monitor_id && %monitors) {
+ my @working = split(/\s+/,$_);
+ # this is the monitor current dimensions
+ # 5120x1440 59.98* 29.98
+ # print Data::Dumper::Dumper \@working;
+ next if !$working[2];
+ if ($working[2] =~ /\*/){
+ # print "$working[1] :: $working[2]\n";
+ $working[2] =~ s/\*|\+//g;
+ $working[2] = sprintf("%.0f",$working[2]);
+ $monitors{$monitor_id}->{'hz'} = $working[2];
+ ($diagonal,$dpi) = ('','');
+ # print Data::Dumper::Dumper \@monitors;
+ }
+ # \tCONNECTOR_ID: 52
+ elsif ($working[1] eq 'CONNECTOR_ID:'){
+ # print "$working[1] :: $working[2]\n";
+ if (!$monitors{$monitor_id}->{'connector-id'}){
+ push(@{$ids[$#ids]},$working[2]);
+ $monitors{$monitor_id}->{'connector-id'} = $working[2];
+ }
}
- ($diagonal,$dpi) = ('','');
- # print Data::Dumper::Dumper \@monitors;
}
}
if (%monitors){
- push(@xrandr_screens,\%monitors);
+ push(@xrandr_screens,{%monitors});
}
my $i = 0;
my $layouts;
- if (!defined $graphics{'display-screens'} && $graphics{'screens'}){
+ # corner cases, xrandr screens > xdpyinfo screen, no xdpyinfo counts
+ if ($graphics{'screens'} && (!defined $graphics{'display-screens'} ||
+ $graphics{'display-screens'} < scalar @{$graphics{'screens'}})){
$graphics{'display-screens'} = scalar @{$graphics{'screens'}};
}
map_monitor_ids(\@ids) if @ids;
@@ -15808,7 +17352,32 @@ sub xrandr_data {
main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log;
eval $end if $b_log;
}
-# case where no xpdyinfo display server/version data exists, or to set Wayland
+
+# Handle some strange corner cases with more robust testing
+sub check_screens {
+ my ($id) = @_;
+ my $b_use;
+ # used: scalar @{$graphics{'screens'}} != (scalar @$xrandr_screens + 1)
+ # before but that test can fail in some cases.
+ # no screens set in xdpyinfo. If xrandr has > 1 xscreen, this would be false
+ if (!$graphics{'screens'}){
+ $b_use = 1;
+ }
+ # verify that any xscreen set so far does not exist in $graphics{'screens'}
+ else {
+ my $b_detected;
+ foreach my $screen (@{$graphics{'screens'}}){
+ if ($screen->{'screen'} eq $id){
+ $b_detected = 1;
+ last;
+ }
+ }
+ $b_use = 1 if !$b_detected;
+ }
+ return $b_use;
+}
+
+# Case where no xpdyinfo display server/version data exists, or to set Wayland
# Xwayland version, or Xvesa data.
sub display_server_data {
eval $start if $b_log;
@@ -15828,14 +17397,8 @@ sub display_server_data {
@data = main::grabber("$program -version 2>&1",'','strip');
$server = 'X.org';
}
- elsif ($program = main::check_program('Xvesa')){
- @data = main::grabber("$program -version 2>&1",'','strip');
- $server = 'Xvesa';
- $graphics{'display-driver'} = ['vesa'];
- $graphics{'xvesa'} = $program;
- if (!$graphics{'screens'}){
- $graphics{'no-screens'} = main::message('screen-xvesa');
- }
+ else {
+ tinyx_data(\$server,\$version);
}
# print join('^ ', @paths), " :: $program\n";
# print Data::Dumper::Dumper \@data;
@@ -15850,10 +17413,6 @@ sub display_server_data {
elsif ($data[0] =~ /X Window System Version (\S+)/i){
$version = $1;
}
- elsif ($data[0] =~ /Xvesa from tinyx (\S+)/i){
- $version = $1;
- $server = 'TinyX Xvesa';
- }
}
$graphics{'x-server'} = [[$server,$version]] if $server;
}
@@ -15873,6 +17432,58 @@ sub display_server_data {
@paths = grep { !/^\/usr\/lib|xorg|libexec/ } @paths;
eval $end if $b_log;
}
+
+# args: 0: $server; 1: $version - both by ref
+sub tinyx_data {
+ eval $start if $b_log;
+ my ($server,$version) = @_;
+ # ordered by likelihood, Xmodesetting proposted by tinycore. Others were
+ # supported by DSL. Existed: Xigs Xipaq Xneomagic Xmga
+ my $tinies = 'vesa|fbdev|modesetting|chips|i810|igs|ipaq|mach64|mga|';
+ $tinies .= 'neomagic|savage|sis530|trident|trio|ts300';
+ # these run as a process, and sometimes also have screen resolution
+ if (my @result = (grep {/^(|\/\S+\/)X($tinies)\b/i} @ps_cmd)){
+ if ($result[0] =~ /^(|\/\S+\/)X($tinies)\b/i){
+ my $driver = $2;
+ my $vsize;
+ if ($result[0] =~ /\s-screen\s+(\d+(x\d+)+)\s/){
+ $vsize = $1;
+ }
+ my $tinyx = $graphics{'tinyx'} = 'X' . $driver;
+ $$server = "TinyX $tinyx";
+ $graphics{'display-driver'} = [$driver];
+ # not all tinyx had -version, DSL did not.
+ if (my $program = main::check_program($tinyx)){
+ $graphics{'xvesa'} = $program if $driver eq 'vesa';
+ my @data = main::grabber("$program -version 2>&1",'','strip');
+ if (@data && $data[0] =~ /$tinyx from tinyx (\S+)/i){
+ $$version = $1;
+ }
+ }
+ # should never happen but just in case
+ if (!$graphics{'screens'}){
+ # no-screens will store either res or tinyx res missing message
+ if ($vsize){
+ $graphics{'no-screens'} = $vsize;
+ }
+ else {
+ if (-d '/sys/devices/platform/'){
+ my @size = main::globber('/sys/devices/platform/*/graphics/*/virtual_size');
+ if (@size && (my $vsize = main::reader($size[0],'strip',0))){
+ $vsize =~ s/,/x/g;
+ $graphics{'no-screens'} = $vsize;
+ }
+ }
+ if (!$graphics{'no-screens'}){
+ $graphics{'no-screens'} = main::message('screen-tinyx',$driver);
+ }
+ }
+ }
+ }
+ }
+ eval $end if $b_log;
+}
+
sub display_protocol {
eval $start if $b_log;
$graphics{'protocol'} = '';
@@ -15948,9 +17559,11 @@ sub gpu_drivers_sys {
eval $end if $b_log;
return $drivers;
}
+
sub display_drivers_x {
eval $start if $b_log;
my $driver_data = [];
+ # print 'x-log: ' . $system_files{'xorg-log'} . "\n";
if (my $log = $system_files{'xorg-log'}){
if ($fake{'xorg-log'}){
# $log = "$ENV{HOME}/bin/scripts/inxi/data/xorg-logs/Xorg.0-voyager-serena.log";
@@ -15959,18 +17572,18 @@ sub display_drivers_x {
# $log = "$ENV{HOME}/bin/scripts/inxi/data/xorg-logs/Xorg.0-gm10.log";
# $log = "$ENV{HOME}/bin/scripts/inxi/data/xorg-logs/xorg-multi-driver-1.log";
}
- my $xorg = main::reader($log,'','ref');
+ my $x_log = main::reader($log,'','ref');
# list is from sgfxi plus non-free drivers, plus ARM drivers.
# Don't use ati. It's just a wrapper for: r128, mach64, radeon
my $list = join('|', qw(amdgpu apm ark armsoc atimisc
chips cirrus cyrix etnaviv fbdev fbturbo fglrx geode glide glint
i128 i740 i810-dec100 i810e i810 i815 i830 i845 i855 i865 i915 i945 i965
- iftv imstt intel ivtv mach64 mesa mga modesetting neomagic newport
- nouveau nsc nvidia nv openchrome r128 radeonhd radeon rendition
- s3virge s3 savage siliconmotion sisimedia sisusb sis
- sunbw2 suncg14 suncg3 suncg6 sunffb sunleo suntcx tdfx tga trident tseng
+ iftv igs imstt intel ipaq ivtv mach64 mesa mga m68k modesetting neomagic
+ newport nouveau nsc nvidia nv openchrome r128 radeonhd radeon rendition
+ s3virge s3 savage siliconmotion sisimedia sisusb sis sis530 sunbw2 suncg14
+ suncg3 suncg6 sunffb sunleo suntcx tdfx tga trident trio ts300 tseng
unichrome v4l vboxvideo vesa vga via vmware vmwgfx voodoo));
- $list = qr/$list/; # i only added perl 5.14, don't use
+ # $list = qr/$list/i; # qr/../i only added perl 5.14, fails on older perls
my ($b_use_dri,$dri,$driver,%drivers);
my ($alternate,$failed,$loaded,$unloaded);
my $pattern = 'Failed|Unload|Loading';
@@ -15979,22 +17592,22 @@ sub display_drivers_x {
$b_use_dri = 1;
$pattern .= '|DRI driver:';
}
- $pattern = qr/$pattern/;
+ # $pattern = qr/$pattern/i; # qr/../i only added perl 5.14, fails on older perls
# it's much cheaper to grab the simple pattern match then do the expensive one
# in the main loop.
- # @xorg = grep {/Failed|Unload|Loading/} @xorg;
- foreach my $line (@$xorg){
+ # @$x_log = grep {/Failed|Unload|Loading/} @$x_log;
+ foreach my $line (@$x_log){
next if $line !~ /$pattern/i;
- # print "$_\n";
- # note that in file names, driver is always lower case
- if ($line =~ /\sLoading.*($list)_drv\.so$/i){
+ # print "$line\n";
+ # note that in file names, driver is always lower case. Legacy _drv.o
+ if ($line =~ /\sLoading.*($list)_drv\.s?o$/i){
$driver=lc($1);
# we get all the actually loaded drivers first, we will use this to compare the
# failed/unloaded, which have not always actually been truly loaded
$drivers{$driver}='loaded';
}
# openbsd uses UnloadModule:
- elsif ($line =~ /(Unloading\s|UnloadModule).*\"?($list)(_drv\.so)?\"?$/i){
+ elsif ($line =~ /(Unloading\s|UnloadModule).*\"?($list)(_drv\.s?o)?\"?$/i){
$driver=lc($2);
# we get all the actually loaded drivers first, we will use this to compare the
# failed/unloaded, which have not always actually been truly loaded
@@ -16037,6 +17650,7 @@ sub display_drivers_x {
}
}
}
+ # print 'drivers: ', Data::Dumper::Dumper \%drivers;
foreach (sort keys %drivers){
if ($drivers{$_} eq 'loaded'){
push(@$loaded,$_);
@@ -16052,13 +17666,38 @@ sub display_drivers_x {
}
}
if ($loaded || $unloaded || $failed || $alternate){
- @$driver_data = ($loaded,$unloaded,$failed,$alternate);
+ $driver_data = [$loaded,$unloaded,$failed,$alternate];
}
}
eval $end if $b_log;
+ # print 'source: ', Data::Dumper::Dumper $driver_data;
return $driver_data;
}
+sub set_mesa_drivers {
+ %mesa_drivers = (
+ 'anv' => 'intel',
+ 'crocus' => 'intel',
+ 'etnaviv' => 'vivante',
+ 'freedreno' => 'qualcomm',
+ 'i915' => 'intel',
+ 'i965' => 'intel',
+ 'iris' => 'intel',
+ 'lima' => 'mali',
+ 'nouveau' => 'nvidia',
+ 'panfrost' => 'mali/bifrost',
+ 'r200' => 'amd',
+ 'r300' => 'amd',
+ 'r600' => 'amd',
+ 'radeonsi' => 'amd',
+ 'radv' => 'amd',
+ 'svga3d' => 'vmware',
+ 'v3d' => 'broadcom',
+ 'v3dv' => 'broadcom',
+ 'vc4' => 'broadcom',
+ );
+}
+
## GPU DATA ##
sub set_amd_data {
$gpu_amd = [
@@ -16103,12 +17742,14 @@ sub set_amd_data {
# 'years' => '1999-2001',
# },
# rage 5 was game cube flipper chip
+# rage 5 was game cube flipper chip 2000
{'arch' => 'Rage-6',
'ids' => '4137|4337|4437|4c59|5144|5159|515e',
'code' => 'R100',
'process' => 'TSMC 180nm',
'years' => '2000-07',
},
+ # |Radeon (7[3-9]{2}|8d{3}|9[5-9]d{2}
{'arch' => 'Rage-7',
'ids' => '4136|4150|4152|4170|4172|4242|4336|4966|496e|4c57|4c58|4c66|4c6e|' .
'4e51|4f72|4f73|5148|514c|514d|5157|5834|5835|5940|5941|5944|5960|5961|5962|' .
@@ -16134,7 +17775,7 @@ sub set_amd_data {
'ids' => '3150|3151|3152|3154|3155|3171|3e50|3e54|3e70|4e4a|4e56|5460|5461|' .
'5462|5464|5657|5854|5874|5954|5955|5974|5975|5b60|5b62|5b64|5b65|5b66|5b70|' .
'5b74|5b75',
- 'code' => 'R360-R400',
+ 'code' => 'Radeon IGP',
'process' => 'TSMC 110nm',
'years' => '2003-08',
},
@@ -16156,6 +17797,7 @@ sub set_amd_data {
'process' => 'TSMC 90nm',
'years' => '2005-07',
},
+ # process: tsmc 55nm, 65nm, xbox 360s at 40nm
{'arch' => 'TeraScale',
'ids' => '4346|4630|4631|9400|9401|9403|9405|940a|940b|9440|9441|9442|9443|' .
'9444|9446|944a|944b|944c|944e|9450|9452|9456|945a|9460|9462|946a|9480|9488|' .
@@ -16164,7 +17806,7 @@ sub set_amd_data {
'9515|9519|9540|954f|9552|9553|9555|9557|955f|9580|9586|9587|9588|9589|958a|' .
'958c|9591|9593|9595|9596|9597|9598|9599|95c0|95c2|95c4|95c5|95c6|95c9|95cc|' .
'95cd|95cf|9610|9611|9612|9613|9614|9615|9616|9710|9712|9713|9714|9715',
- 'code' => '',
+ 'code' => 'R6xx/RV6xx/RV7xx',
'process' => 'TSMC 55-65nm',
'years' => '2005-13',
},
@@ -16175,7 +17817,7 @@ sub set_amd_data {
'689b|689c|689d|689e|68a0|68a1|68a8|68a9|68b8|68b9|68ba|68be|68bf|68c0|68c1|' .
'68c7|68c8|68c9|68d8|68d9|68da|68de|68e0|68e1|68e4|68e5|68e8|68e9|68f1|68f2|' .
'68f8|68f9|68fa|68fe|9640|9641|9642|9643|9644|9645|9647|9648|9649|964a|964b|' .
- '964c|964e|964f|9802|9803|9804|9805|9806|9807|9808|9809|980a',
+ '964c|964e|964f|9802|9803|9804|9805|9806|9807|9808|9809|980a|9925|9926',
'code' => 'Evergreen',
'process' => 'TSMC 32-40nm',
'years' => '2009-15',
@@ -16191,72 +17833,89 @@ sub set_amd_data {
},
{'arch' => 'GCN-1',
'ids' => '154c|6600|6601|6604|6605|6606|6607|6608|6609|6610|6611|6613|6617|' .
- '6631|6660|6663|6664|6665|6667|666f|6780|6784|6788|678a|6798|679a|679b|679e|' .
- '679f|6800|6801|6802|6806|6808|6809|6810|6811|6816|6817|6818|6819|6820|6821|' .
- '6822|6823|6825|6826|6827|6828|6829|682a|682b|682c|682d|682f|6835|6837|683d|' .
- '683f',
+ '6631|6660|6663|6664|6665|6666|6667|666f|6780|6784|6788|678a|6798|6799|679a|' .
+ '679b|679e|679f|6800|6801|6802|6806|6808|6809|6810|6811|6816|6817|6818|6819|' .
+ '6820|6821|6822|6823|6825|6826|6827|6828|6829|682a|682b|682c|682d|682f|6830|' .
+ '6831|6835|6837|683d|683f|684c',
'code' => 'Southern Islands',
'process' => 'TSMC 28nm',
'years' => '2011-20',
},
+ # process: both TSMC and GlobalFoundries
{'arch' => 'GCN-2',
'ids' => '1304|1305|1306|1307|1309|130a|130b|130c|130d|130e|130f|1310|1311|' .
'1312|1313|1315|1316|1317|1318|131b|131c|131d|6640|6641|6646|6647|6649|664d|' .
'6650|6651|6658|665c|665d|665f|67a0|67a1|67a2|67a8|67a9|67aa|67b0|67b1|67b8|' .
'67b9|67be|9830|9831|9832|9833|9834|9835|9836|9837|9838|9839|983d|9850|9851|' .
- '9852|9853|9854|9855|9856|9857|9858|9859|985a|985b|985c|985d|985e|985f|98e4|' .
- '9920',
+ '9852|9853|9854|9855|9856|9857|9858|9859|985a|985b|985c|985d|985e|985f|991e|' .
+ '9920|9922',
'code' => 'Sea Islands',
- 'process' => 'GF/TSMC 16-28nm', # both TSMC and GlobalFoundries
+ 'process' => 'GF/TSMC 16-28nm',
'years' => '2013-17',
},
{'arch' => 'GCN-3',
- 'ids' => '6900|6901|6907|6920|6921|6929|692b|6938|6939|693b|7300|9874',
+ 'ids' => '6900|6901|6902|6907|6920|6921|6929|692b|692f|6930|6938|6939|693b|' .
+ '7300|730f|9874|98c0|98e4',
'code' => 'Volcanic Islands',
'process' => 'TSMC 28nm',
'years' => '2014-19',
},
{'arch' => 'GCN-4',
- 'ids' => '154e|1551|1552|1561|67c0|67c2|67c4|67c7|67ca|67cc|67cf|67d0|67d4|' .
- '67d7|67df|67e0|67e1|67e3|67e8|67e9|67eb|67ef|67ff|694c|694e|694f|6980|6981|' .
- '6985|6986|6987|698f|6995|699f|6fdf|9924|9925',
+ 'ids' => '154e|1551|1552|1561|67c0|67c1|67c2|67c4|67c7|67ca|67cc|67cf|67d0|' .
+ '67d4|67d7|67df|67e0|67e1|67e3|67e8|67e9|67eb|67ef|67ff|694c|694e|694f|6980|' .
+ '6981|6984|6985|6986|6987|698f|6995|6997|699f|6fdf|9924|9925',
'code' => 'Arctic Islands',
'process' => 'GF 14nm',
'years' => '2016-20',
},
{'arch' => 'GCN-5.1',
- 'ids' => '15df|1636|1638|164c|66a0|66a1|66a2|66a3|66a7|66af|69af',
+ 'ids' => '15d8|15dd|15df|15e7|1636|1638|164c|66a0|66a1|66a2|66a3|66a7|66af|' .
+ '69af',
'code' => 'Vega-2',
- 'process' => 'TSMC n7 (7nm)',
- 'years' => '2018-21',
+ 'process' => 'TSMC n7 (7nm)',
+ 'years' => '2018-22+',
},
{'arch' => 'GCN-5',
- 'ids' => '15d8|15dd|15ff|6860|6861|6862|6863|6864|6867|6868|6869|686a|686b|' .
- '686c|686d|686e|687f|69a0|69a1|69a2|69a3',
+ 'ids' => '15d8|15d9|15dd|15e7|15ff|1636|1638|164c|66a0|66a1|66a2|66a3|66a4|' .
+ '66a7|66af|6860|6861|6862|6863|6864|6867|6868|6869|686a|686b|686c|686d|686e|' .
+ '687f|69a0|69a1|69a2|69a3|69af',
'code' => 'Vega',
- 'process' => 'GF 14nm',
+ 'process' => 'GF 14nm',
'years' => '2017-20',
},
{'arch' => 'RDNA-1',
- 'ids' => '13e9|13fe|1478|1479|1607|7310|7312|731f|7340|7341|7347|734f|7360|' .
- '7362',
- 'code' => 'Navi',
+ 'ids' => '13e9|13f9|13fe|1478|1479|1607|7310|7312|7318|7319|731a|731b|731e|' .
+ '731f|7340|7341|7343|7347|734f|7360|7362',
+ 'code' => 'Navi-1x',
'process' => 'TSMC n7 (7nm)',
'years' => '2019-20',
},
{'arch' => 'RDNA-2',
- 'ids' => '13f9|1506|15e7|163f|164d|164e|1681|73a1|73a2|73a3|73a5|73ab|73ae|' .
- '73af|73bf|73c3|73ce|73df|73e0|73e1|73e3|73ef|73ff|7421|7422|7423|7424|743f',
+ 'ids' => '1435|1506|163f|164d|164e|1681|73a0|73a1|73a2|73a3|73a5|73ab|73ae|' .
+ '73af|73bf|73c0|73c1|73c3|73ce|73df|73e0|73e1|73e3|73ef|73ff|7420|7421|7422|' .
+ '7423|7424|743f',
'code' => 'Navi-2x',
'process' => 'TSMC n7 (7nm)',
'years' => '2020-22',
},
{'arch' => 'RDNA-3',
- 'ids' => '15bf|164f',
+ 'ids' => '73a8|73c4|73c5|73c8|7448|744c|745e|7460|7461|7470|7478|747e',
'code' => 'Navi-3x',
'process' => 'TSMC n5 (5nm)',
'years' => '2022+',
},
+ {'arch' => 'RDNA-3',
+ 'ids' => '73f0|7480|7481|7483|7487|7489|748b|749f',
+ 'code' => 'Navi-33',-
+ 'process' => 'TSMC n6 (6nm)',
+ 'years' => '2023+',
+ },
+ {'arch' => 'RDNA-3',
+ 'ids' => '15bf|15c8|164f|1900|1901',
+ 'code' => 'Phoenix',
+ 'process' => 'TSMC n4 (4nm)',
+ 'years' => '2023+',
+ },
{'arch' => 'CDNA-1',
'ids' => '7388|738c|738e',
'code' => 'Instinct-MI1xx',
@@ -16266,11 +17925,18 @@ sub set_amd_data {
{'arch' => 'CDNA-2',
'ids' => '7408|740c|740f',
'code' => 'Instinct-MI2xx',
- 'process' => 'TSMC n6 (7nm)',
+ 'process' => 'TSMC n6 (6nm)',
'years' => '2021-22+',
},
+ {'arch' => 'CDNA-3',
+ 'ids' => '74a0|74a1',
+ 'code' => 'Instinct-MI3xx',
+ 'process' => 'TSMC n5 (5nm)',
+ 'years' => '2023+',
+ },
];
}
+
sub set_intel_data {
$gpu_intel = [
{'arch' => 'Gen-1',
@@ -16344,97 +18010,125 @@ sub set_intel_data {
'years' => '2012-13',
},
{'arch' => 'Gen-6',
- 'ids' => '0102|0106|010b|010e|0112|0116|0122|0126|08cf',
- 'code' => '',
+ 'ids' => '0102|0106|010a|010b|010e|0112|0116|0122|0126|08cf',
+ 'code' => 'Sandybridge',
'process' => 'Intel 32nm',
'years' => '2011',
},
- {'arch' => 'Gen-7',
- 'ids' => '0152|0156|015a|015e|0162|0166|016a|0172|0176',
+ {'arch' => 'Gen-7.5',
+ 'ids' => '0402|0406|040a|040b|040e|0412|0416|041a|041b|041e|0422|0426|042a|' .
+ '042b|042e|0a02|0a06|0a0a|0a0b|0a0e|0a12|0a16|0a1a|0a1b|0a1e|0a22|0a26|0a2a|' .
+ '0a2b|0a2e|0c02|0c06|0c0a|0c0b|0c0e|0c12|0c16|0c1a|0c1b|0c1e|0c22|0c26|0c2a|' .
+ '0c2b|0c2e|0d02|0d06|0d0a|0d0b|0d0e|0d12|0d16|0d1a|0d1b|0d1e|0d22|0d26|0d2a|' .
+ '0d2b|0d2e',
'code' => '',
'process' => 'Intel 22nm',
- 'years' => '2012-13',
+ 'years' => '2013',
},
- {'arch' => 'Gen-7.5',
- 'ids' => '0406|041e|0a06|0a16|0a22|0a26|0a2a|0a2e',
+ {'arch' => 'Gen-7',
+ 'ids' => '0152|0155|0156|0157|015a|015e|0162|0166|016a|0172|0176|0f31|0f32|' .
+ '0f33',
'code' => '',
'process' => 'Intel 22nm',
- 'years' => '2013',
+ 'years' => '2012-13',
},
{'arch' => 'Gen-8',
- 'ids' => '1602|160a|160b|160d|160e|1612|1616|161a|161b|161d|161e|1622|1626|' .
- '162a|162b|162d|162e|1632|1636|163a|163b|163d|163e|22b0|22b1',
+ 'ids' => '1602|1606|160a|160b|160d|160e|1612|1616|161a|161b|161d|161e|1622|' .
+ '1626|162a|162b|162d|162e|1632|1636|163a|163b|163d|163e|22b0|22b1|22b2|22b3',
'code' => '',
'process' => 'Intel 14nm',
'years' => '2014-15',
},
- {'arch' => 'Gen-9',
- 'ids' => '1902|1906|190b|1912|1916|191b|191d|191e|1921|1923|1926|1927|192b|' .
- '192d|1932|193a|193b|193d|5a84|5a85',
- 'code' => '',
- 'process' => 'Intel 14n',
- 'years' => '2015-16',
- },
{'arch' => 'Gen-9.5',
- 'ids' => '3184|3185|3e90|3e91|3e92|3e93|3e94|3e96|3e98|3e9a|3e9b|3e9c|3ea0|' .
- '3ea1|3ea5|3ea6|3ea8|3ea9|5902|5906|590b|5912|5916|5917|591b|591c|591d|591e|' .
- '5921|5923|5926|5927|87c0|87ca|9b21|9b41|9ba4|9ba8|9baa|9bac|9bc4|9bc5|9bc6|' .
- '9bc8|9bca|9bcc|9be6|9bf6',
+ 'ids' => '3184|3185|3e90|3e91|3e92|3e93|3e94|3e96|3e98|3e99|3e9a|3e9b|3e9c|' .
+ '3ea0|3ea1|3ea2|3ea3|3ea4|3ea5|3ea6|3ea7|3ea8|3ea9|5902|5906|5908|590a|590b|' .
+ '590e|5912|5913|5915|5916|5917|591a|591b|591c|591d|591e|5921|5923|5926|5927|' .
+ '593b|87c0|87ca|9b21|9b41|9ba0|9ba2|9ba4|9ba5|9ba8|9baa|9bab|9bac|9bc0|9bc2|' .
+ '9bc4|9bc5|9bc6|9bc8|9bca|9bcb|9bcc|9be6|9bf6',
'code' => '',
'process' => 'Intel 14nm',
'years' => '2016-20',
},
+ {'arch' => 'Gen-9',
+ 'ids' => '0a84|1902|1906|190a|190b|190e|1912|1913|1915|1916|1917|191a|191b|' .
+ '191d|191e|1921|1923|1926|1927|192a|192b|192d|1932|193a|193b|193d|1a84|1a85|' .
+ '5a84|5a85',
+ 'code' => '',
+ 'process' => 'Intel 14n',
+ 'years' => '2015-16',
+ },
# gen10 was cancelled.,
{'arch' => 'Gen-11',
- 'ids' => '0d16|0d26|0d36|4555|4571|4e55|4e61|4e71|8a51|8a52|8a53|8a56|8a58|' .
- '8a5a|8a5c|9840|9841',
+ 'ids' => '0d16|0d26|0d36|4541|4551|4555|4557|4571|4e51|4e55|4e57|4e61|4e71|' .
+ '8a50|8a51|8a52|8a53|8a54|8a56|8a57|8a58|8a59|8a5a|8a5b|8a5c|8a5d|8a70|8a71|' .
+ '9840|9841',
'code' => '',
'process' => 'Intel 10nm',
'years' => '2019-21',
},
{'arch' => 'Gen-12.1',
- 'ids' => '4905|4908|4c8a|4c8b|4c90|4c9a|9a40|9a49|9a60|9a68|9a70|9a78',
+ 'ids' => '4905|4907|4908|4c80|4c8a|4c8b|4c8c|4c90|4c9a|9a40|9a49|9a59|9a60|' .
+ '9a68|9a70|9a78|9ac0|9ac9|9ad9|9af8',
'code' => '',
'process' => 'Intel 10nm',
'years' => '2020-21',
},
{'arch' => 'Gen-12.2',
'ids' => '4626|4628|462a|4636|4638|463a|4682|4688|468a|468b|4690|4692|4693|' .
- '46a3|46a6|46a8|46aa|46b0|46b1|46b3|46b6|46b8|46ba|46c1|46c3',
+ '46a3|46a6|46a8|46aa|46b0|46b1|46b3|46b6|46b8|46ba|46c1|46c3|46d0|46d1|46d2',
'code' => '',
'process' => 'Intel 10nm',
'years' => '2021-22+',
},
{'arch' => 'Gen-12.5',
- 'ids' => '',
- 'code' => 'Arctic Sound',
- 'pattern' => 'Arctic',
+ 'ids' => '0bd0|0bd5|0bd6|0bd7|0bd9|0bda|0bdb',
+ 'code' => '',
'process' => 'Intel 10nm',
- 'years' => '2021-22+',
+ 'years' => '2021-23+',
},
# Jupiter Sound cancelled?
{'arch' => 'Gen-12.7',
- 'ids' => '',
+ 'ids' => '4f80|4f81|4f82|4f83|4f84|4f85|4f86|4f87|4f88|5690|5691|5692|5693|' .
+ '5694|5695|5696|5697|5698|56a0|56a1|56a3|56a4|56a5|56a6|56a7|56a8|56a9|56b0|' .
+ '56b1|56b2|56b3|56ba|56bb|56bc|56bd',
'code' => 'Alchemist',
- 'pattern' => 'Alchemist|DG2|Arc A\d{3}M?',
+ 'process' => 'TSMC n6 (7nm)',
+ 'years' => '2022+',
+ },
+ {'arch' => 'Gen-12.7',
+ 'ids' => '56c0|56c1',
+ 'code' => '',
'process' => 'TSMC n6 (7nm)',
'years' => '2022+',
},
{'arch' => 'Gen-13',
- 'ids' => 'a780|a781|a782|a783|a788|a789|a78a|a78b',
+ 'ids' => 'a720|a721|a74d|a780|a781|a782|a783|a788|a789|a78a|a78b|a7a0|a7a1|' .
+ 'a7a8|a7a9|a7aa|a7ab|a7ac|a7ad',
'code' => '',
- 'pattern' => 'Raptor Lake',
- 'process' => 'Intel 7 (10nm)',
+ 'process' => 'Intel 7 (10nm)',
'years' => '2022+',
},
+ {'arch' => 'Gen-14',
+ 'ids' => '7d40|7d45|7d55|7d60|7dd5',
+ 'code' => '',
+ 'process' => 'Intel 4 (7nm+)',
+ 'years' => '2023+',
+ },
+ {'arch' => 'Gen-15',
+ 'ids' => '7d51|7d67|7dd1',
+ 'code' => '',
+ 'process' => 'TSMC 3nm',
+ 'years' => '2024+',
+ },
];
}
+
sub set_nv_data {
# this is vendor id: 12d2, nv1/riva/tnt type cards
# 0008|0009|0010|0018|0019
# and these are vendor id: 10de for 73.14
# 0020|0028|0029|002c|002d|00a0|0100|0101|0103|0150|0151|0152|0153
- my $status_eol = main::message('nv-legacy-eol');
+ # generic fallback if we don't have the actual EOL termination date
my $date = $self_date;
$date =~ s/-\d+$//;
my $status_current = main::message('nv-current',$date);
@@ -16450,7 +18144,7 @@ sub set_nv_data {
'process' => 'TSMC 220-350nm',
'release' => '71.86.15',
'series' => '71.86.xx',
- 'status' => $status_eol,
+ 'status' => main::message('nv-legacy-eol','2011-08-xx'),
'xorg' => '1.7',
'years' => '1998-2000',
},
@@ -16462,7 +18156,7 @@ sub set_nv_data {
'process' => 'TSMC 150-220nm',
'release' => '71.86.15',
'series' => '71.86.xx',
- 'status' => $status_eol,
+ 'status' => main::message('nv-legacy-eol','2011-08-xx'),
'xorg' => '1.7',
'years' => '1999-2005',
},
@@ -16475,7 +18169,7 @@ sub set_nv_data {
'process' => 'TSMC 150-220nm',
'release' => '96.43.23',
'series' => '96.43.xx',
- 'status' => $status_eol,
+ 'status' => main::message('nv-legacy-eol','2012-09-xx'),
'xorg' => '1.12',
'years' => '1999-2005',
},
@@ -16483,17 +18177,18 @@ sub set_nv_data {
'ids' => '0170|0171|0172|0173|0174|0175|0176|0177|0178|0179|017a|017c|017d|' .
'0181|0182|0183|0185|0188|018a|018b|018c|01f0|0200|0201|0202|0203|0250|0251|' .
'0253|0258|0259|025b|0280|0281|0282|0286|0288|0289|028c',
- 'code' => 'NV[12]x',
+ 'code' => 'NV2x',
'kernel' => '3.6',
'legacy' => 1,
'process' => 'TSMC 150nm',
'release' => '96.43.23',
'series' => '96.43.xx',
- 'status' => $status_eol,
+ 'status' => main::message('nv-legacy-eol','2012-09-xx'),
'xorg' => '1.12',
- 'years' => '2001-03',
+ 'years' => '2001-2003',
},
## Legacy 173.14.xx
+ # process: IBM 130, TSMC 130-150
{'arch' => 'Rankine',
'ids' => '00fa|00fb|00fc|00fd|00fe|0301|0302|0308|0309|0311|0312|0314|031a|' .
'031b|031c|0320|0321|0322|0323|0324|0325|0326|0327|0328|032a|032b|032c|032d|' .
@@ -16501,14 +18196,16 @@ sub set_nv_data {
'code' => 'NV3x',
'kernel' => '3.12',
'legacy' => 1,
- 'process' => '130-150nm', # IBM 130, TSMC 130-150
+ 'process' => '130-150nm',
'release' => '173.14.39',
'series' => '173.14.xx',
- 'status' => $status_eol,
+ 'status' => main::message('nv-legacy-eol','2013-12-xx'),
'xorg' => '1.15',
- 'years' => '2003-05',
+ 'years' => '2003-2005',
},
## Legacy 304.xx
+ # code: hard to get these, roughly MCP[567]x/NV4x/G7x
+ # process: IBM 130, TSMC 90-110
{'arch' => 'Curie',
'ids' => '0040|0041|0042|0043|0044|0045|0046|0047|0048|004e|0090|0091|0092|' .
'0093|0095|0098|0099|009d|00c0|00c1|00c2|00c3|00c8|00c9|00cc|00cd|00ce|00f1|' .
@@ -16519,18 +18216,20 @@ sub set_nv_data {
'0292|0293|0294|0295|0297|0298|0299|029a|029b|029c|029d|029e|029f|02e0|02e1|' .
'02e2|02e3|02e4|038b|0390|0391|0392|0393|0394|0395|0397|0398|0399|039c|039e|' .
'03d0|03d1|03d2|03d5|03d6|0531|0533|053a|053b|053e|07e0|07e1|07e2|07e3|07e5',
- 'code' => '', # hard to get these, roughly MCP[567]x/NV4x/G7x
+ 'code' => '',
'kernel' => '4.13',
'legacy' => 1,
- 'process' => '90-130nm', # IBM 130, TSMC 90-110
+ 'process' => '90-130nm',
'release' => '304.137',
'series' => '304.xx',
- 'status' => $status_eol,
+ 'status' => main::message('nv-legacy-eol','2017-09-xx'),
'xorg' => '1.19',
- 'years' => '2003-13',
+ 'years' => '2003-2013',
},
## Legacy 340.xx
# these are both Tesla and Tesla 2.0
+ # code: not clear, 8800/GT2xx/maybe G7x
+ # years: 2006-2010 Tesla 2007-2013 Tesla 2.0
{'arch' => 'Tesla',
'ids' => '0191|0193|0194|0197|019d|019e|0400|0401|0402|0403|0404|0405|0406|' .
'0407|0408|0409|040a|040b|040c|040d|040e|040f|0410|0420|0421|0422|0423|0424|' .
@@ -16549,28 +18248,28 @@ sub set_nv_data {
'0a65|0a66|0a67|0a68|0a69|0a6a|0a6c|0a6e|0a6f|0a70|0a71|0a72|0a73|0a74|0a75|' .
'0a76|0a78|0a7a|0a7c|0ca0|0ca2|0ca3|0ca4|0ca5|0ca7|0ca8|0ca9|0cac|0caf|0cb0|' .
'0cb1|0cbc|10c0|10c3|10c5|10d8',
- 'code' => '', # not clear, 8800/GT2xx/maybe G7x
+ 'code' => '',
'kernel' => '5.4',
'legacy' => 1,
'process' => '40-80nm',
'release' => '340.108',
'series' => '340.xx',
- 'status' => $status_eol,
+ 'status' => main::message('nv-legacy-eol','2019-12-xx'),
'xorg' => '1.20',
- 'years' => '2006-13',
+ 'years' => '2006-2013',
},
## Legacy 367.xx
{'arch' => 'Kepler',
'ids' => '0fef|0ff2|11bf',
'code' => 'GKxxx',
- 'kernel' => '',
+ 'kernel' => '5.4',
'legacy' => 1,
'process' => 'TSMC 28nm',
'release' => '',
'series' => '367.xx',
- 'status' => main::message('nv-legacy-active','late 2022'),
- 'xorg' => '',
- 'years' => '2012-18',
+ 'status' => main::message('nv-legacy-eol','2017'),
+ 'xorg' => '1.20',
+ 'years' => '2012-2018',
},
## Legacy 390.xx
# this is Fermi, Fermi 2.0
@@ -16585,14 +18284,14 @@ sub set_nv_data {
'1207|1208|1210|1211|1212|1213|1241|1243|1244|1245|1246|1247|1248|1249|124b|' .
'124d|1251',
'code' => 'GF1xx',
- 'kernel' => '',
+ 'kernel' => '6.0',
'legacy' => 1,
'process' => '40/28nm',
- 'release' => '',
+ 'release' => '390.157',
'series' => '390.xx+',
- 'status' => main::message('nv-legacy-active','late 2022'),
- 'xorg' => '',
- 'years' => '2010-16',
+ 'status' => main::message('nv-legacy-eol','2022-11-22'),
+ 'xorg' => '1.21',
+ 'years' => '2010-2016',
},
## Legacy 470.xx
{'arch' => 'Fermi 2',
@@ -16603,10 +18302,12 @@ sub set_nv_data {
'process' => 'TSMC 28nm',
'release' => '',
'series' => '470.xx+',
- 'status' => main::message('nv-legacy-active','2023/24'),
+ 'status' => main::message('nv-legacy-active','2024-09-xx'),
'xorg' => '',
- 'years' => '2010-16',
+ 'years' => '2010-2016',
},
+ # GT 720M and 805A/810A are the same cpu id.
+ # years: 2012-2018 Kepler 2013-2015 Kepler 2.0
{'arch' => 'Kepler',
'ids' => '0fc6|0fc8|0fc9|0fcd|0fce|0fd1|0fd2|0fd3|0fd4|0fd5|0fd8|0fd9|0fdf|' .
'0fe0|0fe1|0fe2|0fe3|0fe4|0fe9|0fea|0fed|0fee|0ff6|0ff8|0ff9|0ffa|0ffb|0ffc|' .
@@ -16622,9 +18323,9 @@ sub set_nv_data {
'process' => 'TSMC 28nm',
'release' => '',
'series' => '470.xx+',
- 'status' => main::message('nv-legacy-active','2023/24'),
+ 'status' => main::message('nv-legacy-active','2024-09-xx'),
'xorg' => '',
- 'years' => '2012-18',
+ 'years' => '2012-2018',
},
## Current Active Series
# load microarch data, as stuff goes legacy, these will form new legacy items.
@@ -16633,35 +18334,45 @@ sub set_nv_data {
'1380|1381|1382|1390|1391|1392|1393|1398|1399|139a|139b|139c|139d|13b0|13b1|' .
'13b2|13b3|13b4|13b6|13b9|13ba|13bb|13bc|13c0|13c2|13d7|13d8|13d9|13da|13f0|' .
'13f1|13f2|13f3|13f8|13f9|13fa|13fb|1401|1402|1406|1407|1427|1430|1431|1436|' .
- '1617|1618|1619|161a|1667|174d|174e|179c|17c8|17f0|17f1|17fd|1c8c|1c8d|1c90|' .
- '1c91|1d10|1d12|1e91|1ed1|1ed3|1f14|1f54',
+ '1617|1618|1619|161a|1667|174d|174e|179c|17c8|17f0|17f1|17fd|1c90|1d10|1d12',
'code' => 'GMxxx',
+ 'kernel' => '',
+ 'legacy' => 0,
'process' => 'TSMC 28nm',
- 'series' => '520.xx+',
- 'status' => $status_current,
- 'years' => '2014-19',
+ 'release' => '',
+ 'series' => '545.xx+',
+ 'status' => main::message('nv-current-eol',$date,'2026-12-xx'),
+ 'xorg' => '',
+ 'years' => '2014-2019',
},
{'arch' => 'Pascal',
'ids' => '15f0|15f7|15f8|15f9|17c2|1b00|1b02|1b06|1b30|1b38|1b80|1b81|1b82|' .
- '1b83|1b84|1b87|1ba0|1ba1|1ba2|1bb0|1bb1|1bb4|1bb5|1bb6|1bb7|1bb8|1bb9|1bbb|' .
- '1bc7|1be0|1be1|1c02|1c03|1c04|1c06|1c07|1c09|1c20|1c21|1c22|1c23|1c30|1c31|' .
- '1c60|1c61|1c62|1c81|1c82|1c83|1c8c|1c8d|1c8f|1c90|1c91|1c92|1c94|1c96|1cb1|' .
- '1cb2|1cb3|1cb6|1cba|1cbb|1cbc|1cbd|1cfa|1cfb|1d01|1d02|1d11|1d13|1d16|1d33|' .
- '1d34|1d52',
+ '1b83|1b84|1b87|1ba0|1ba1|1ba2|1bb0|1bb1|1bb3|1bb4|1bb5|1bb6|1bb7|1bb8|1bb9|' .
+ '1bbb|1bc7|1be0|1be1|1c02|1c03|1c04|1c06|1c07|1c09|1c20|1c21|1c22|1c23|1c30|' .
+ '1c31|1c60|1c61|1c62|1c81|1c82|1c83|1c8c|1c8d|1c8f|1c90|1c91|1c92|1c94|1c96|' .
+ '1cb1|1cb2|1cb3|1cb6|1cba|1cbb|1cbc|1cbd|1cfa|1cfb|1d01|1d02|1d11|1d13|1d16|' .
+ '1d33|1d34|1d52',
'code' => 'GP10x',
+ 'kernel' => '',
+ 'legacy' => 0,
'process' => 'TSMC 16nm',
- 'series' => '520.xx+',
- 'status' => $status_current,
- 'years' => '2016-21',
+ 'release' => '',
+ 'series' => '545.xx+',
+ 'status' => main::message('nv-current-eol',$date,'2026-12-xx'),
+ 'xorg' => '',
+ 'years' => '2016-2021',
},
{'arch' => 'Volta',
- 'ids' => '1d81|1db1|1db3|1db4|1db5|1db6|1db7|1db8|1dba|1df0|1df2|1df6|1fb0|' .
- '20b0|20b3|20b6',
+ 'ids' => '1d81|1db1|1db3|1db4|1db5|1db6|1db7|1db8|1dba|1df0|1df2|1df6|1fb0',
'code' => 'GV1xx',
+ 'kernel' => '',
+ 'legacy' => 0,
'process' => 'TSMC 12nm',
- 'series' => '520.xx+',
- 'status' => $status_current,
- 'years' => '2017-20',
+ 'release' => '',
+ 'series' => '545.xx+',
+ 'status' => main::message('nv-current-eol',$date,'2026-12-xx'),
+ 'xorg' => '',
+ 'years' => '2017-2020',
},
{'arch' => 'Turing',
'ids' => '1e02|1e04|1e07|1e09|1e30|1e36|1e78|1e81|1e82|1e84|1e87|1e89|1e90|' .
@@ -16669,45 +18380,64 @@ sub set_nv_data {
'1f07|1f08|1f0a|1f0b|1f10|1f11|1f12|1f14|1f15|1f36|1f42|1f47|1f50|1f51|1f54|' .
'1f55|1f76|1f82|1f83|1f91|1f95|1f96|1f97|1f98|1f99|1f9c|1f9d|1f9f|1fa0|1fb0|' .
'1fb1|1fb2|1fb6|1fb7|1fb8|1fb9|1fba|1fbb|1fbc|1fdd|1ff0|1ff2|1ff9|2182|2184|' .
- '2187|2188|2189|2191|2192|21c4|21d1|25a6|25a7|25a9|25aa',
+ '2187|2188|2189|2191|2192|21c4|21d1|25a6|25a7|25a9|25aa|25ad|25ed|28b8|28f8',
'code' => 'TUxxx',
- 'process' => 'TSMC 12nm',
- 'series' => '520.xx+',
- 'status' => $status_current,
- 'years' => '2018-22',
+ 'kernel' => '',
+ 'legacy' => 0,
+ 'process' => 'TSMC 12nm FF',
+ 'release' => '',
+ 'series' => '545.xx+',
+ 'status' => main::message('nv-current-eol',$date,'2026-12-xx'),
+ 'xorg' => '',
+ 'years' => '2018-2022',
},
{'arch' => 'Ampere',
- 'ids' => '20b0|20b2|20b5|20b7|20f1|2203|2204|2206|2207|2208|220a|220d|2216|' .
- '2230|2231|2232|2233|2235|2236|2237|2238|2414|2420|2438|2460|2482|2484|2486|' .
- '2487|2488|2489|248a|249c|249d|24a0|24b0|24b1|24b6|24b7|24b8|24b9|24ba|24bb|' .
- '24c9|24dc|24dd|24e0|24fa|2503|2504|2507|2508|2520|2521|2523|2531|2544|2560|' .
- '2563|2571|25a0|25a2|25a5|25b6|25b8|25b9|25ba|25bb|25e0|25e2|25e5|25f9|25fa',
+ 'ids' => '20b0|20b2|20b3|20b5|20b6|20b7|20bd|20f1|20f3|20f5|20f6|20fd|2203|' .
+ '2204|2206|2207|2208|220a|220d|2216|2230|2231|2232|2233|2235|2236|2237|2238|' .
+ '2414|2420|2438|2460|2482|2484|2486|2487|2488|2489|248a|249c|249d|24a0|24b0|' .
+ '24b1|24b6|24b7|24b8|24b9|24ba|24bb|24c7|24c9|24dc|24dd|24e0|24fa|2503|2504|' .
+ '2507|2508|2520|2521|2523|2531|2544|2560|2563|2571|2582|25a0|25a2|25a5|25ab|' .
+ '25ac|25b6|25b8|25b9|25ba|25bb|25bc|25bd|25e0|25e2|25e5|25ec|25f9|25fa|25fb|' .
+ '2838',
'code' => 'GAxxx',
+ 'kernel' => '',
+ 'legacy' => 0,
'process' => 'TSMC n7 (7nm)',
- 'series' => '520.xx+',
- 'status' => $status_current,
- 'years' => '2020-22',
+ 'release' => '',
+ 'series' => '545.xx+',
+ 'status' => main::message('nv-current-eol',$date,'2026-12-xx'),
+ 'xorg' => '',
+ 'years' => '2020-2023',
},
{'arch' => 'Hopper',
- 'ids' => '2331',
+ 'ids' => '2321|2322|2324|2330|2331|2339|233a|2342',
'code' => 'GH1xx',
- 'pattern' => '\bG?H[12]\d{2}',
+ 'kernel' => '',
+ 'legacy' => 0,
'process' => 'TSMC n4 (5nm)',
- 'series' => '520.xx+',
+ 'release' => '',
+ 'series' => '545.xx+',
'status' => $status_current,
+ 'xorg' => '',
'years' => '2022+',
},
{'arch' => 'Lovelace',
- 'ids' => '2684',
+ 'ids' => '2684|2685|26b1|26b2|26b3|26b5|26b9|26ba|2704|2705|2717|2730|2757|' .
+ '2770|2782|2783|2786|27a0|27b0|27b1|27b2|27b6|27b8|27ba|27bb|27e0|27fb|2803|' .
+ '2805|2820|2860|2882|28a0|28a1|28e0|28e1',
'code' => 'AD1xx',
- 'pattern' => '\bG?L\d{1,4}|\bAD1\d{2}|RTX [6-8]0\d{2}',
+ 'kernel' => '',
+ 'legacy' => 0,
'process' => 'TSMC n4 (5nm)',
- 'series' => '520.xx+',
+ 'release' => '',
+ 'series' => '545.xx+',
'status' => $status_current,
- 'years' => '2022-23+',
+ 'xorg' => '',
+ 'years' => '2022+',
},
- ];
+ ],
}
+
sub gpu_data {
eval $start if $b_log;
my ($v_id,$p_id,$name) = @_;
@@ -16729,6 +18459,7 @@ sub gpu_data {
eval $end if $b_log;
return ($gpu_data,$b_nv);
}
+
sub get_gpu_data {
eval $start if $b_log;
my ($gpu,$p_id,$name) = @_;
@@ -16769,7 +18500,7 @@ sub set_monitors_sys {
eval $start if $b_log;
my $pattern = '/sys/class/drm/card[0-9]/device/driver/module/drivers/*';
my @cards_glob = main::globber($pattern);
- $pattern = '/sys/class/drm/card*-*/{edid,enabled,status,modes}';
+ $pattern = '/sys/class/drm/card*-*/{connector_id,edid,enabled,status,modes}';
my @ports_glob = main::globber($pattern);
# print Data::Dumper::Dumper \@cards_glob;
# print Data::Dumper::Dumper \@ports_glob;
@@ -16803,6 +18534,9 @@ sub set_monitors_sys {
# print "$file\n";
$monitor_ids->{$port}{$item} = main::reader($file,'strip',0);
}
+ elsif ($item eq 'connector_id'){
+ $monitor_ids->{$port}{'connector-id'} = main::reader($file,'strip',0);
+ }
# arm: U:1680x1050p-0
elsif ($item eq 'modes'){
@data = main::reader($file,'strip');
@@ -16820,6 +18554,7 @@ sub set_monitors_sys {
print 'monitor_sys_data(): ', Data::Dumper::Dumper $monitor_ids if $dbg[44];
eval $end if $b_log;
}
+
sub monitor_edid_data {
eval $start if $b_log;
my ($file,$port) = @_;
@@ -16869,8 +18604,12 @@ sub monitor_edid_data {
$monitor_ids->{$port}{'ratio'} = join(', ', @{$edid->{'ratios'}});
}
if ($edid->{'detailed_timings'}){
- $monitor_ids->{$port}{'res-x'} = $edid->{'detailed_timings'}[0]{'horizontal_active'};
- $monitor_ids->{$port}{'res-y'} = $edid->{'detailed_timings'}[0]{'vertical_active'};
+ if ($edid->{'detailed_timings'}[0]{'horizontal_active'}){
+ $monitor_ids->{$port}{'res-x'} = $edid->{'detailed_timings'}[0]{'horizontal_active'};
+ }
+ if ($edid->{'detailed_timings'}[0]{'vertical_active'}){
+ $monitor_ids->{$port}{'res-y'} = $edid->{'detailed_timings'}[0]{'vertical_active'};
+ }
if ($edid->{'detailed_timings'}[0]{'horizontal_image_size'}){
$monitor_ids->{$port}{'size-x'} = $edid->{'detailed_timings'}[0]{'horizontal_image_size'};
$monitor_ids->{$port}{'size-x-i'} = $edid->{'detailed_timings'}[0]{'horizontal_image_size_i'};
@@ -16902,6 +18641,7 @@ sub monitor_edid_data {
}
eval $end if $b_log;
}
+
sub advanced_monitor_data {
eval $start if $b_log;
my ($monitors,$layouts) = @_;
@@ -16996,7 +18736,8 @@ sub advanced_monitor_data {
print Data::Dumper::Dumper $monitors if $dbg[45];
eval $end if $b_log;
}
-# clear out all disabled or not connected monitor ports
+
+# Clear out all disabled or not connected monitor ports
sub set_active_monitors {
eval $start if $b_log;
foreach my $key (keys %$monitor_ids){
@@ -17008,6 +18749,7 @@ sub set_active_monitors {
# print 'active monitors: ', Data::Dumper::Dumper $monitor_ids;
eval $end if $b_log;
}
+
sub get_monitor_position {
eval $start if $b_log;
my ($monitor,$horiz,$vert) = @_;
@@ -17031,6 +18773,7 @@ sub get_monitor_position {
eval $end if $b_log;
return $position;
}
+
sub set_monitor_layouts {
my ($layouts) = @_;
$layouts->[1][2] = {'1-1' => 'left','1-2' => 'right'};
@@ -17050,17 +18793,23 @@ sub set_monitor_layouts {
'2-1' => 'middle-l','2-2' => 'middle-c','2-3' => 'middle-r',
'3-1' => 'bottom-l','3-2' => 'bottom-c','3-3' => 'bottom-r'};
}
-# this is required to resolve the situation where some xorg drivers change
+
+# This is required to resolve the situation where some xorg drivers change
# the kernel ID for the port to something slightly different, amdgpu in particular.
+# Note: connector_id if available from xrandr and /sys allow for matching.
sub map_monitor_ids {
eval $start if $b_log;
my ($display_ids) = @_;
return if !$monitor_ids;
my (@sys_ids,@unmatched_display,@unmatched_sys);
- @unmatched_display = @$display_ids = sort { lc($a) cmp lc($b) } @$display_ids;
- foreach my $key (keys %$monitor_ids){
+ @$display_ids = sort {lc($a->[0]) cmp lc($b->[0])} @$display_ids;
+ foreach my $d_id (@$display_ids){
+ push(@unmatched_display,$d_id->[0]);
+ }
+ foreach my $key (sort keys %$monitor_ids){
if ($monitor_ids->{$key}{'status'} eq 'connected'){
- push(@sys_ids,$key);
+ push(@sys_ids,[$key,$monitor_ids->{$key}{'connector-id'}]);
+ push(@unmatched_sys,$key);
}
}
# @sys_ids = ('DVI-I-1','eDP-1','VGA-1');
@@ -17069,28 +18818,42 @@ sub map_monitor_ids {
print 'sys: ', Data::Dumper::Dumper \@sys_ids if $dbg[45];
print 'display: ', Data::Dumper::Dumper $display_ids if $dbg[45];
return if scalar @sys_ids != scalar @$display_ids;
- @unmatched_sys = @sys_ids = sort { lc($a) cmp lc($b) } @sys_ids;
$monitor_map = {};
# known patterns: s: DP-1 d: DisplayPort-0; s: DP-1 d: DP1-1; s: DP-2 d: DP1-2;
# s: HDMI-A-2 d: HDMI-A-1; s: HDMI-A-2 d: HDMI-2; s: DVI-1 d: DVI1; s: HDMI-1 d: HDMI1
# s: DVI-I-1 d: DVI0; s: VGA-1 d: VGA1; s: DP-1-1; d: DP-1-1;
# s: eDP-1 d: eDP-1-1 (yes, reversed from normal deviation!); s: eDP-1 d: eDP
# worst: s: DP-6 d: DP-2-3 (2 banks of 3 according to X); s: eDP-1 d: DP-4;
+ # s: DP-3 d: DP-1-1; s: DP-4 d: DP-1-2
# s: DP-3 d: DP-4 [yes, +1, not -];
my ($d_1,$d_2,$d_m,$s_1,$s_2,$s_m);
my $b_single = (scalar @sys_ids == 1) ? 1 : 0;
my $pattern = '([A-Z]+)(-[A-Z]-\d+-\d+|-[A-Z]-\d+|-?\d+-\d+|-?\d+|)';
for (my $i=0; $i < scalar @$display_ids; $i++){
- print "s: $sys_ids[$i] d: $display_ids->[$i]\n" if $dbg[45];
+ print "s: $sys_ids[$i]->[0] d: $display_ids->[$i][0]\n" if $dbg[45];
+ my $b_match;
+ # we're going for the connector match first
+ if ($display_ids->[$i][1]){
+ # for off case where they did not sort to same order
+ foreach my $sys (@sys_ids){
+ if (defined $sys->[1] && $sys->[1] == $display_ids->[$i][1]){
+ $b_match = 1;
+ $monitor_map->{$display_ids->[$i][0]} = $sys->[0];
+ @unmatched_display = grep {$_ ne $display_ids->[$i][0]} @unmatched_display;
+ @unmatched_sys = grep {$_ ne $sys->[0]} @unmatched_sys;
+ last;
+ }
+ }
+ }
# try 1: /^([A-Z]+)(-[AB]|-[ADI]|-[ADI]-\d+?|-\d+?)?(-)?(\d+)$/i
- if ($display_ids->[$i] =~ /^$pattern$/i){
+ if (!$b_match && $display_ids->[$i][0] =~ /^$pattern$/i){
$d_1 = $1;
$d_2 = ($2) ? $2 : '';
$d_2 =~ /(\d+)?$/;
$d_m = ($1) ? $1 : 0;
$d_1 =~ s/^DisplayPort/DP/i; # amdgpu...
print " d1: $d_1 d2: $d_2 d3: $d_m\n" if $dbg[45];
- if ($sys_ids[$i] =~ /^$pattern$/i){
+ if ($sys_ids[$i]->[0] =~ /^$pattern$/i){
$s_1 = $1;
$s_2 = ($2) ? $2 : '';
$s_2 =~ /(\d+)?$/;
@@ -17098,21 +18861,21 @@ sub map_monitor_ids {
$d_1 = $s_1 if uc($d_1) eq 'XWAYLAND';
print " d1: $d_1 s1: $s_1 dm: $d_m sm: $s_m \n" if $dbg[45];
if ($d_1 eq $s_1 && ($d_m == $s_m || $d_m == ($s_m - 1))){
- $monitor_map->{$display_ids->[$i]} = $sys_ids[$i];
- @unmatched_display = grep {$_ ne $display_ids->[$i]} @unmatched_display;
- @unmatched_sys = grep {$_ ne $sys_ids[$i]} @unmatched_sys;
+ $monitor_map->{$display_ids->[$i][0]} = $sys_ids[$i]->[0];
+ @unmatched_display = grep {$_ ne $display_ids->[$i][0]} @unmatched_display;
+ @unmatched_sys = grep {$_ ne $sys_ids[$i]->[0]} @unmatched_sys;
}
}
}
# in case of one unmatched, we'll dump this, and use the actual unmatched
- if (!$monitor_map->{$display_ids->[$i]}){
+ if (!$b_match && !$monitor_map->{$display_ids->[$i][0]}){
# we're not even going to try, if there's 1 sys and 1 display, just use it!
if ($b_single){
- $monitor_map->{$display_ids->[$i]} = $sys_ids[$i];
+ $monitor_map->{$display_ids->[$i][0]} = $sys_ids[$i]->[0];
(@unmatched_display,@unmatched_sys) = ();
}
else {
- $monitor_map->{$display_ids->[$i]} = main::message('monitor-id');
+ $monitor_map->{$display_ids->[$i][0]} = main::message('monitor-id');
}
}
}
@@ -17129,7 +18892,7 @@ sub map_monitor_ids {
eval $end if $b_log;
}
-# handle case of monitor on left or right edge, vertical that is.
+# Handle case of monitor on left or right edge, vertical that is.
# mm dimensiions are based on the default position of monitor as sold.
# very old systems may not have non 0 value for size x or y
# size, res x,y by reference
@@ -17142,55 +18905,57 @@ sub flip_size_x_y {
}
eval $end if $b_log;
}
+
## COMPOSITOR DATA ##
sub set_compositor_data {
eval $start if $b_log;
my $compositors = get_compositors();
if (@$compositors){
+ # these use different spelling or command for full data.
+ my %custom = (
+ 'hyprland' => 'hyprctl',
+ );
my @data;
foreach my $compositor (@$compositors){
# gnome-shell is incredibly slow to return version
- if (($extra > 1 || $graphics{'protocol'} eq 'wayland') &&
+ if (($extra > 1 || $graphics{'protocol'} eq 'wayland' || $b_android) &&
(!$show{'system'} || $compositor ne 'gnome-shell')){
+ my $comp_lc = lc($compositor);
$graphics{'compositors'} = [] if !$graphics{'compositors'};
- push(@{$graphics{'compositors'}},[main::program_data($compositor,$compositor)]);
+ # if -S found wm/comp, this is already set so no need to run version again
+ # note: -Sxxx shows wm v:, but -Gxx OR WL shows comp + v.
+ if (!$comps{$comp_lc} || ($extra < 3 && !$comps{$comp_lc}->[1])){
+ my $comp = ($custom{$comp_lc}) ? $custom{$comp_lc}: $compositor;
+ push(@{$graphics{'compositors'}},[ProgramData::full($comp)]);
+ }
+ else {
+ push(@{$graphics{'compositors'}},$comps{$comp_lc}); # already array ref
+ }
}
else {
$graphics{'compositors'} = [] if !$graphics{'compositors'};
- push(@{$graphics{'compositors'}},[(main::program_values($compositor))[3]]);
+ push(@{$graphics{'compositors'}},[(ProgramData::values($compositor))[3]]);
}
}
}
eval $end if $b_log;
}
+
sub get_compositors {
eval $start if $b_log;
- my $found = [];
- main::set_ps_gui() if !$loaded{'ps-gui'};
- if (@ps_gui){
- # ORDER MATTES!
- # notes: compiz: debian package compiz-core;
- # enlightenment: as of version 20 wayland compositor
- my @compositors = qw(budgie-wm compiz compton enlightenment gnome-shell
- kwin_wayland kwin_x11 kwinft marco muffin mutter);
- # these are more obscure, so check for them after primary common ones
- push (@compositors,qw(3dwm dcompmgr gala kmscon metisse mir moblin
- monsterwm picom ukwm unagi unity-system-compositor xcompmgr xfwm4
- xfwm5 xfwm));
- my $matches = join('|',@compositors) . $wl_compositors;
- foreach my $psg (@ps_gui){
- if ($psg =~ /^($matches)$/){
- push(@$found,$1);
- }
- }
- }
- main::log_data('dump','$found compositors:', $found) if $b_log;
+ PsData::set_de_wm() if !$loaded{'ps-gui'};
+ my $comps = [];
+ push(@$comps,@{$ps_data{'compositors-pure'}}) if @{$ps_data{'compositors-pure'}};
+ push(@$comps,@{$ps_data{'de-wm-compositors'}}) if @{$ps_data{'de-wm-compositors'}};
+ push(@$comps,@{$ps_data{'wm-compositors'}}) if @{$ps_data{'wm-compositors'}};
+ @$comps = sort(@$comps) if @$comps;
+ main::log_data('dump','$comps:', $comps) if $b_log;
eval $end if $b_log;
- return $found;
+ return $comps;
}
## UTILITIES ##
-sub tty_data(){
+sub tty_data {
eval $start if $b_log;
my ($tty);
if ($size{'term-cols'}){
@@ -17273,6 +19038,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub general_output {
eval $start if $b_log;
my ($rows,$general_data) = @_;
@@ -17299,6 +19065,7 @@ sub general_output {
}
eval $end if $b_log;
}
+
sub lvm_output {
eval $start if $b_log;
my ($rows,$lvm_data) = @_;
@@ -17362,6 +19129,7 @@ sub components_output {
$rows->[$$j]{main::key($$num++,1,$l1,'Components')} = $status;
components_recursive_output($type,$j,$num,$rows,$components,0,'c','p');
}
+
sub components_recursive_output {
my ($type,$j,$num,$rows,$components,$indent,$c,$p) = @_;
my ($l,$m,$size) = (1,1,0);
@@ -17402,7 +19170,7 @@ sub components_recursive_output {
}
}
-# note: type dm is seen in only one dataset, but it's a start
+# Note: type dm is seen in only one dataset, but it's a start
sub general_data {
eval $start if $b_log;
my (@found,$parent,$parent_fs);
@@ -17462,7 +19230,7 @@ sub general_data {
return $general_data;
}
-# note: called for disk totals, raid, and logical
+# Note: called for disk totals, raid, and logical
sub lvm_data {
eval $start if $b_log;
$loaded{'logical-data'} = 1;
@@ -17475,7 +19243,7 @@ sub lvm_data {
PartitionData::set() if !$loaded{'partition-data'};
main::set_mapper() if !$loaded{'mapper'};
if ($fake{'logical'}){
- # my $file = "$fake_data_dir/lvm/lvs-test-1.txt";
+ # my $file = "$fake_data_dir/raid-logical/lvm/lvs-test-1.txt";
# @data = main::reader($file,'strip');
}
else {
@@ -17484,10 +19252,9 @@ sub lvm_data {
# 2>/dev/null -unit k ---separator ^:
my $cmd = $alerts{'lvs'}->{'path'};
$cmd .= ' -aPv --unit k --separator "^:" --segments --noheadings -o ';
- # $cmd .= ' -o +lv_size,pv_major,pv_minor 2>/dev/null';
- $cmd .= join(',', @args);
- $cmd .= ' 2>/dev/null';
- @data = main::grabber("$cmd",'','strip');
+ # $cmd .= ' -o +lv_size,pv_major,pv_minor 2>/dev/null';
+ $cmd .= join(',', @args) . ' 2>/dev/null';
+ @data = main::grabber($cmd,'','strip');
main::log_data('dump','lvm @data', \@data) if $b_log;
print "command: $cmd\n" if $dbg[22];
}
@@ -17510,6 +19277,7 @@ sub lvm_data {
print Data::Dumper::Dumper \@lvm if $dbg[22];
eval $end if $b_log;
}
+
sub process_lvm_data {
eval $start if $b_log;
my $processed = {};
@@ -17547,10 +19315,12 @@ sub process_lvm_data {
eval $end if $b_log;
return $processed;
}
+
sub component_data {
my ($maj_min,$full_components) = @_;
push(@$full_components, component_recursive_data($maj_min));
}
+
sub component_recursive_data {
eval $start if $b_log;
my ($maj_min) = @_;
@@ -17577,7 +19347,9 @@ sub component_recursive_data {
}
## MachineItem
+# public methods: get(), is_vm()
{
+my $b_vm;
package MachineItem;
sub get {
@@ -17612,7 +19384,7 @@ sub get {
}
}
}
- elsif (-d '/sys/class/dmi/id/'){
+ elsif (!$fake{'elbrus'} && -d '/sys/class/dmi/id/'){
$data = machine_data_sys();
if (%$data){
machine_output($rows,$data);
@@ -17657,13 +19429,19 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
+sub is_vm {
+ return $b_vm;
+}
+
## keys for machine data are:
-# 0-sys_vendor 1-product_name 2-product_version 3-product_serial 4-product_uuid
-# 5-board_vendor 6-board_name 7-board_version 8-board_serial
-# 9-bios_vendor 10-bios_version 11-bios_date
+# bios_vendor; bios_version; bios_date;
+# board_name; board_serial; board_sku; board_vendor; board_version;
+# product_name; product_version; product_serial; product_sku; product_uuid;
+# sys_vendor;
## with extra data:
-# 12-chassis_vendor 13-chassis_type 14-chassis_version 15-chassis_serial
-## unused: 16-bios_rev 17-bios_romsize 18 - firmware type
+# chassis_serial; chassis_type; chassis_vendor; chassis_version;
+## unused: bios_rev; bios_romsize; firmware type
sub machine_output {
eval $start if $b_log;
my ($rows,$data) = @_;
@@ -17674,9 +19452,9 @@ sub machine_output {
my ($bios_date,$bios_rev,$bios_romsize,$bios_vendor,$bios_version,$chassis_serial,
$chassis_type,$chassis_vendor,$chassis_version,$mobo_model,$mobo_serial,$mobo_vendor,
$mobo_version,$product_name,$product_serial,$product_version,$system_vendor);
-# foreach my $key (keys %data){
-# print "$key: $data->{$key}\n";
-# }
+ # foreach my $key (keys %data){
+ # print "$key: $data->{$key}\n";
+ # }
if (!$data->{'sys_vendor'} ||
($data->{'board_vendor'} && $data->{'sys_vendor'} eq $data->{'board_vendor'} &&
!$data->{'product_name'} && !$data->{'product_version'} &&
@@ -17777,8 +19555,14 @@ sub machine_output {
$rows->[$j]{main::key($num++,0,3,'v')} = $mobo_version;
}
$rows->[$j]{main::key($num++,0,3,'serial')} = $mobo_serial;
- if ($extra > 2 && $data->{'board_uuid'}){
- $rows->[$j]{main::key($num++,0,3,'uuid')} = $data->{'board_uuid'};
+ if ($extra > 1 && $data->{'product_sku'}){
+ $rows->[$j]{main::key($num++,0,3,'part-nu')} = $data->{'product_sku'};
+ }
+ if (($show{'uuid'} || $extra > 2) &&
+ ($data->{'product_uuid'} || $data->{'board_uuid'})){
+ my $uuid = ($data->{'product_uuid'}) ? $data->{'product_uuid'} : $data->{'board_uuid'};
+ $uuid = main::filter($uuid,'filter-uuid');
+ $rows->[$j]{main::key($num++,0,3,'uuid')} = $uuid;
}
if ($extra > 1 && $data->{'board_mfg_date'}){
$rows->[$j]{main::key($num++,0,3,'mfg-date')} = $data->{'board_mfg_date'};
@@ -17794,6 +19578,7 @@ sub machine_output {
}
eval $end if $b_log;
}
+
sub machine_soc_output {
my ($rows,$soc_machine) = @_;
my ($key);
@@ -17830,21 +19615,20 @@ sub machine_soc_output {
}
eval $end if $b_log;
}
+
sub machine_data_fruid {
eval $start if $b_log;
my ($program) = @_;
- my ($b_start,@fruid);
+ my ($b_start,$file,@fruid);
my $data = {};
if (!$fake{'elbrus'}){
@fruid = main::grabber("$program 2>/dev/null",'','strip');
}
else {
- # my $file;
- # $file = "$fake_data_dir/fruid/fruid-e904-1_full.txt";
- # $file = "$fake_data_dir/fruid/fruid-e804-1_full.txt";
- # @fruid = main::reader($file,'strip');
+ # $file = "$fake_data_dir/machine/elbrus/fruid/fruid-e801-1_full.txt";
+ $file = "$fake_data_dir/machine/elbrus/fruid/fruid-e804-1_full.txt";
+ @fruid = main::reader($file,'strip');
}
- # print Data::Dumper::Dumper \@fruid;
foreach (@fruid){
$b_start = 1 if /^Board info/;
next if !$b_start;
@@ -17857,10 +19641,16 @@ sub machine_data_fruid {
$data->{'board_vendor'} = $split[1];
}
elsif ($split[0] eq 'Board part number'){
- $data->{'board_part_nu'} = $split[1];
+ $data->{'product_sku'} = $split[1];
}
elsif ($split[0] eq 'Board product name'){
$data->{'board_name'} = $split[1];
+ if ($split[1] =~ /(SWTX|^EL)/){
+ $data->{'device'} = 'server';
+ }
+ elsif ($split[1] =~ /(PC$)/){
+ $data->{'device'} = 'desktop';
+ }
}
elsif ($split[0] eq 'Board serial number'){
$data->{'board_serial'} = $split[1];
@@ -17869,10 +19659,95 @@ sub machine_data_fruid {
$data->{'board_version'} = $split[1];
}
}
- print Data::Dumper::Dumper $data if $dbg[28];
- main::log_data('dump','%data',$data) if $b_log;
+ if (%$data){
+ $data->{'bios_vendor'} = 'MCST';
+ $data->{'firmware'} = 'Boot';
+ }
+ if ($dbg[28]){
+ print 'fruid: $data: ', Data::Dumper::Dumper $data;
+ print 'fruid: @fruid: ', Data::Dumper::Dumper \@fruid;
+ }
+ if ($b_log){
+ main::log_data('dump','@fruid',\@fruid);
+ main::log_data('dump','%data',$data);
+ }
+ if ($fake{'elbrus'} || -e '/proc/bootdata'){
+ machine_data_bootdata($data);
+ }
+ eval $end if $b_log;
return $data;
}
+
+# Note: fruid should get device, extra data here uuid, mac
+# Field names map to dmi/sys names.
+# args: 0: $data hash ref;
+sub machine_data_bootdata {
+ eval $start if $b_log;
+ my ($b_pairs,@bootdata,$file);
+ if (!$fake{'elbrus'}){
+ @bootdata = main::reader('/proc/bootdata','strip');
+ }
+ else {
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e2c3/desktop-e2c3.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e4c/server-e4c-x4-1.txt";
+ $file = "$fake_data_dir/machine/elbrus/bootdata/e4c/server-e4c-x4-2.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e8c/desktop-e8c.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e8c/server-e8c-x4-1.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e8c/server-e8c-x4-2.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e8c2/desktop-e8c2.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e8c2/server-e8c2-4x.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e8c2/server-e8c2.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e16c/server-e16c-1.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e16c/server-e16c-2.txt";
+ # $file = "$fake_data_dir/machine/elbrus/bootdata/e16c/server-e16c-3.txt";
+ @bootdata = main::reader($file,'strip');
+ }
+ foreach (@bootdata){
+ s/\s\s+/ /g; # spaces not consistent
+ my @line = split(/=/,$_,2);
+ # These only positive IDs, unreliable data source
+ if ($line[1]){
+ $line[1] =~ s/'//g;
+ $line[0] = lc($line[0]);
+ if ($line[0] eq 'mb_type'){
+ # unknown: unknown (0x0);
+ if ($line[1] =~ /([\/-]SWT|^EL)/){
+ $_[0]->{'device'} = 'server';
+ }
+ elsif ($line[1] =~ /([\/-]PC)/){
+ $_[0]->{'device'} = 'desktop';
+ }
+ }
+ elsif ($line[0] eq 'uuid'){
+ $_[0]->{'product_uuid'} = $line[1];
+ }
+ # fruid has mac address too, but in 0x.. form, this one is easier to read
+ elsif ($line[0] eq 'mac'){
+ $_[0]->{'board_mac'} = $line[1];
+ }
+ }
+ else {
+ if (/release-([\d\.A-Z-]+).*?\srevision\s([\d\.A-Z-]+)/i){
+ $_[0]->{'bios_version'} = $1;
+ $_[0]->{'bios_rev'} = $2;
+ }
+ elsif (/built\son\s(\S+\s\d+\s\d+)\b/){
+ $_[0]->{'bios_date'} = $1;
+ }
+ }
+ }
+ if ($dbg[28]){
+ print 'bootdata: $data: ', Data::Dumper::Dumper $_[0];
+ print 'bootdata: @bootdata: ', Data::Dumper::Dumper \@bootdata;
+ }
+ if ($b_log){
+ main::log_data('dump','@bootdata',\@bootdata);
+ main::log_data('dump','%data', $_[0]);
+ eval $end;
+ }
+ eval $end if $b_log;
+}
+
sub machine_data_sys {
eval $start if $b_log;
my ($path,$vm);
@@ -17881,7 +19756,8 @@ sub machine_data_sys {
my $sys_dir_alt = '/sys/devices/virtual/dmi/id/';
my @sys_files = qw(bios_vendor bios_version bios_date
board_name board_serial board_vendor board_version chassis_type
- product_name product_serial product_uuid product_version sys_vendor
+ product_name product_serial product_sku product_uuid product_version
+ sys_vendor
);
if ($extra > 1){
splice(@sys_files, 0, 0, qw(chassis_serial chassis_vendor chassis_version));
@@ -17917,7 +19793,7 @@ sub machine_data_sys {
}
if ($data->{'chassis_type'}){
if ($data->{'chassis_type'} == 1){
- $data->{'device'} = get_device_vm($data->{'sys_vendor'},$data->{'product_name'});
+ $data->{'device'} = check_vm($data->{'sys_vendor'},$data->{'product_name'});
$data->{'device'} ||= 'other-vm?';
}
else {
@@ -17933,7 +19809,8 @@ sub machine_data_sys {
eval $end if $b_log;
return $data;
}
-# this will create an alternate machine data source
+
+# This will create an alternate machine data source
# which will be used for alt ARM machine data in cases
# where no dmi data present, or by cpu data to guess at
# certain actions for arm only.
@@ -18020,15 +19897,17 @@ sub machine_data_soc {
# board_vendor: ASRock
# board_version:
# chassis_serial:
+# chassis_sku:
# chassis_type: 3
# chassis_vendor:
# chassis_version:
# firmware:
# product_name:
# product_serial:
+# product_sku:
# product_uuid:
# product_version:
-# sys_uuid: dmi/sysctl only
+# uuid: dmi/sysctl only, map to product_uuid
# sys_vendor:
sub machine_data_dmi {
eval $start if $b_log;
@@ -18078,8 +19957,10 @@ sub machine_data_dmi {
$data->{'product_serial'} = main::clean_dmi($value[1]) }
elsif ($value[0] eq 'Manufacturer'){
$data->{'sys_vendor'} = main::clean_dmi($value[1]) }
+ elsif ($value[0] eq 'SKU Number'){
+ $data->{'product_sku'} = main::clean_dmi($value[1]) }
elsif ($value[0] eq 'UUID'){
- $data->{'sys_uuid'} = main::clean_dmi($value[1]) }
+ $data->{'product_uuid'} = main::clean_dmi($value[1]) }
}
}
next;
@@ -18110,6 +19991,9 @@ sub machine_data_dmi {
my @value = split(/:\s+/, $item);
if ($value[0] eq 'Serial Number'){
$data->{'chassis_serial'} = main::clean_dmi($value[1]) }
+ # not sure if this sku is same as system sku
+ elsif ($value[0] eq 'SKU Number'){
+ $data->{'chassis_sku'} = main::clean_dmi($value[1]) }
elsif ($value[0] eq 'Type'){
$data->{'chassis_type'} = main::clean_dmi($value[1]) }
elsif ($value[0] eq 'Manufacturer'){
@@ -18130,6 +20014,7 @@ sub machine_data_dmi {
if (!$data->{'device'}){
if (grep {/hypervisor/i} @$row){
$data->{'device'} = 'virtual-machine';
+ $b_vm = 1;
}
}
last;
@@ -18139,18 +20024,19 @@ sub machine_data_dmi {
}
}
if (!$data->{'device'}){
- $data->{'device'} = get_device_vm($data->{'sys_vendor'},$data->{'product_name'});
+ $data->{'device'} = check_vm($data->{'sys_vendor'},$data->{'product_name'});
$data->{'device'} ||= 'other-vm?';
}
-# print "dmi:\n";
-# foreach (keys %data){
-# print "$_: $data->{$_}\n";
-# }
+ # print "dmi:\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;
return $data;
}
+
# As far as I know, only OpenBSD supports this method.
# it uses hw. info from sysctl -a and bios info from dmesg.boot
sub machine_data_sysctl {
@@ -18193,7 +20079,7 @@ sub machine_data_sysctl {
$data->{'product_serial'} = main::clean_dmi($item[1]);
}
elsif ($item[0] eq 'machdep.dmi.system-uuid'){
- $data->{'sys_uuid'} = main::clean_dmi($item[1]);
+ $data->{'product_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
@@ -18226,7 +20112,7 @@ sub machine_data_sysctl {
$product = $data->{'board_name'} if !$product;
}
# detections can be from other sources.
- $data->{'device'} = get_device_vm($vendor,$product);
+ $data->{'device'} = check_vm($vendor,$product);
print Data::Dumper::Dumper $data if $dbg[28];
main::log_data('dump','%data',$data) if $b_log;
eval $end if $b_log;
@@ -18282,7 +20168,7 @@ sub get_device_sys {
return $device;
}
-sub get_device_vm {
+sub check_vm {
eval $start if $b_log;
my ($manufacturer,$product_name) = @_;
$manufacturer ||= '';
@@ -18371,16 +20257,17 @@ sub get_device_vm {
if (!$vm && $manufacturer && $manufacturer eq 'Xen'){
$vm = 'xen';
}
+ $b_vm = 1 if $vm;
eval $end if $b_log;
return $vm;
}
-
}
## NetworkItem
{
package NetworkItem;
my ($b_ip_run,@ifs_found);
+
sub get {
eval $start if $b_log;
my $rows = [];
@@ -18430,6 +20317,9 @@ sub get {
else {
advanced_data_bsd($rows,'check');
}
+ if ($b_admin){
+ info_data($rows);
+ }
}
if ($show{'ip'}){
wan_ip($rows);
@@ -18532,6 +20422,7 @@ sub device_output {
# @rows = ();
eval $end if $b_log;
}
+
sub usb_output {
eval $start if $b_log;
return if !$usb{'network'};
@@ -18550,22 +20441,37 @@ sub usb_output {
$j = scalar @$rows;
push(@$rows, {
main::key($num++,1,1,'Device') => $product,
- main::key($num++,0,2,'type') => 'USB',
main::key($num++,0,2,'driver') => $driver,
+ main::key($num++,1,2,'type') => 'USB',
},);
$b_wifi = check_wifi($product);
if ($extra > 0){
+ if ($extra > 1){
+ $row->[8] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'rev')} = $row->[8];
+ if ($row->[17]){
+ $rows->[$j]{main::key($num++,0,3,'speed')} = $row->[17];
+ }
+ if ($row->[24]){
+ $rows->[$j]{main::key($num++,0,3,'lanes')} = $row->[24];
+ }
+ if ($b_admin && $row->[22]){
+ $rows->[$j]{main::key($num++,0,3,'mode')} = $row->[22];
+ }
+ }
$rows->[$j]{main::key($num++,0,2,'bus-ID')} = "$path_id:$row->[1]";
- }
- if ($extra > 1){
- $row->[7] ||= 'N/A';
- $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
- }
- if ($extra > 2 && defined $row->[5] && $row->[5] ne ''){
- $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::filter($row->[16]);
+ if ($extra > 1){
+ $row->[7] ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'chip-ID')} = $row->[7];
+ }
+ if ($extra > 2){
+ if (defined $row->[5] && $row->[5] ne ''){
+ $rows->[$j]{main::key($num++,0,2,'class-ID')} = "$row->[4]$row->[5]";
+ }
+ if ($row->[16]){
+ $rows->[$j]{main::key($num++,0,2,'serial')} = main::filter($row->[16]);
+ }
+ }
}
if ($show{'network-advanced'}){
if (!$bsd_type){
@@ -18583,6 +20489,7 @@ sub usb_output {
}
eval $end if $b_log;
}
+
sub advanced_data_sys {
eval $start if $b_log;
return if ! -d '/sys/class/net';
@@ -18601,6 +20508,7 @@ sub advanced_data_sys {
@paths = main::globber('/sys/class/net/*');
}
@paths = grep {!/\/lo$/} @paths;
+ # push(@paths,'/sys/class/net/ppp0'); # fake IF if needed to match test data
if ($count > 0 && $count < scalar @paths){
@paths = splice(@paths, $count, scalar @paths);
}
@@ -18703,7 +20611,6 @@ sub advanced_data_bsd {
($cont_if,$ind_if) = (1,2);
}
foreach my $item (@ifs_bsd){
-
if (ref $item ne 'ARRAY'){
$working_if = $item;
# print "$working_if\n";
@@ -18751,19 +20658,19 @@ sub advanced_data_bsd {
}
eval $end if $b_log;
}
-## values:
-# 0 - ipv
-# 1 - ip
-# 2 - broadcast, if found
-# 3 - scope, if found
-# 4 - scope if, if different from if
+
+## Result values:
+# 0: ipv
+# 1: ip
+# 2: broadcast, if found
+# 3: scope, if found
+# 4: scope IF, if different from IF
sub if_ip {
eval $start if $b_log;
my ($rows,$type,$if) = @_;
my ($working_if);
- my ($cont_ip,$ind_ip) = (3,4);
- my $num = 0;
- my $j = 0;
+ my ($cont_ip,$ind_ip,$if_cnt) = (3,4,0);
+ my ($j,$num) = (0,0);
$b_ip_run = 1;
if ($type eq 'IF-ID'){
($cont_ip,$ind_ip) = (2,3);
@@ -18776,11 +20683,13 @@ sub if_ip {
next;
}
if ($working_if eq $if){
+ $if_cnt = 0;
# print "if $if item:\n", Data::Dumper::Dumper $item;
foreach my $data2 (@$item){
$j = scalar @$rows;
$num = 1;
- if ($limit > 0 && $j >= $limit){
+ $if_cnt++;
+ if ($limit > 0 && $if_cnt > $limit){
push(@$rows, {
main::key($num++,0,$cont_ip,'Message') => main::message('output-limit',scalar @$item),
});
@@ -18835,7 +20744,30 @@ sub if_ip {
}
eval $end if $b_log;
}
-# get ip using downloader to stdout. This is a clean, text only IP output url,
+
+sub info_data {
+ eval $start if $b_log;
+ my ($rows) = @_;
+ my $j = scalar @$rows;
+ my $num = 0;
+ my $services;
+ PsData::set_cmd() if !$loaded{'ps-cmd'};
+ PsData::set_network();
+ if (@{$ps_data{'network-services'}}){
+ main::make_list_value($ps_data{'network-services'},\$services,',','sort');
+ }
+ else {
+ $services = main::message('network-services');
+ }
+
+ push(@$rows,{
+ main::key($num++,1,1,'Info') => '',
+ main::key($num++,0,2,'services') => $services,
+ });
+ eval $end if $b_log;
+}
+
+# Get ip using downloader to stdout. This is a clean, text only IP output url,
# single line only, ending in the ip address. May have to modify this in the future
# to handle ipv4 and ipv6 addresses but should not be necessary.
# ip=$(echo 2001:0db8:85a3:0000:0000:8a2e:0370:7334 | gawk --re-interval '
@@ -18850,15 +20782,16 @@ sub wan_ip {
my ($b_dig,$b_html,$ip,$ua);
my $num = 0;
# time: 0.06 - 0.07 seconds
- # cisco opendns.com may be terminating supporting this one, sometimes works, sometimes not:
- # use -4/6 to force ipv 4 or 6, but generally we want the 'natural' native
- # ip returned.
- # dig +short +time=1 +tries=1 myip.opendns.com @resolver1.opendns.com
- # dig +short @ns1-1.akamaitech.net ANY whoami.akamai.net
- # this one can take forever, and sometimes requires explicit -4 or -6
- # dig -4 TXT +short o-o.myaddr.l.google.com @ns1.google.com
+ # Cisco opendns.com may be terminating supporting this one, sometimes works, sometimes not:
+ # use -4/6 to force ipv 4 or 6, but generally we want the 'natural' native ip returned.
+ # dig +short +time=1 +tries=1 myip.opendns.com @resolver1.opendns.com :: 0.021s
+ # Works but is slow:
+ # dig +short @ns1-1.akamaitech.net ANY whoami.akamai.net :: 0.156s
+ # This one can take forever, and sometimes requires explicit -4 or -6
+ # dig -4 TXT +short o-o.myaddr.l.google.com @ns1.google.com :: 0.026s; 1.087ss
if (!$force{'no-dig'} && (my $program = main::check_program('dig'))){
$ip = (main::grabber("$program +short +time=1 +tries=1 \@ns1-1.akamaitech.net ANY whoami.akamai.net 2>/dev/null"))[0];
+ $ip =~ s/"//g if $ip; # some return IP in quotes, when using TXT
$b_dig = 1;
}
if (!$ip && !$force{'no-html-wan'}){
@@ -18866,16 +20799,19 @@ sub wan_ip {
if (!defined $dl{'no-ssl'}){
main::set_downloader();
}
- # note: tests: akamai: 0.055 - 0.065 icanhazip.com: 0.177 0.164
- # smxi: 0.525, so almost 10x slower. Dig is fast too
+ # note: tests: akamai: 0.015 - 0.025 icanhazip.com: 0.020 0.030
+ # smxi: 0.230, so ~10x slower. Dig is not as fast as you'd expect
+ # dig: 0.167s 0.156s
# leaving smxi as last test because I know it will always be up.
# --wan-ip-url replaces values with user supplied arg
- # 0.059s: http://whatismyip.akamai.com/
- # 0.255s: https://get.geojs.io/v1/ip
- # 0.371s: http://icanhazip.com/
- # 0.430s: https://smxi.org/opt/ip.php
+ # 0.020s: http://whatismyip.akamai.com/
+ # 0.136s: https://get.geojs.io/v1/ip
+ # 0.024s: http://icanhazip.com/
+ # 0.027s: ifconfig.io
+ # 0.230s: https://smxi.org/opt/ip.php
+ # 0.023s: https://api.ipify.org :: NOTE: hangs, widely variable times, don't use
my @urls = (!$wan_url) ? qw(http://whatismyip.akamai.com/
- http://icanhazip.com/ https://smxi.org/opt/ip.php) : ($wan_url);
+ http://icanhazip.com/ https://smxi.org/opt/ip.php) : ($wan_url);
foreach (@urls){
$ua = 'ip' if $_ =~ /smxi/;
$ip = main::download_file('stdout',$_,'',$ua);
@@ -18908,6 +20844,7 @@ sub wan_ip {
});
eval $end if $b_log;
}
+
sub check_bus_id {
eval $start if $b_log;
my ($path,$bus_id) = @_;
@@ -18924,6 +20861,7 @@ sub check_bus_id {
eval $end if $b_log;
return $b_valid;
}
+
sub check_wifi {
my ($item) = @_;
my $b_wifi = ($item =~ /wireless|wi-?fi|wlan|802\.11|centrino/i) ? 1 : 0;
@@ -18934,10 +20872,11 @@ sub check_wifi {
## OpticalItem
{
package OpticalItem;
+
sub get {
eval $start if $b_log;
my $rows = $_[0];
- my $start = scalar @$rows;
+ my $rows_start = scalar @$rows;
my ($data,$val1);
my $num = 0;
if ($bsd_type){
@@ -18962,12 +20901,13 @@ sub get {
drive_output($rows,$data) if %$data;
}
# if none of the above increased the row count, show the error message
- if ($start == scalar @$rows){
+ if ($rows_start == scalar @$rows){
push(@$rows,{main::key($num++,0,1,'Message') => $val1});
}
eval $end if $b_log;
return $rows;
}
+
sub drive_output {
eval $start if $b_log;
my ($rows,$drives) = @_;
@@ -19053,6 +20993,7 @@ sub drive_output {
# print Data::Dumper::Dumper $drives;
eval $end if $b_log;
}
+
sub drive_data_bsd {
eval $start if $b_log;
my (@rows,@temp);
@@ -19156,6 +21097,7 @@ sub drive_data_bsd {
eval $end if $b_log;
return $drives;
}
+
sub drive_data_linux {
eval $start if $b_log;
my (@data,@info,@rows);
@@ -19253,6 +21195,8 @@ sub drive_data_linux {
## PartitionItem
{
+# these will be globally accessible via PartitionItem::filters()
+my ($fs_exclude,$fs_skip,$part_filter);
package PartitionItem;
sub get {
@@ -19261,7 +21205,7 @@ sub get {
my $rows = [];
my $num = 0;
set_partitions() if !$loaded{'set-partitions'};
- # fails in corner case with zram but no other mounted filesystems
+ # Fails in corner case with zram but no other mounted filesystems
if (!@partitions){
$key1 = 'Message';
#$val1 = ($bsd_type && $bsd_type eq 'darwin') ?
@@ -19275,6 +21219,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub create_output {
eval $start if $b_log;
my $rows = $_[0];
@@ -19288,7 +21233,7 @@ sub create_output {
else {
@partitions = sort { $a->{$show{'partition-sort'}} <=> $b->{$show{'partition-sort'}} } @partitions;
}
- my $fs_skip = fs_excludes('label-uuid');
+ my $fs_skip = get_filters('fs-skip');
foreach my $row (@partitions){
$num = 1;
next if $row->{'type'} eq 'secondary' && $show{'partition'};
@@ -19334,8 +21279,8 @@ sub create_output {
}
if ($b_admin && $row->{'block-size'}){
$rows->[$j]{main::key($num++,0,2,'block-size')} = $row->{'block-size'} . ' B';;
- #$rows->[$j]{main::key($num++,0,2,'physical')} = $row->{'block-size'} . ' B';
- #$rows->[$j]{main::key($num++,0,2,'logical')} = $row->{'block-logical'} . ' B';
+ # $rows->[$j]{main::key($num++,0,2,'physical')} = $row->{'block-size'} . ' B';
+ # $rows->[$j]{main::key($num++,0,2,'logical')} = $row->{'block-logical'} . ' B';
}
$rows->[$j]{main::key($num++,1,2,$dev_type)} = $dev;
if ($b_admin && $row->{'maj-min'}){
@@ -19363,7 +21308,7 @@ sub create_output {
}
}
}
- # corner case, no partitions, but zram swap
+ # Corner case, no partitions, but zram swap.
if (!@$rows){
@$rows = ({main::key($num++,0,1,'Message') => main::message('partition-data')});
}
@@ -19372,7 +21317,7 @@ sub create_output {
sub set_partitions {
eval $start if $b_log;
- #return if $bsd_type && $bsd_type eq 'darwin'; # darwin has muated output, of course
+ # return if $bsd_type && $bsd_type eq 'darwin'; # darwin has mutated output
my (@data,@rows,@mount,@partitions_working,$part,@working);
my ($back_size,$back_used,$b_fs,$cols) = (4,3,1,6);
my ($b_dfp,$b_fake_map,$b_load,$b_logical,$b_space,);
@@ -19381,18 +21326,22 @@ sub set_partitions {
$type,$uuid,$used);
$loaded{'set-partitions'} = 1;
if ($b_admin){
- # for partition block size
+ # For partition block size
$blockdev = $alerts{'blockdev'}->{'path'} if $alerts{'blockdev'}->{'path'};
}
- # for raw partition sizes, maj_min
- PartitionData::set() if !$bsd_type && !$loaded{'partition-data'};
- DiskDataBSD::set() if $bsd_type && !$loaded{'disk-data-bsd'};
- LsblkData::set() if !$bsd_type && !$loaded{'lsblk'};
+ # For raw partition sizes, maj_min
+ if ($bsd_type){
+ DiskDataBSD::set() if !$loaded{'disk-data-bsd'};
+ }
+ else {
+ PartitionData::set() if !$loaded{'partition-data'};
+ LsblkData::set() if !$loaded{'lsblk'};
+ }
# set @labels, @uuid
if (!$bsd_type){
set_label_uuid() if !$loaded{'label-uuid'};
}
- # most current OS support -T and -k, but -P means different things
+ # Most current OS support -T and -k, but -P means different things
# in freebsd. However since most use is from linux, we make that default
# android 7 no -T support
if (!$fake{'partitions'}){
@@ -19401,9 +21350,9 @@ sub set_partitions {
$b_dfp = 1;
}
elsif (@partitions_working = main::grabber("df -T -k 2>/dev/null")){
- # fine, it worked, could be bsd or linux
+ # Fine, it worked, could be bsd or linux
}
- # busybox supports -k and -P, older openbsd, darwin, solaris don't have -P
+ # Busybox supports -k and -P, older openbsd, darwin, solaris don't have -P
else {
if (@partitions_working = main::grabber("df -k -P 2>/dev/null")){
$b_dfp = 1;
@@ -19419,12 +21368,12 @@ sub set_partitions {
}
else {
my $file;
- # $file = "$fake_data_dir/df/df-kTP-cygwin-1.txt";
- $file = "$fake_data_dir/df/df-kT-wrapped-1.txt";
- @partitions_working = main::reader($file);
+ # $file = "$fake_data_dir/block-devices/df/df-kTP-cygwin-1.txt";
+ # $file = "$fake_data_dir/block-devices/df/df-kT-wrapped-1.txt";
+ # @partitions_working = main::reader($file);
}
# print Data::Dumper::Dumper \@partitions_working;
- # determine positions
+ # Determine positions
if (@partitions_working){
my $row1 = shift @partitions_working;
$row1 =~ s/Mounted on/Mounted-on/i;
@@ -19450,9 +21399,10 @@ sub set_partitions {
@partitions_working = @part_temp;
}
if (!$bsd_type){
- # new kernels/df have rootfs and / repeated, creating two entries for the same partition
- # so check for two string endings of / then slice out the rootfs one, I could check for it
- # before slicing it out, but doing that would require the same action twice re code execution
+ # New kernels/df have rootfs and / repeated, creating two entries for the
+ # same partition so check for two string endings of / then slice out the
+ # rootfs one, I could check for it before slicing it out, but doing that
+ # would require the same action twice re code execution.
my $roots = 0;
foreach (@partitions_working){
$roots++ if /\s\/$/;
@@ -19469,7 +21419,13 @@ sub set_partitions {
($back_size,$back_used) = (7,6);
}
}
- my $filters = partition_filters();
+ my $filters = get_filters('partition');
+ # These are local, not remote, iso, or overlay types:
+ my $fuse_fs = 'adb|apfs(-?fuse)?|archive(mount)?|gphoto|gv|gzip|ifuse|';
+ $fuse_fs .= '[^\.]*mtp|ntfs-?3g|[^\.]*ptp|vdfuse|vram|wim(mount)?|xb|xml';
+ # Just the common ones desktops might have
+ my $remote_fs = 'curlftp|gmail|g(oogle-?)?drive|pnfs|\bnfs|rclone|';
+ $remote_fs .= 's3fs|smb|ssh|vboxsf';
# push @partitions_working, '//mafreebox.freebox.fr/Disque dur cifs 239216096 206434016 20607496 91% /freebox/Disque dur';
# push @partitions_working, '//mafreebox.freebox.fr/AllPG cifs 436616192 316339304 120276888 73% /freebox/AllPG';
# push(@partitions_working,'/dev/loop0p1 iso9660 3424256 3424256 0 100% /media/jason/d-live nf 11.3.0 gn 6555 9555 amd64');
@@ -19499,7 +21455,7 @@ sub set_partitions {
# print Data::Dumper::Dumper \@row;
$row[0] =~ s/\^\^/ /g if $b_space; # reset spaces in > 1 word fs name
# autofs is a bsd thing, has size 0
- if ($row[0] =~ /^($filters)$/ || $row[0] =~ /^ROOT/i ||
+ if ($row[0] =~ /^$filters$/ || $row[0] =~ /^ROOT/i ||
($b_fs && ($row[2] == 0 || $row[1] =~ /^(autofs|devtmpfs|iso9660|tmpfs)$/))){
next;
}
@@ -19582,7 +21538,7 @@ sub set_partitions {
$fs = ($b_fs) ? $row[1]: get_mounts_fs($row[0],\@mount);
}
# assuming that all null/nullfs are parts of a logical fs
- $b_logical = 1 if $fs && $fs =~ /^(btrfs|hammer|null|wekafs|zfs)/;
+ $b_logical = 1 if $fs && $fs =~ /^(btrfs|hammer|null|zfs)/;
$id = join(' ', @row[$cols .. $#row]);
$size = $row[$cols - $back_size];
if ($b_admin && -e "/sys/block/"){
@@ -19613,19 +21569,26 @@ sub set_partitions {
$dev_base = $1;
}
# note: possible: sshfs path: beta:data/; remote: fuse.rclone
- elsif ($dev_base =~ /^\/\/|:\// || ($fs && $fs =~ /(rclone)/)){
+ elsif ($dev_base =~ /^\/\/|:\// || ($fs && $fs =~ /($remote_fs)/i)){
$dev_type = 'remote';
$dev_base = $row[0] if !$dev_base; # only trips in fs test case
}
# a slice bsd system, zfs can't be detected this easily
- elsif ($b_logical && $fs && $fs =~ /^(null(fs)?)$/){
+ elsif ($b_logical && $fs && $fs =~ /^null(fs)?$/){
$dev_type = 'logical';
$dev_base = $row[0] if !$dev_base;
}
- # an error has occurred almost for sure
elsif (!$dev_base){
- $dev_type = 'source';
- $dev_base = main::message('unknown-dev');
+ if ($fs && $fs =~ /^(fuse[\._-]?)?($fuse_fs)(fs)?/i){
+ $dev_base = $2;
+ $dev_type = 'fuse';
+ }
+ # Check dm-crypt, that may be real partition type, but no data.
+ # We've hit something inxi doesn't know about, or error has occured
+ else {
+ $dev_type = 'source';
+ $dev_base = main::message('unknown-dev');
+ }
}
else {
$dev_type = 'dev';
@@ -19669,13 +21632,15 @@ sub set_partitions {
print Data::Dumper::Dumper \@partitions if $dbg[16];
eval $end if $b_log;
}
+
sub swap_data {
eval $start if $b_log;
$loaded{'set-swap'} = 1;
my (@data,@working);
my ($block_size,$cache_pressure,$dev_base,$dev_mapped,$dev_type,$label,
$maj_min,$mount,$path,$pattern1,$pattern2,$percent_used,$priority,
- $size,$swap_type,$swappiness,$used,$uuid);
+ $size,$swap_type,$swappiness,$used,$uuid,$zram_comp,$zram_mcs,
+ $zswap_enabled,$zram_comp_avail,$zswap_comp,$zswap_mpp);
my ($s,$j,$size_id,$used_id) = (1,0,2,3);
if (!$bsd_type){
# faster, avoid subshell, same as swapon -s
@@ -19688,9 +21653,8 @@ sub swap_data {
@working = main::grabber("$path -s 2>/dev/null");
}
if ($b_admin){
- @data = swap_advanced_data();
- $swappiness = $data[0];
- $cache_pressure = $data[1];
+ swap_advanced_data(\$swappiness,\$cache_pressure,\$zswap_enabled,
+ \$zswap_comp,\$zswap_mpp);
}
if (($show{'label'} || $show{'uuid'}) && !$loaded{'label-uuid'}){
set_label_uuid();
@@ -19713,12 +21677,19 @@ sub swap_data {
foreach (@working){
#next if ! /^\/dev/ || /^\/dev\/(ramzwap|zram)/;
next if /^(Device|Filename|no swap)/;
- ($block_size,$dev_base,$dev_mapped,$dev_type,$label,$maj_min,$mount,$priority,
- $swap_type,$uuid) = ('','','','','','','',undef,'partition','');
+ ($block_size,$dev_base,$dev_mapped,$dev_type,$label,$maj_min,$mount,
+ $swap_type,$uuid) = ('','','','','','','','partition','');
+ ($priority,$zram_comp_avail,$zram_comp,$zram_mcs) = ();
@data = split(/\s+/, $_);
- if (/^\/dev\/(block\/)?(compcache|ramzwap|zram)/i){
+ # /dev/zramX; ramzswapX == compcache, legacy version of zram.
+ # /run/initramfs/dev/zram0; /dev/ramzswap0
+ if (/^\/(dev|run).*?\/((compcache|ramzwap|zram)\d+)/i){
+ $dev_base = $2;
$swap_type = 'zram';
$dev_type = 'dev';
+ if ($b_admin){
+ zram_data($dev_base,\$zram_comp,\$zram_comp_avail,\$zram_mcs);
+ }
}
elsif ($data[1] && $data[1] eq 'ram'){
$swap_type = 'ram';
@@ -19781,6 +21752,12 @@ sub swap_data {
'swap-type' => $swap_type,
'used' => $used,
'uuid' => $uuid,
+ 'zram-comp' => $zram_comp,
+ 'zram-comp-avail' => $zram_comp_avail,
+ 'zram-max-comp-streams' => $zram_mcs,
+ 'zswap-enabled' => $zswap_enabled,
+ 'zswap-compressor' => $zswap_comp,
+ 'zswap-max-pool-percent' => $zswap_mpp,
});
$s++;
}
@@ -19788,34 +21765,72 @@ sub swap_data {
print Data::Dumper::Dumper \@swaps if $dbg[15];;
eval $end if $b_log;
}
+
+# Alll by ref: 0: $swappiness; 1: $cache_pressure; 2: $zswap_enabled;
+# 3: $zswap_comp; 4: $zswap_mpp
sub swap_advanced_data {
eval $start if $b_log;
- my ($swappiness,$cache_pressure) = ();
if (-r '/proc/sys/vm/swappiness'){
- $swappiness = main::reader('/proc/sys/vm/swappiness','',0);
- if (defined $swappiness){
- $swappiness .= ($swappiness == 60) ? ' (default)' : ' (default 60)' ;
+ ${$_[0]} = main::reader('/proc/sys/vm/swappiness','',0);
+ if (defined ${$_[0]}){
+ ${$_[0]} .= (${$_[0]} == 60) ? ' (default)' : ' (default 60)' ;
}
}
if (-r '/proc/sys/vm/vfs_cache_pressure'){
- $cache_pressure = main::reader('/proc/sys/vm/vfs_cache_pressure','',0);
- if (defined $cache_pressure){
- $cache_pressure .= ($cache_pressure == 100) ? ' (default)' : ' (default 100)' ;
+ ${$_[1]} = main::reader('/proc/sys/vm/vfs_cache_pressure','',0);
+ if (defined ${$_[1]}){
+ ${$_[1]} .= (${$_[1]}== 100) ? ' (default)' : ' (default 100)' ;
+ }
+ }
+ if (-r '/sys/module/zswap/parameters/enabled'){
+ ${$_[2]} = main::reader('/sys/module/zswap/parameters/enabled','',0);
+ if (${$_[2]} =~ /^(Y|yes|true|1)$/){
+ ${$_[2]} = 'yes';
+ }
+ elsif (${$_[2]} =~ /^(N|no|false|0)$/){
+ ${$_[2]} = 'no';
+ }
+ else {
+ ${$_[2]} = 'unset';
}
}
+ if (-r '/sys/module/zswap/parameters/compressor'){
+ ${$_[3]} = main::reader('/sys/module/zswap/parameters/compressor','',0);
+ }
+ if (-r '/sys/module/zswap/parameters/max_pool_percent'){
+ ${$_[4]} = main::reader('/sys/module/zswap/parameters/max_pool_percent','',0);
+ }
eval $end if $b_log;
- return ($swappiness,$cache_pressure);
}
-# handle cases of hidden file systems
+
+# 0: device id [zram0]; by ref: 1: $zram_comp; 2: $zram_comp_avail; 3: $zram_mcs;
+sub zram_data {
+ if (-r "/sys/block/$_[0]/comp_algorithm"){
+ ${$_[2]} = main::reader("/sys/block/$_[0]/comp_algorithm",'',0);
+ # current is in [..] in list
+ if (${$_[2]} =~ /\[(\S+)\]/){
+ ${$_[1]} = $1;
+ # dump the active one, and leave the available
+ ${$_[2]} =~ s/\[${$_[1]}\]//;
+ ${$_[2]} =~ s/^\s+|\s+$//g;
+ ${$_[2]} =~ s/\s+/,/g;
+ }
+ }
+ if (-r "/sys/block/$_[0]/max_comp_streams"){
+ ${$_[3]} = main::reader("/sys/block/$_[0]/max_comp_streams",'',0);
+ }
+}
+
+# Handle cases of hidden file systems
sub check_partition_data {
eval $start if $b_log;
my ($b_found,$dev_mapped,$temp);
- my $filters = partition_filters();
+ my $filters = get_filters('partition');
foreach my $row (@lsblk){
$b_found = 0;
$dev_mapped = '';
if (!$row->{'name'} || !$row->{'mount'} || !$row->{'type'} ||
- ($row->{'fs'} && $row->{'fs'} =~ /^($filters)$/) ||
+ ($row->{'fs'} && $row->{'fs'} =~ /^$filters$/) ||
($row->{'type'} =~ /^(disk|loop|rom)$/)){
next;
}
@@ -19859,38 +21874,77 @@ sub check_partition_data {
}
eval $end if $b_log;
}
-# NOTE: Was forgetting to update one or the other so put them
-# all here for: subs partitiion_data(), check_partition_data()
-# note: p_d filters 'filesystem', and c_p_d filters against fs
-sub partition_filters {
- # snap mounts with squashfs; appimage/flatpak mount?
- # swap is set in swap_data(); cgmfs is in ram, like devfs, sysfs;
- # union fs types: aufs, lofs, overlayfs, unionfs, mergerfs
- my $filters = 'aufs|cgroup.*|cgmfs|configfs|debugfs|\/dev|dev|\/dev\/loop[0-9]*|';
- $filters .= 'devfs|devtmpfs|efivarfs|fdescfs|hugetlbfs|iso9660|kernfs|';
- $filters .= 'linprocfs|linsysfs|lofs|mergerfs|none|overla(id|y)(fs)?|procfs|';
- $filters .= 'ptyfs|/run(\/.*)?|run|securityfs|shm|squashfs|swap|';
- $filters .= 'sys|\/sys\/.*|sysfs|tmpfs|tracefs|type|udev|unionfs|vartmp';
- return $filters
-}
-# used to exclude disk used, partition/unmounted/swap label/uuid, unmounted label/uuid
-# see docs/inxi-data.txt PARTITION DATA for more on remote/fuse fs
-sub fs_excludes {
- my ($source) = @_;
- # panfs is parallel NAS volume manager, need more data
- # null is hammer fs slice; nfs/nfs3/nfs4; some can be fuse mounts: fuse.sshfs
- # afs aufs avfs cifs ffs gfs\d{0,2} hdfs ipfs k(osmos)?fs .*lafs lofs mhddfs
- # mergerfs nfs\d{0,2} null ocfs\d{0,2} openafs orangefs overla(id|y)(fs)?
- # panfs pvfs\d{0,2} s3fs squashfs sshfs smbfs unionfs vmfs
- my $excludes = '(fuse(blk)?[\._-]?)?(';
- $excludes .= 'f|' if $source eq 'label-uuid'; # ffs not remote, but no u/l
- $excludes .= 'a|archivemount|au|av|ceph|ci|g|gluster|gmail|hd|ip|';
- $excludes .= 'iso9660|k(osmos)?|lo|.*la|mhdd|merger|moose|n|null|oc|opena|';
- $excludes .= 'orange|overla(id|y)|pan|pv|s3|rclone|sheepdog|squash|ssh|';
- $excludes .= 'smb|union|vm';
- $excludes .= ')(fs)?(\d{0,2})?';
- return $excludes;
+
+# fs-exclude: Excludes fs size from disk used total;
+# fs-skip: do not display label/uuid fields from partition/unmounted/swap.
+# partition: do not use this partition in -p output.
+# args: 0: [fs-exclude|fs-skip|partition]
+sub get_filters {
+ set_filters() if !$fs_exclude;
+ if ($_[0] eq 'fs-exclude'){
+ return $fs_exclude;
+ }
+ elsif ($_[0] eq 'fs-skip'){
+ return $fs_skip;
+ }
+ elsif ($_[0] eq 'partition'){
+ return $part_filter;
+ }
+}
+
+# See docs/inxi-partitions.txt FILE SYSTEMS for specific fs info.
+# The filter string must match /^[regex]$/ exactly.
+sub set_filters {
+ # Notes: appimage/flatpak mount?; astreamfs reads remote http urls;
+ # avfs == fuse; cgmfs,vramfs in ram, like devfs, sysfs; gfs = googlefs;
+ # hdfs == hadoop; ifs == integrated fs; pvfs == orangefs; smb == cifs;
+ # null == hammer fs slice; kfs/kosmosfs == CloudStore;
+ # snap mounts with squashfs; swap is set in swap_data(); vdfs != vdfuse;
+ # vramfs == like zram except gpu ram;
+ # Some can be fuse mounts: fuse.sshfs.
+ # Distributed/Remote: 9p, (open-)?afs, alluxio, astreamfs, beegfs,
+ # cephfs, cfs, chironfs, cifs, cloudstore, dfs, davfs, dce,
+ # gdrivefs, gfarm, gfs\d{0,2}, gitfs, glusterfs, gmailfs, gpfs,
+ # hdfs, httpdirfs, hubicfuse, ipfs, juice, k(osmos)?fs, .*lafs, lizardfs,
+ # lustre, magma, mapr, moosefs, nfs[34], objective, ocfs\d{0,2}, onefs,
+ # orangefs, panfs, pnfs, pvfs\d{0,2}, rclone, restic, rozofs, s3fs, scality,
+ # sfs, sheepdogfs, spfs, sshfs, smbfs, v9fs, vboxsf, vdfs, vmfs, wekafs,
+ # xtreemfs
+ # Stackable/Union: aufs, e?cryptfs, encfs, erofs, gocryptfs, ifs, lofs,
+ # mergerfs, mhddfs, overla(id|y)(fs)?, squashfs, unionfs;
+ # ISO/Archive: archive(mount)?, atlas, avfs. borg, erofs, fuse-archive,
+ # fuseiso, gzipfs, iso9660, lofs, vdfuse, wimmountfs, xbfuse
+ # FUSE: adbfs, apfs-fuse, atomfs, gvfs, gvfs-mtp, ifuse, jmtpfs, mtpfs, ptpfs,
+ # puzzlefs, simple-mtpfs, vramfs, xmlfs
+ # System fs: cgmfs, configfs, debugfs, devfs, devtmpfs, efivarfs, fdescfs,
+ # hugetlbfs, kernfs, linprocfs, linsysfs, lxcfs, procfs, ptyfs, run,
+ # securityfs, shm, swap, sys, sysfs, tmpfs, tracefs, type, udev, vartmp
+ # System dir: /dev, /dev/(block/)?loop[0-9]+, /run(/.*)?, /sys/.*
+
+ ## These are global, all filters use these. ISO, encrypted/stacked
+ my @all = qw%au av e?crypt enc ero gocrypt i (fuse-?)?iso iso9660 lo merger
+ mhdd overla(id|y) splitview(-?fuse)? squash union vboxsf xbfuse%;
+ ## These are fuse/archive/distributed/remote/clustered mostly
+ my @exclude = (@all,qw%9p (open-?)?a adb archive(mount)? astream atlas atom
+ beeg borg c ceph chiron ci cloudstore curlftp d dav dce
+ g gdrive gfarm git gluster gmail gocrypt google-drive-ocaml gp gphoto gv gzip
+ hd httpd hubic ip juice k(osmos)? .*la lizard lustre magma mapr moose .*mtp
+ null p?n objective oc one orange pan .*ptp puzzle pv rclone restic rozo
+ s s3 scality sheepdog sp ssh smb v9 vd vm vram weka wim(mount)? xb xml
+ xtreem%);
+ # Various RAM based system FS
+ my @partition = (@all,qw%cgroup.* cgm config debug dev devtmp efivar fdesc
+ hugetlb kern linproc linsys lxc none proc pty run security shm swap sys
+ tmp trace type udev vartmp%);
+ my $begin = '(fuse(blk)?[\._-]?)?(';
+ my $end = ')([\._-]?fuse)?(fs)?\d{0,2}';
+ $fs_exclude = $begin . join('|',@exclude) . $end;
+ $fs_skip = $begin . join('|',@exclude,'f') . $end; # apfs?; BSD ffs has no u/l
+ $part_filter = '((' . join('|',@partition) . ')(fs)?|';
+ $part_filter .= '\/dev|\/dev\/(block\/)?loop[0-9]+|\/run(\/.*)?|\/sys\/.*)';
+ # print "$part_filter\n";
}
+
sub get_mounts_fs {
eval $start if $b_log;
my ($item,$mount) = @_;
@@ -19915,6 +21969,7 @@ sub get_mounts_fs {
main::log_data('data',"fs: $fs") if $b_log;
return $fs;
}
+
sub set_label_uuid {
eval $start if $b_log;
$loaded{'label-uuid'} = 1;
@@ -19931,7 +21986,7 @@ sub set_label_uuid {
eval $end if $b_log;
}
-# args: 1: blockdev full path (part only); 2: block id; 3: size (part only)
+# args: 0: blockdev full path (part only); 1: block id; 2: size (part only)
sub admin_data {
eval $start if $b_log;
my ($blockdev,$id,$size) = @_;
@@ -19958,6 +22013,7 @@ sub admin_data {
eval $end if $b_log;
return @sizes;
}
+
sub get_maj_min {
eval $start if $b_log;
my ($id) = @_;
@@ -19971,6 +22027,7 @@ sub get_maj_min {
eval $end if $b_log;
return $maj_min;
}
+
sub get_label {
eval $start if $b_log;
my ($item) = @_;
@@ -19988,6 +22045,7 @@ sub get_label {
eval $end if $b_log;
return $label;
}
+
sub get_root {
eval $start if $b_log;
my ($path) = ('/dev/root');
@@ -20034,11 +22092,20 @@ sub get_uuid {
## ProcessItem
{
package ProcessItem;
+# header:
+# 0: CMD
+# 1: PID
+# 2: %CPU
+# 3: %MEM
+# 4: RSS
+my $header;
+
sub get {
eval $start if $b_log;
my $num = 0;
my $rows = [];
if (@ps_aux){
+ $header = $ps_data{'header'}; # will always be set if @ps_aux
if ($show{'ps-cpu'}){
cpu_processes($rows);
}
@@ -20055,30 +22122,27 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub cpu_processes {
eval $start if $b_log;
my $rows = $_[0];
my ($j,$num,$cpu,$cpu_mem,$mem,$pid) = (0,0,'','','','');
- my ($pid_col,@ps_rows);
- my $count = ($b_irc)? 5: $ps_count;
- if ($ps_cols >= 10){
+ my (@ps_rows);
+ my $count = ($b_irc)? 5 : $ps_count;
+ if (defined $header->[2]){
@ps_rows = sort {
my @a = split(/\s+/, $a);
my @b = split(/\s+/, $b);
- $b[2] <=> $a[2] } @ps_aux;
- $pid_col = 1;
+ $b[$header->[2]] <=> $a[$header->[2]]
+ } @ps_aux;
}
else {
@ps_rows = @ps_aux;
- $pid_col = 0 if $ps_cols == 2;
}
- # if there's a count limit, for irc, etc, only use that much of the data
@ps_rows = splice(@ps_rows,0,$count);
$j = scalar @ps_rows;
- # $cpu_mem = ' - Memory: MiB / % used' if $extra > 0;
- my $throttled = throttled($ps_count,$count,$j);
- # my $header = "CPU % used - Command - pid$cpu_mem - top";
- # my $header = "Top $count by CPU";
+ # if there's a count limit, for irc, etc, only use that much of the data
+ my $throttled = throttled($ps_count,$count);
push(@$rows,{
main::key($num++,1,1,'CPU top') => "$count$throttled" . ' of ' . scalar @ps_aux
});
@@ -20087,54 +22151,59 @@ sub cpu_processes {
$num = 1;
$j = scalar @$rows;
my @row = split(/\s+/, $_);
- my $command = process_starter(scalar @row, $row[$ps_cols],$row[$ps_cols + 1]);
- $cpu = ($ps_cols >= 10) ? $row[2] . '%': 'N/A';
+ my $command = process_starter(
+ scalar @row,
+ $row[$header->[0]],
+ $row[$header->[0] + 1]
+ );
+ $cpu = (defined $header->[2]) ? $row[$header->[2]] . '%': 'N/A';
push(@$rows,{
main::key($num++,1,2,$i++) => '',
main::key($num++,0,3,'cpu') => $cpu,
main::key($num++,1,3,'command') => $command->[0],
});
if ($command->[1]){
- $rows->[$j]{main::key($num++,0,4,'started by')} = $command->[1];
+ $rows->[$j]{main::key($num++,0,4,'started-by')} = $command->[1];
}
- $pid = (defined $pid_col)? $row[$pid_col] : 'N/A';
+ $pid = (defined $header->[1])? $row[$header->[1]] : 'N/A';
$rows->[$j]{main::key($num++,0,3,'pid')} = $pid;
- if ($extra > 0 && $ps_cols >= 10){
- my $decimals = ($row[5]/1024 > 10) ? 1 : 2;
- $mem = (defined $row[5]) ? sprintf("%.${decimals}f", $row[5]/1024) . ' MiB' : 'N/A';
- $mem .= ' (' . $row[3] . '%)';
+ if ($extra > 0 && defined $header->[4]){
+ my $decimals = ($row[$header->[4]]/1024 > 10) ? 1 : 2;
+ $mem = (defined $row[$header->[4]]) ? sprintf("%.${decimals}f", $row[$header->[4]]/1024) . ' MiB' : 'N/A';
+ $mem .= ' (' . $row[$header->[3]] . '%)';
$rows->[$j]{main::key($num++,0,3,'mem')} = $mem;
}
# print Data::Dumper::Dumper \@processes, "i: $i; j: $j ";
}
eval $end if $b_log;
}
+
sub mem_processes {
eval $start if $b_log;
my $rows = $_[0];
my ($j,$num,$cpu,$cpu_mem,$mem,$pid) = (0,0,'','','','');
- my (@data,$pid_col,$memory,@ps_rows);
- my $count = ($b_irc)? 5: $ps_count;
- if ($ps_cols >= 10){
+ my (@data,$memory,@ps_rows);
+ my $count = ($b_irc)? 5 : $ps_count;
+ if (defined $header->[4]){
@ps_rows = sort {
my @a = split(/\s+/, $a);
my @b = split(/\s+/, $b);
- $b[5] <=> $a[5] } @ps_aux; # 5
- #$a[1] <=> $b[1] } @ps_aux; # 5
- $pid_col = 1;
+ $b[$header->[4]] <=> $a[$header->[4]]
+ } @ps_aux;
}
else {
@ps_rows = @ps_aux;
- $pid_col = 0 if $ps_cols == 2;
}
@ps_rows = splice(@ps_rows,0,$count);
# print Data::Dumper::Dumper \@rows;
- push(@$rows,main::MemoryData::full('process')) if !$loaded{'memory'};
+ if (!$loaded{'memory'}){
+ my $row = {};
+ main::MemoryData::row('process',$row,\$num,1);
+ push(@$rows,$row);
+ $num = 0;
+ }
$j = scalar @$rows;
- my $throttled = throttled($ps_count,$count,$j);
- #$cpu_mem = ' - CPU: % used' if $extra > 0;
- # my $header = "Memory MiB/% used - Command - pid$cpu_mem - top";
- # my $header = "Top $count by Memory";
+ my $throttled = throttled($ps_count,$count);
push(@$rows, {
main::key($num++,1,1,'Memory top') => "$count$throttled" . ' of ' . scalar @ps_aux
});
@@ -20143,38 +22212,41 @@ sub mem_processes {
$num = 1;
$j = scalar @$rows;
my @row = split(/\s+/, $_);
- if ($ps_cols >= 10){
- my $decimals = ($row[5]/1024 > 10) ? 1 : 2;
- $mem = (main::is_int($row[5])) ? sprintf("%.${decimals}f", $row[5]/1024) . ' MiB' : 'N/A';
- $mem .= " (" . $row[3] . "%)";
+ if (defined $header->[4]){
+ my $decimals = ($row[$header->[4]]/1024 > 10) ? 1 : 2;
+ $mem = (main::is_int($row[$header->[4]])) ?
+ sprintf("%.${decimals}f", $row[$header->[4]]/1024) . ' MiB' : 'N/A';
+ $mem .= " (" . $row[$header->[3]] . "%)";
}
else {
$mem = 'N/A';
}
- my $command = process_starter(scalar @row, $row[$ps_cols],$row[$ps_cols + 1]);
+ my $command = process_starter(scalar @row, $row[$header->[0]],$row[$header->[0] + 1]);
push(@$rows,{
main::key($num++,1,2,$i++) => '',
main::key($num++,0,3,'mem') => $mem,
main::key($num++,1,3,'command') => $command->[0],
});
if ($command->[1]){
- $rows->[$j]{main::key($num++,0,4,'started by')} = $command->[1];
+ $rows->[$j]{main::key($num++,0,4,'started-by')} = $command->[1];
}
- $pid = (defined $pid_col)? $row[$pid_col] : 'N/A';
+ $pid = (defined $header->[1])? $row[$header->[1]] : 'N/A';
$rows->[$j]{main::key($num++,0,3,'pid')} = $pid;
- if ($extra > 0 && $ps_cols >= 10){
- $cpu = $row[2] . '%';
+ if ($extra > 0 && defined $header->[2]){
+ $cpu = $row[$header->[2]] . '%';
$rows->[$j]{main::key($num++,0,3,'cpu')} = $cpu;
}
# print Data::Dumper::Dumper \@processes, "i: $i; j: $j ";
}
eval $end if $b_log;
}
+
sub process_starter {
my ($count, $row10, $row11) = @_;
my $return = [];
# note: [migration/0] would clear with a simple basename
- if ($count > ($ps_cols + 1) && $row11 =~ /^\// && $row11 !~ /^\/(tmp|temp)/){
+ if ($count > ($header->[0] + 1) &&
+ $row11 =~ /^\// && $row11 !~ /^\/(tmp|temp)/){
$row11 =~ s/^\/.*\///;
$return->[0] = $row11;
$row10 =~ s/^\/.*\///;
@@ -20187,16 +22259,10 @@ sub process_starter {
}
return $return;
}
+
+# args: 0: $ps_count; 1: $count
sub throttled {
- my ($ps_count,$count,$j) = @_;
- my $throttled = '';
- if ($count > $j){
- $throttled = " ( $j processes)"; # space to avoid emoji in irc
- }
- elsif ($count < $ps_count){
- $throttled = " (throttled from $ps_count)";
- }
- return $throttled;
+ return ($_[1] < $_[0]) ? " (throttled from $_[0])" : '';
}
}
@@ -20248,6 +22314,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub hw_output {
eval $start if $b_log;
my ($rows,$hardware_raid) = @_;
@@ -20285,6 +22352,7 @@ sub hw_output {
eval $end if $b_log;
# print Data::Dumper::Dumper $rows;
}
+
sub btrfs_output {
eval $start if $b_log;
my $rows = $_[0];
@@ -20301,6 +22369,7 @@ sub btrfs_output {
eval $end if $b_log;
# print Data::Dumper::Dumper $rows;
}
+
sub lvm_output {
eval $start if $b_log;
my $rows = $_[0];
@@ -20322,7 +22391,6 @@ sub lvm_output {
if ($row->{'raid-sync'}){
$rows->[$j]{main::key($num++,0,2,'sync')} = $row->{'raid-sync'};
}
-
if ($extra > 0){
$j = scalar @$rows;
$num = 1;
@@ -20364,6 +22432,7 @@ sub lvm_output {
eval $end if $b_log;
# print Data::Dumper::Dumper $rows;
}
+
sub md_output {
eval $start if $b_log;
my $rows = $_[0];
@@ -20661,7 +22730,7 @@ sub zfs_output {
# print Data::Dumper::Dumper $rows;
}
-## Most key stuff passed by ref, and is changed on the fly
+# Most key stuff passed by ref, and is changed on the fly
sub components_output {
eval $start if $b_log;
my ($type,$item,$rows,$array,$j,$num,$b_bump) = @_;
@@ -20755,17 +22824,18 @@ sub raid_data {
}
eval $end if $b_log;
}
-# 0 type
-# 1 type_id
-# 2 bus_id
-# 3 sub_id
-# 4 device
-# 5 vendor_id
-# 6 chip_id
-# 7 rev
-# 8 port
-# 9 driver
-# 10 modules
+
+# 0: type
+# 1: type_id
+# 2: bus_id
+# 3: sub_id
+# 4: device
+# 5: vendor_id
+# 6: chip_id
+# 7: rev
+# 8: port
+# 9: driver
+# 10: modules
sub hw_data {
eval $start if $b_log;
return if !$devices{'hwraid'};
@@ -20796,6 +22866,8 @@ sub hw_data {
eval $end if $b_log;
return $hardware_raid;
}
+
+# Placeholder, if they ever get useful tools
sub btrfs_data {
eval $start if $b_log;
my (@btraid,@working);
@@ -20811,6 +22883,7 @@ sub btrfs_data {
eval $end if $b_log;
return @btraid;
}
+
sub lvm_data {
eval $start if $b_log;
LogicalItem::lvm_data() if !$loaded{'logical-data'};
@@ -20869,19 +22942,20 @@ sub lvm_data {
eval $end if $b_log;
return @lvraid;
}
+
sub md_data {
eval $start if $b_log;
my ($mdstat) = @_;
my $j = 0;
if ($fake{'raid-md'}){
- #$mdstat = "$fake_data_dir/raid/md-4-device-1.txt";
- #$mdstat = "$fake_data_dir/raid/md-rebuild-1.txt";
- #$mdstat = "$fake_data_dir/raid/md-2-mirror-fserver2-1.txt";
- #$mdstat = "$fake_data_dir/raid/md-2-raid10-abucodonosor.txt";
- #$mdstat = "$fake_data_dir/raid/md-2-raid10-ant.txt";
- #$mdstat = "$fake_data_dir/raid/md-inactive-weird-syntax.txt";
- #$mdstat = "$fake_data_dir/raid/md-inactive-active-syntax.txt";
- #$mdstat = "$fake_data_dir/raid/md-inactive-active-spare-syntax.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-4-device-1.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-rebuild-1.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-2-mirror-fserver2-1.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-2-raid10-abucodonosor.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-2-raid10-ant.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-inactive-weird-syntax.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-inactive-active-syntax.txt";
+ #$mdstat = "$fake_data_dir/raid-logical/md/md-inactive-active-spare-syntax.txt";
}
my @working = main::reader($mdstat,'strip');
# print Data::Dumper::Dumper \@working;
@@ -21024,6 +23098,7 @@ sub md_data {
eval $end if $b_log;
return @mdraid;
}
+
sub md_details {
eval $start if $b_log;
my ($id) = @_;
@@ -21165,11 +23240,11 @@ sub zfs_data {
my ($i,$j,$k) = (0,0,0);
if ($fake{'raid-zfs'}){
# my $file;
- # $file = "$fake_data_dir/raid/zpool-list-1-mirror-main-solestar.txt";
- # $file = "$fake_data_dir/raid/zpool-list-2-mirror-main-solestar.txt";
- # $file = "$fake_data_dir/raid/zpool-list-v-tank-1.txt";
- # $file = "$fake_data_dir/raid/zpool-list-v-gojev-1.txt";
- # $file = "$fake_data_dir/raid/zpool-list-v-w-spares-1.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-list-1-mirror-main-solestar.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-list-2-mirror-main-solestar.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-list-v-tank-1.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-list-v-gojev-1.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-list-v-w-spares-1.txt";
#@working = main::reader($file);$zpool = '';
}
else {
@@ -21345,6 +23420,7 @@ sub zfs_data {
eval $end if $b_log;
return @zfs;
}
+
sub zfs_fs_sizes {
my ($path,$id) = @_;
eval $start if $b_log;
@@ -21366,6 +23442,7 @@ sub zfs_fs_sizes {
eval $end if $b_log;
return @data;
}
+
sub zfs_status {
eval $start if $b_log;
my ($zpool,$zfs) = @_;
@@ -21376,9 +23453,9 @@ sub zfs_status {
$k = 0;
if ($fake{'raid-zfs'}){
my $file;
- # $file = "$fake_data_dir/raid/zpool-status-1-mirror-main-solestar.txt";
- # $file = "$fake_data_dir/raid/zpool-status-2-mirror-main-solestar.txt";
- # $file = "$fake_data_dir/raid/zpool-status-tank-1.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-status-1-mirror-main-solestar.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-status-2-mirror-main-solestar.txt";
+ # $file = "$fake_data_dir/raid-logical/zfs/zpool-status-tank-1.txt";
#@pool_status = main::reader($file,'strip');
}
else {
@@ -21418,6 +23495,7 @@ sub zfs_status {
eval $end if $b_log;
return @$zfs;
}
+
sub check_zfs_status {
eval $start if $b_log;
my ($item,$pool_status) = @_;
@@ -21438,14 +23516,14 @@ sub check_zfs_status {
## RamItem
{
package RamItem;
-my ($vendors,$vendor_ids);
+my ($speed_maps,$vendors,$vendor_ids);
+my $ram_total = 0;
sub get {
- my ($key1,$ram,$val1);
- my $rows = [];
+ my ($key1,$val1);
+ my ($ram,$rows) = ([],[]);
my $num = 0;
- push(@$rows, MemoryData::full('ram')) if !$loaded{'memory'};
if ($bsd_type && !$force{'dmidecode'} && ($dboot{'ram'} || $fake{'dboot'})){
- $ram = dboot_data();
+ dboot_data($ram);
if (@$ram){
ram_output($rows,$ram,'dboot');
}
@@ -21458,21 +23536,43 @@ sub get {
});
}
}
- elsif ($fake{'dmidecode'} || $alerts{'dmidecode'}->{'action'} eq 'use'){
- $ram = dmidecode_data();
+ elsif (!$fake{'udevadm'} && !$force{'udevadm'} && ($fake{'dmidecode'} ||
+ $alerts{'dmidecode'}->{'action'} eq 'use')){
+ dmidecode_data($ram);
if (@$ram){
ram_output($rows,$ram,'dmidecode');
}
else {
$key1 = 'message';
- $val1 = main::message('ram-data');
+ $val1 = main::message('ram-data','dmidecode');
push(@$rows, {
main::key($num++,1,1,'RAM Report') => '',
main::key($num++,0,2,$key1) => $val1,
});
}
}
- else {
+ elsif ($fake{'udevadm'} || $alerts{'udevadm'}->{'action'} eq 'use'){
+ udevadm_data($ram);
+ if (@$ram){
+ ram_output($rows,$ram,'udevadm');
+ }
+ else {
+ $key1 = 'message';
+ my ($n,$v) = ProgramData::full('udevadm'); # v will be null/numeric start
+ $v =~ s/^(\d+)([^\d].*)?/$1/ if $v;
+ if ($v && $v < 249){
+ $val1 = main::message('ram-udevadm-version',$v);
+ }
+ else {
+ $val1 = main::message('ram-data','udevadm');
+ }
+ push(@$rows, {
+ main::key($num++,1,1,'RAM Report') => '',
+ main::key($num++,0,2,$key1) => $val1,
+ });
+ }
+ }
+ if (!$key1 && !@$ram) {
$key1 = $alerts{'dmidecode'}->{'action'};
$val1 = $alerts{'dmidecode'}->{'message'};
push(@$rows, {
@@ -21480,57 +23580,94 @@ sub get {
main::key($num++,0,2,$key1) => $val1,
});
}
+ # we want the real installed RAM total if detected so add this after.
+ if (!$loaded{'memory'}){
+ $num = 0;
+ my $system_ram = {};
+ MemoryData::row('ram',$system_ram,\$num,1);
+ unshift(@$rows,$system_ram);
+ }
($vendors,$vendor_ids) = ();
eval $end if $b_log;
return $rows;
}
+sub ram_total {
+ return $ram_total;
+}
+
sub ram_output {
eval $start if $b_log;
my ($rows,$ram,$source) = @_;
return if !@$ram;
my $num = 0;
my $j = 0;
+ my $arrays = {};
+ set_arrays_data($ram,$arrays);
my ($b_non_system);
- my ($arrays,$modules,$slots,$type_holder) = (0,0,0,'');
if ($source eq 'dboot'){
push(@$rows, {
main::key($num++,0,1,'Message') => main::message('ram-data-complete'),
});
}
- foreach my $item (@$ram){
- $j = scalar @$rows;
- if (!$show{'ram-short'}){
- $b_non_system = ($item->{'use'} && lc($item->{'use'}) ne 'system memory') ? 1:0 ;
- $num = 1;
+ # really only volts are inaccurate, possibly configured speed? Servers have
+ # very poor data quality, so always show for udevadm and high slot counts
+ # don't need t show for risc since if not dmi data, not running ram_output()
+ if (!$show{'ram-short'} && $source eq 'udevadm' &&
+ ($extra > 1 || ($arrays->{'slots'} && $arrays->{'slots'} > 4))){
+ my $message;
+ if (!$b_root){
+ $message = main::message('ram-udevadm');
+ }
+ elsif ($b_root && $alerts{'dmidecode'}->{'action'} eq 'missing'){
+ $message = main::message('ram-udevadm-root');
+ }
+ if ($message){
push(@$rows, {
- main::key($num++,1,1,'Array') => '',
- main::key($num++,1,2,'capacity') => process_size($item->{'capacity'}),
+ main::key($num++,1,1,'Message') => $message,
});
- if ($item->{'cap-qualifier'}){
- $rows->[$j]{main::key($num++,0,3,'note')} = $item->{'cap-qualifier'};
- }
- $rows->[$j]{main::key($num++,0,2,'use')} = $item->{'use'} if $b_non_system;
- $rows->[$j]{main::key($num++,1,2,'slots')} = $item->{'slots'};
- if ($item->{'slots-qualifier'}){
- $rows->[$j]{main::key($num++,0,3,'note')} = $item->{'slots-qualifier'};
- }
- $item->{'eec'} ||= 'N/A';
- $rows->[$j]{main::key($num++,0,2,'EC')} = $item->{'eec'};
- if ($extra > 0 && (!$b_non_system ||
- (main::is_numeric($item->{'max-module-size'}) && $item->{'max-module-size'} > 10))){
- $rows->[$j]{main::key($num++,1,2,'max-module-size')} = process_size($item->{'max-module-size'});
- if ($item->{'mod-qualifier'}){
- $rows->[$j]{main::key($num++,0,3,'note')} = $item->{'mod-qualifier'};
- }
- }
- if ($extra > 1 && $item->{'voltage'}){
- $rows->[$j]{main::key($num++,0,2,'voltage')} = $item->{'voltage'};
+ }
+ }
+ if (scalar @$ram > 1 || $show{'ram-short'}){
+ arrays_output($rows,$ram,$arrays);
+ if ($show{'ram-short'}){
+ eval $end if $b_log;
+ return 0;
+ }
+ }
+ foreach my $item (@$ram){
+ $j = scalar @$rows;
+ $num = 1;
+ $b_non_system = ($item->{'use'} && lc($item->{'use'}) ne 'system memory') ? 1: 0;
+ push(@$rows, {
+ main::key($num++,1,1,'Array') => '',
+ main::key($num++,1,2,'capacity') => process_size($item->{'capacity'}),
+ });
+ if ($item->{'cap-qualifier'}){
+ $rows->[$j]{main::key($num++,0,3,'note')} = $item->{'cap-qualifier'};
+ }
+ # show if > 1 array otherwise shows in System RAM line.
+ if (scalar @$ram > 1){
+ $rows->[$j]{main::key($num++,0,2,'installed')} = process_size($item->{'used-capacity'});
+ }
+ $rows->[$j]{main::key($num++,0,2,'use')} = $item->{'use'} if $b_non_system;
+ $rows->[$j]{main::key($num++,1,2,'slots')} = $item->{'slots'};
+ if ($item->{'slots-qualifier'}){
+ $rows->[$j]{main::key($num++,0,3,'note')} = $item->{'slots-qualifier'};
+ }
+ $rows->[$j]{main::key($num++,0,2,'modules')} = $item->{'slots-active'};
+ $item->{'eec'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,2,'EC')} = $item->{'eec'};
+ if ($extra > 0 && (!$b_non_system ||
+ (main::is_numeric($item->{'max-module-size'}) &&
+ $item->{'max-module-size'} > 10))){
+ $rows->[$j]{main::key($num++,1,2,'max-module-size')} = process_size($item->{'max-module-size'});
+ if ($item->{'mod-qualifier'}){
+ $rows->[$j]{main::key($num++,0,3,'note')} = $item->{'mod-qualifier'};
}
}
- else {
- $slots += $item->{'slots'} if $item->{'slots'};
- $arrays++;
+ if ($extra > 1 && $item->{'voltage'}){
+ $rows->[$j]{main::key($num++,0,2,'voltage')} = $item->{'voltage'};
}
foreach my $entry ($item->{'modules'}){
next if ref $entry ne 'ARRAY';
@@ -21538,19 +23675,14 @@ sub ram_output {
foreach my $mod (@$entry){
$num = 1;
$j = scalar @$rows;
- # multi array setups will start index at next from previous array
+ # Multi array setups will start index at next from previous array
next if ref $mod ne 'HASH';
- if ($show{'ram-short'}){
- $modules++ if ($mod->{'size'} =~ /^\d/);
- $type_holder = $mod->{'device-type'} if $mod->{'device-type'};
- next;
- }
next if ($show{'ram-modules'} && $mod->{'size'} =~ /\D/);
$mod->{'locator'} ||= 'N/A';
push(@$rows, {
main::key($num++,1,2,'Device') => $mod->{'locator'},
});
- # this will contain the no module string
+ # This will contain the no module string
if ($mod->{'size'} =~ /\D/){
$rows->[$j]{main::key($num++,0,3,'type')} = lc($mod->{'size'});
next;
@@ -21569,27 +23701,35 @@ sub ram_output {
$mod->{'speed'} ne $mod->{'configured-clock-speed'}){
$rows->[$j]{main::key($num++,1,3,'speed')} = '';
$rows->[$j]{main::key($num++,0,4,'spec')} = $mod->{'speed'};
- $rows->[$j]{main::key($num++,0,4,'note')} = $mod->{'speed-note'} if $mod->{'speed-note'};
+ if ($mod->{'speed-note'}){
+ $rows->[$j]{main::key($num++,0,4,'note')} = $mod->{'speed-note'};
+ }
$rows->[$j]{main::key($num++,0,4,'actual')} = $mod->{'configured-clock-speed'};
- $rows->[$j]{main::key($num++,0,5,'note')} = $mod->{'configured-note'} if $mod->{'configured-note'};
+ if ($mod->{'configured-note'}){
+ $rows->[$j]{main::key($num++,0,5,'note')} = $mod->{'configured-note'};
+ }
}
else {
if (!$mod->{'speed'} && $mod->{'configured-clock-speed'}){
if ($mod->{'configured-clock-speed'}){
$mod->{'speed'} = $mod->{'configured-clock-speed'};
- $mod->{'speed-note'} = $mod->{'configured-note'} if $mod->{'configured-note'} ;
+ if ($mod->{'configured-note'}){
+ $mod->{'speed-note'} = $mod->{'configured-note'};
+ }
}
}
- # rare instances, dmi type 6, no speed, dboot also no speed
+ # Rare instances, dmi type 6, no speed, dboot also no speed
$mod->{'speed'} ||= 'N/A';
$rows->[$j]{main::key($num++,1,3,'speed')} = $mod->{'speed'};
- $rows->[$j]{main::key($num++,0,4,'note')} = $mod->{'speed-note'} if $mod->{'speed-note'};
+ if ($mod->{'speed-note'}){
+ $rows->[$j]{main::key($num++,0,4,'note')} = $mod->{'speed-note'};
+ }
}
- # handle cases where -xx or -xxx and no voltage data (common) or voltages
+ # Handle cases where -xx or -xxx and no voltage data (common) or voltages
# are all the same.
if ($extra > 1){
- if (($mod->{'voltage-config'} || $mod->{'voltage-max'} || $mod->{'voltage-min'}) &&
- ($b_admin || (
+ if (($mod->{'voltage-config'} || $mod->{'voltage-max'} ||
+ $mod->{'voltage-min'}) && ($b_admin || (
($mod->{'voltage-config'} && $mod->{'voltage-max'} &&
$mod->{'voltage-config'} ne $mod->{'voltage-max'}) ||
($mod->{'voltage-config'} && $mod->{'voltage-min'} &&
@@ -21598,6 +23738,9 @@ sub ram_output {
$mod->{'voltage-max'} ne $mod->{'voltage-min'})
))){
$rows->[$j]{main::key($num++,1,3,'volts')} = '';
+ if ($mod->{'voltage-note'}){
+ $rows->[$j]{main::key($num++,0,4,'note')} = $mod->{'voltage-note'};
+ }
if ($mod->{'voltage-config'}){
$rows->[$j]{main::key($num++,0,4,'curr')} = $mod->{'voltage-config'};
}
@@ -21610,60 +23753,197 @@ sub ram_output {
}
else {
$mod->{'voltage-config'} ||= 'N/A';
- $rows->[$j]{main::key($num++,0,3,'volts')} = $mod->{'voltage-config'};
+ $rows->[$j]{main::key($num++,1,3,'volts')} = $mod->{'voltage-config'};
+ if ($mod->{'voltage-note'}){
+ $rows->[$j]{main::key($num++,0,4,'note')} = $mod->{'voltage-note'};
+ }
}
}
- if ($source ne 'dboot' && $extra > 2){
- if (!$mod->{'data-width'} && !$mod->{'total-width'}){
- $rows->[$j]{main::key($num++,0,3,'width')} = 'N/A';
+ if ($source ne 'dboot'){
+ if ($extra > 2){
+ if (!$mod->{'data-width'} && !$mod->{'total-width'}){
+ $rows->[$j]{main::key($num++,0,3,'width')} = 'N/A';
+ }
+ else {
+ $rows->[$j]{main::key($num++,1,3,'width (bits)')} = '';
+ $mod->{'data-width'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,4,'data')} = $mod->{'data-width'};
+ $mod->{'total-width'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,4,'total')} = $mod->{'total-width'};
+ }
}
- else {
- $rows->[$j]{main::key($num++,1,3,'width (bits)')} = '';
- $mod->{'data-width'} ||= 'N/A';
- $rows->[$j]{main::key($num++,0,4,'data')} = $mod->{'data-width'};
- $mod->{'total-width'} ||= 'N/A';
- $rows->[$j]{main::key($num++,0,4,'total')} = $mod->{'total-width'};
+ if ($extra > 1){
+ $mod->{'manufacturer'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'manufacturer')} = $mod->{'manufacturer'};
+ $mod->{'part-number'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,0,3,'part-no')} = $mod->{'part-number'};
+ }
+ if ($b_admin && $mod->{'firmware'}){
+ $rows->[$j]{main::key($num++,0,3,'firmware')} = $mod->{'firmware'};
+ }
+ if ($extra > 2){
+ $mod->{'serial'} = main::filter($mod->{'serial'});
+ $rows->[$j]{main::key($num++,0,3,'serial')} = $mod->{'serial'};
}
}
- if ($source ne 'dboot' && $extra > 1){
- $mod->{'manufacturer'} ||= 'N/A';
- $rows->[$j]{main::key($num++,0,3,'manufacturer')} = $mod->{'manufacturer'};
- $mod->{'part-number'} ||= 'N/A';
- $rows->[$j]{main::key($num++,0,3,'part-no')} = $mod->{'part-number'};
+ }
+ }
+ }
+ eval $end if $b_log;
+}
+
+# args: 0: $rows ref; 1: $ram ref;
+sub arrays_output {
+ eval $end if $b_log;
+ my ($rows,$ram,$arrays) = @_;
+ my $num = 1;
+ $arrays->{'arrays'} ||= 'N/A';
+ $arrays->{'capacity'} ||= 'N/A';
+ $arrays->{'used-capacity'} ||= 'N/A';
+ $arrays->{'eec'} ||= 'N/A';
+ $arrays->{'slots'} ||= 'N/A';
+ $arrays->{'slots-active'} ||= 'N/A';
+ $arrays->{'device-type'} ||= 'N/A';
+ push(@$rows, {
+ main::key($num++,1,1,'Report') => '',
+ main::key($num++,1,2,'arrays') => $arrays->{'arrays'},
+ main::key($num++,1,2,'capacity') => process_size($arrays->{'capacity'}),
+ main::key($num++,0,3,'installed') => process_size($arrays->{'used-capacity'}),
+ main::key($num++,1,2,'slots') => $arrays->{'slots'},
+ main::key($num++,0,3,'active') => $arrays->{'slots-active'},
+ main::key($num++,0,2,'type') => $arrays->{'device-type'},
+ main::key($num++,0,2,'eec') => $arrays->{'eec'},
+ });
+ eval $end if $b_log;
+}
+
+sub set_arrays_data {
+ my ($ram,$arrays) = @_;
+ $arrays->{'arrays'} = 0;
+ $arrays->{'capacity'} = 0;
+ $arrays->{'used-capacity'} = 0;
+ $arrays->{'slots'} = 0;
+ $arrays->{'slots-active'} = 0;
+ foreach my $array (@$ram){
+ $arrays->{'arrays'}++;
+ $arrays->{'capacity'} += $array->{'capacity'} if $array->{'capacity'};
+ $arrays->{'used-capacity'} += $array->{'used-capacity'} if $array->{'used-capacity'};
+ $arrays->{'eec'} = $array->{'eec'} if !$arrays->{'eec'} && $array->{'eec'};
+ $arrays->{'slots'} += $array->{'slots'} if $array->{'slots'};
+ $arrays->{'slots-active'} += $array->{'slots-active'} if $array->{'slots-active'};
+ $arrays->{'device-type'} = $array->{'device-type'} if !$arrays->{'device-type'} && $array->{'device-type'};
+ }
+}
+
+# args: 0: $ram ref;
+sub dboot_data {
+ eval $start if $b_log;
+ my $ram = $_[0];
+ my $est = main::message('note-est');
+ my ($arr,$derived_module_size,$subtract) = (0,0,0);
+ my ($holder,@slots_active);
+ foreach (@{$dboot{'ram'}}){
+ my ($addr,$detail,$device_detail,$ecc,$iic,$locator,$size,$speed,$type);
+ # Note: seen a netbsd with multiline spdmem0/1 etc but not consistent, don't use
+ if (/^(spdmem([\d]+)):at iic([\d]+)(\saddr 0x([0-9a-f]+))?/){
+ $iic = $3;
+ $locator = $1;
+ $holder = $iic if !defined $holder; # prime for first use
+ # Note: seen iic2 as only device
+ if ($iic != $holder){
+ if ($ram->[$arr] && $ram->[$arr]{'slots-16'}){
+ $subtract += $ram->[$arr]{'slots-16'};
}
- if ($source ne 'dboot' && $extra > 2){
- $mod->{'serial'} = main::filter($mod->{'serial'});
- $rows->[$j]{main::key($num++,0,3,'serial')} = $mod->{'serial'};
+ $holder = $iic;
+ # Then since we are on a new iic device, assume new ram array.
+ # This needs more data to confirm this guess.
+ $arr++;
+ $slots_active[$arr] = 0;
+ }
+ if ($5){
+ $addr = hex($5);
+ }
+ if (/(non?[\s-]parity)/i){
+ $device_detail = $1;
+ $ecc = 'None';
+ }
+ elsif (/EEC/i){
+ $device_detail = 'EEC';
+ $ecc = 'EEC';
+ }
+ # Possible: PC2700CL2.5 PC3-10600
+ if (/\b(PC([2-9]?-|)\d{4,})[^\d]/){
+ $speed = $1;
+ $speed =~ s/PC/PC-/ if $speed =~ /^PC\d{4}/;
+ my $temp = speed_mapper($speed);
+ if ($temp ne $speed){
+ $detail = $speed;
+ $speed = $temp;
}
}
+ # We want to avoid netbsd trying to complete @ram without real data.
+ if (/:(\d+[MGT])B?\s(DDR[0-9]*)\b/){
+ $size = main::translate_size($1); # mbfix: /1024
+ $type = $2;
+ if ($addr){
+ $ram->[$arr]{'slots-16'} = $addr - 80 + 1 - $subtract;
+ $locator = 'Slot-' . $ram->[$arr]{'slots-16'};
+ }
+ $slots_active[$arr]++;
+ $derived_module_size = $size if $size > $derived_module_size;
+ $ram->[$arr]{'derived-module-size'} = $derived_module_size;
+ $ram->[$arr]{'device-count-found'}++;
+ $ram->[$arr]{'eec'} = $ecc if !$ram->[$arr]{'eec'} && $ecc;
+ # Build up actual capacity found for override tests
+ $ram->[$arr]{'max-capacity-16'} += $size;
+ $ram->[$arr]{'max-cap-qualifier'} = $est;
+ $ram->[$arr]{'slots-16'}++ if !$addr;
+ $ram->[$arr]{'slots-active'} = $slots_active[$arr];
+ $ram->[$arr]{'slots-qualifier'} = $est;
+ $ram->[$arr]{'type'} = $type;
+ $ram->[$arr]{'used-capacity'} += $size;
+ if (!$ram->[$arr]{'device-type'} && $type){
+ $ram->[$arr]{'device-type'} = $type;
+ }
+ push(@{$ram->[$arr]{'modules'}},{
+ 'device-type' => $type,
+ 'device-type-detail' => $detail,
+ 'locator' => $locator,
+ 'size' => $size,
+ 'speed' => $speed,
+ });
+ }
}
}
- if ($show{'ram-short'}){
- $num = 1;
- $type_holder ||= 'N/A';
- push(@$rows, {
- main::key($num++,1,1,'Report') => '',
- main::key($num++,0,2,'arrays') => $arrays,
- main::key($num++,0,2,'slots') => $slots,
- main::key($num++,0,2,'modules') => $modules,
- main::key($num++,0,2,'type') => $type_holder,
- });
+ for (my $i = 0; $i++ ;scalar @$ram){
+ next if ref $ram->[$i] ne 'HASH';
+ # 1 slot is possible, but 3 is very unlikely due to dual channel ddr
+ if ($ram->[$i]{'slots'} && $ram->[$i]{'slots'} > 2 && $ram->[$i]{'slots'} % 2 == 1){
+ $ram->[$i]{'slots'}++;
+ }
}
+ print 'dboot pre process_data: ', Data::Dumper::Dumper $ram if $dbg[36];
+ main::log_data('dump','@$ram',$ram) if $b_log;
+ process_data($ram) if @$ram;
+ main::log_data('dump','@$ram',$ram) if $b_log;
+ print 'dboot post process_data: ', Data::Dumper::Dumper $ram if $dbg[36];
eval $end if $b_log;
}
+# args: 0: $ram ref;
sub dmidecode_data {
eval $start if $b_log;
- my ($b_5,$handle,@temp);
+ my $ram = $_[0];
+ my ($b_5,$handle,@slots_active,@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 $ram = [];
my $check = main::message('note-check');
# print Data::Dumper::Dumper \@dmi;
foreach my $entry (@dmi){
- ## NOTE: do NOT reset these values, that causes failures
+ ## Note: do NOT reset these values, that causes failures
# ($derived_module_size,$max_cap_5,$max_cap_16,$max_module_size) = (0,0,0,0);
if ($entry->[0] == 5){
+ $slots_active[$k] = 0;
foreach my $item (@$entry){
@temp = split(/:\s*/, $item, 2);
next if !$temp[1];
@@ -21684,7 +23964,7 @@ sub dmidecode_data {
}
elsif ($temp[0] eq 'Error Detecting Method'){
$temp[1] ||= 'None';
- $ram->[$k]{'eec'} = $temp[1];
+ $ram->[$k]{'eec'} = $temp[1] if !$ram->[$k]{'eec'} && $temp[1];
}
}
$ram->[$k]{'modules'} = [];
@@ -21698,17 +23978,18 @@ sub dmidecode_data {
@temp = split(/:\s*/, $item, 2);
next if !$temp[1];
if ($temp[0] eq 'Installed Size'){
- # get module size
+ # Get module size
$size = calculate_size($temp[1],0);
- # using this causes issues, really only works for 16
-# if ($size =~ /^[0-9][0-9]+$/){
-# $ram->[$k]{'device-count-found'}++;
-# $ram->[$k]{'used-capacity'} += $size;
-# }
- # get data after module size
+ # Using this causes issues, really only works for 16
+ # if ($size =~ /^[0-9][0-9]+$/){
+ # $ram->[$k]{'device-count-found'}++;
+ # $ram->[$k]{'used-capacity'} += $size;
+ # }
+ # Get data after module size
$temp[1] =~ s/ Connection\)?//;
$temp[1] =~ s/^[0-9]+\s*[KkMGTP]B\s*\(?//;
$type = lc($temp[1]);
+ $slots_active[$k]++;
}
elsif ($temp[0] eq 'Current Speed'){
$speed = main::clean_dmi($temp[1]);
@@ -21724,9 +24005,10 @@ sub dmidecode_data {
$device_type = main::clean_dmi($temp[1]);
}
}
- # because of the wide range of bank/slot type data, we will just use
- # the one that seems most likely to be right. Some have: Bank: SO DIMM 0 slot: J6A
- # so we dump the useless data and use the one most likely to be visibly correct
+ # Because of the wide range of bank/slot type data, we will just use
+ # the one that seems most likely to be right. Some have:
+ # 'Bank: SO DIMM 0 slot: J6A' so we dump the useless data and use the
+ # one most likely to be visibly correct
if ($bank_locator =~ /DIMM/){
$main_locator = $bank_locator;
}
@@ -21734,12 +24016,16 @@ sub dmidecode_data {
$main_locator = $locator;
}
$ram->[$k]{'modules'}[$j] = {
+ 'slots-active' => $slots_active[$k],
'device-type' => $device_type,
'locator' => $main_locator,
'size' => $size,
'speed' => $speed,
'type' => $type,
};
+ if (!$ram->[$k]{'device-type'} && $device_type){
+ $ram->[$k]{'device-type'} = $device_type;
+ }
# print Data::Dumper::Dumper \@ram;
$j++;
}
@@ -21747,6 +24033,7 @@ sub dmidecode_data {
$handle = $entry->[1];
$ram->[$handle] = $ram->[$k] if $ram->[$k];
$ram->[$k] = undef;
+ $slots_active[$handle] = 0;
# ($derived_module_size,$max_cap_16) = (0,0);
foreach my $item (@$entry){
@temp = split(/:\s*/, $item, 2);
@@ -21755,7 +24042,7 @@ sub dmidecode_data {
$max_cap_16 = calculate_size($temp[1],$max_cap_16);
$ram->[$handle]{'max-capacity-16'} = $max_cap_16;
}
- # note: these 3 have cleaned data in DmiData, so replace stuff manually
+ # Note: these 3 have cleaned data in DmiData, so replace stuff manually
elsif ($temp[0] eq 'Location'){
$temp[1] =~ s/\sOr\sMotherboard//;
$temp[1] ||= 'System Board';
@@ -21766,8 +24053,14 @@ sub dmidecode_data {
$ram->[$handle]{'use'} = $temp[1];
}
elsif ($temp[0] eq 'Error Correction Type'){
+ # seen <OUT OF SPEC>
+ if ($temp[1] && lc($temp[1]) ne 'none'){
+ $temp[1] = main::clean_dmi($temp[1]);
+ }
$temp[1] ||= 'None';
- $ram->[$handle]{'eec'} = $temp[1];
+ if (!$ram->[$handle]{'eec'} && $temp[1]){
+ $ram->[$handle]{'eec'} = $temp[1];
+ }
}
elsif ($temp[0] eq 'Number Of Devices'){
$ram->[$handle]{'slots-16'} = $temp[1];
@@ -21782,8 +24075,8 @@ sub dmidecode_data {
elsif ($entry->[0] == 17){
my ($bank_locator,$configured_speed,$configured_note,
$data_width) = ('','','','');
- my ($device_type,$device_type_detail,$form_factor,$locator,
- $main_locator) = ('','','','','');
+ my ($device_type,$device_type_detail,$firmware,$form_factor,$locator,
+ $main_locator) = ('','','','','','');
my ($manufacturer,$vendor_id,$part_number,$serial,$speed,$speed_note,
$total_width) = ('','','','','','','');
my ($voltage_config,$voltage_max,$voltage_min);
@@ -21794,7 +24087,7 @@ sub dmidecode_data {
if ($temp[0] eq 'Array Handle'){
$handle = hex($temp[1]);
}
- # these two can have 'none' or 'unknown' value
+ # These two can have 'none' or 'unknown' value
elsif ($temp[0] eq 'Data Width'){
$data_width = main::clean_dmi($temp[1]);
$data_width =~ s/[\s_-]?bits// if $data_width;
@@ -21803,16 +24096,18 @@ sub dmidecode_data {
$total_width = main::clean_dmi($temp[1]);
$total_width =~ s/[\s_-]?bits// if $total_width;
}
- # do not try to guess from installed modules, only use this to correct type 5 data
+ # Do not try to guess from installed modules, only use this to correct
+ # type 5 data
elsif ($temp[0] eq 'Size'){
# we want any non real size data to be preserved
if ($temp[1] =~ /^[0-9]+\s*[KkMTPG]i?B/){
$derived_module_size = calculate_size($temp[1],$derived_module_size);
$working_size = calculate_size($temp[1],0);
$device_size = $working_size;
+ $slots_active[$handle]++;
}
else {
- $device_size = $temp[1];
+ $device_size = ($temp[1] =~ /no module/i) ? main::message('ram-no-module') : $temp[1];
}
}
elsif ($temp[0] eq 'Locator'){
@@ -21833,14 +24128,37 @@ sub dmidecode_data {
$device_type_detail = main::clean_dmi($temp[1]);
}
elsif ($temp[0] eq 'Speed'){
- my $result = process_speed($temp[1],$device_type,$check);
- ($speed,$speed_note) = @$result;
+ my ($working,$unit);
+ $temp[1] = main::clean_dmi($temp[1]);
+ if ($temp[1] && $temp[1] =~ /^(\d+)\s*([GM]\S+)/){
+ $working = $1;
+ $unit = $2;
+ my $result = process_speed($unit,$working,$device_type,$check);
+ ($speed,$speed_note) = @$result;
+ }
+ else {
+ $speed = $temp[1];
+ }
}
- # this is the actual speed the system booted at, speed is hardcoded
+ # This is the actual speed the system booted at, speed is hardcoded
# clock speed means MHz, memory speed MT/S
- elsif ($temp[0] eq 'Configured Clock Speed' || $temp[0] eq 'Configured Memory Speed'){
- my $result = process_speed($temp[1],$device_type,$check);
- ($configured_speed,$configured_note) = @$result;
+ elsif ($temp[0] eq 'Configured Clock Speed' ||
+ $temp[0] eq 'Configured Memory Speed'){
+ my ($working,$unit);
+ $temp[1] = main::clean_dmi($temp[1]);
+ if ($temp[1] && $temp[1] =~ /^(\d+)\s*([GM]\S+)/){
+ $working = $1;
+ $unit = $2;
+ my $result = process_speed($unit,$working,$device_type,$check);
+ ($configured_speed,$configured_note) = @$result;
+ }
+ else {
+ $speed = $temp[1];
+ }
+ }
+ elsif ($temp[0] eq 'Firmware Version'){
+ $temp[1] = main::clean_dmi($temp[1]);
+ $firmware = $temp[1];
}
elsif ($temp[0] eq 'Manufacturer'){
$temp[1] = main::clean_dmi($temp[1]);
@@ -21868,24 +24186,18 @@ sub dmidecode_data {
}
}
}
- # because of the wide range of bank/slot type data, we will just use
- # the one that seems most likely to be right. Some have: Bank: SO DIMM 0 slot: J6A
- # so we dump the useless data and use the one most likely to be visibly correct
- if ($bank_locator =~ /DIMM/){
- $main_locator = $bank_locator;
- }
- else {
- $main_locator = $locator;
- }
+ # locator data is not great or super reliable, so do our best
+ $main_locator = process_locator($locator,$bank_locator);
if ($working_size =~ /^[0-9][0-9]+$/){
$ram->[$handle]{'device-count-found'}++;
# build up actual capacity found for override tests
$ram->[$handle]{'used-capacity'} += $working_size;
}
- # sometimes the data is just wrong, they reverse total/data. data I believe is
- # used for the actual memory bus width, total is some synthetic thing, sometimes missing.
- # note that we do not want a regular string comparison, because 128 bit memory buses are
- # in our future, and 128 bits < 64 bits with string compare
+ # Sometimes the data is just wrong, they reverse total/data. data I
+ # believe is used for the actual memory bus width, total is some synthetic
+ # thing, sometimes missing. Note that we do not want a regular string
+ # comparison, because 128 bit memory buses are in our future, and
+ # 128 bits < 64 bits with string compare.
$data_width =~ /(^[0-9]+).*/;
$i_data = $1;
$total_width =~ /(^[0-9]+).*/;
@@ -21895,27 +24207,20 @@ sub dmidecode_data {
$data_width = $total_width;
$total_width = $temp_width;
}
- if ($manufacturer && $manufacturer =~ /^([a-f0-9]{4})$/i){
- $vendor_id = lc($1) if $1;
- }
- if ((!$manufacturer || $vendor_id) && $part_number){
- my $result = ram_vendor($part_number);
- $manufacturer = $result->[0] if $result->[0];
- $part_number = $result->[1] if $result->[1];
- }
- if ($vendor_id && !$manufacturer){
- set_ram_vendor_ids() if !$vendor_ids;
- if ($vendor_ids->{$vendor_id}){
- $manufacturer = $vendor_ids->{$vendor_id};
- }
+ ($manufacturer,$vendor_id,$part_number) = process_manufacturer(
+ $manufacturer,$part_number);
+ if (!$ram->[$handle]{'device-type'} && $device_type){
+ $ram->[$handle]{'device-type'} = $device_type;
}
$ram->[$handle]{'derived-module-size'} = $derived_module_size;
+ $ram->[$handle]{'slots-active'} = $slots_active[$handle];
$ram->[$handle]{'modules'}[$i]{'configured-clock-speed'} = $configured_speed;
$ram->[$handle]{'modules'}[$i]{'configured-note'} = $configured_note if $configured_note;
$ram->[$handle]{'modules'}[$i]{'data-width'} = $data_width;
$ram->[$handle]{'modules'}[$i]{'size'} = $device_size;
$ram->[$handle]{'modules'}[$i]{'device-type'} = $device_type;
$ram->[$handle]{'modules'}[$i]{'device-type-detail'} = lc($device_type_detail);
+ $ram->[$handle]{'modules'}[$i]{'firmware'} = $firmware;
$ram->[$handle]{'modules'}[$i]{'form-factor'} = $form_factor;
$ram->[$handle]{'modules'}[$i]{'locator'} = $main_locator;
$ram->[$handle]{'modules'}[$i]{'manufacturer'} = $manufacturer;
@@ -21937,98 +24242,316 @@ sub dmidecode_data {
last;
}
}
- print Data::Dumper::Dumper $ram if $dbg[36];
- main::log_data('dump','@$ram',$ram) if $b_log;
+ print 'dmidecode pre process_data: ', Data::Dumper::Dumper $ram if $dbg[36];
+ main::log_data('dump','pre @$ram',$ram) if $b_log;
process_data($ram) if @$ram;
- main::log_data('dump','@$ram',$ram) if $b_log;
- print Data::Dumper::Dumper $ram if $dbg[36];
+ main::log_data('dump','post @$ram',$ram) if $b_log;
+ print 'dmidecode post process_data: ', Data::Dumper::Dumper $ram if $dbg[36];
eval $end if $b_log;
- return $ram;
}
-sub dboot_data {
+
+# this contains a subset of dmi RAM data generated I believe at boot
+# args: 0: $ram ref;
+sub udevadm_data {
eval $start if $b_log;
- my $ram = [];
- my $est = main::message('note-est');
- my ($arr,$derived_module_size,$subtract) = (0,0,0);
- my ($holder);
- foreach (@{$dboot{'ram'}}){
- my ($addr,$detail,$device_detail,$ecc,$iic,$locator,$size,$speed,$type);
- # note: seen one netbsd with multiline spdmem0/1 etc but not consistent so don't use
- if (/^(spdmem([\d]+)):at iic([\d]+)(\saddr 0x([0-9a-f]+))?/){
- $iic = $3;
- $locator = $1;
- $holder = $iic if !defined $holder; # prime for first use
- # note: seen iic2 as only device
- if ($iic != $holder){
- if ($ram->[$arr] && $ram->[$arr]{'slots-16'}){
- $subtract += $ram->[$arr]{'slots-16'};
+ my $ram = $_[0];
+ my ($b_arr_nu,$b_arr_set,$d_holder,@data,$key,@temp);
+ my ($a,$i) = (0,0);
+ my %array_ids;
+ if ($fake{'udevadm'}){
+ my $file;
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-1-array-2-slot-1.txt";
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-1-array-2-slot-2-barebones.txt";
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-1-array-2-slot-3-errors.txt";
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-1-array-4-slot-1.txt";
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-1-array-4-slot-2-volts.txt";
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-1-array-16-slot-1.txt";
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-1-array-16-slot-2.txt";
+ $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-2-array-24-slot-1.txt";
+ # $file = "$fake_data_dir/ram/udevadm/udevadm-dmi-4-array-12-slot-1.txt";
+ @data = main::reader($file,'strip');
+ }
+ else {
+ my $cmd = $alerts{'udevadm'}->{'path'} . ' info -p /devices/virtual/dmi/id 2>/dev/null';
+ @data = main::grabber($cmd,'','strip');
+ }
+ if (@data){
+ @data = map {s/^\S: //;$_ if /^MEMORY/;} @data;
+ # unknown if > 1 array output possible, do not sort in case they just stack it
+ @data = grep {/^ME/} @data;
+ }
+ main::log_data('dump','@data',\@data) if $b_log;
+ print Data::Dumper::Dumper \@data if $dbg[36];
+ foreach my $line (@data){
+ @temp = split(/=/,$line,2);
+ # there should be array numbering at least, but there isn't, not yet anyway
+ if ($temp[0] =~ /^MEMORY_ARRAY_((\d+)_)?(\S+)/){
+ $key = $3;
+ if ($2){
+ $b_arr_nu = 1;
+ $a = $2;
+ }
+ # this _should_ be first item, hoping > 1 arrays is stacked in order
+ if ($key eq 'LOCATION'){
+ $temp[1] =~ s/\sOr\sMotherboard//;
+ $temp[1] ||= 'System Board';
+ $a++ if !$b_arr_nu && $b_arr_set;
+ $ram->[$a]{'location'} = $temp[1];
+ $b_arr_set = 1;
+ }
+ elsif ($key eq 'EC_TYPE'){
+ if ($temp[1] && lc($temp[1]) ne 'none'){
+ $temp[1] = main::clean_dmi($temp[1]); # seen <OUT OF SPEC>
+ }
+ $temp[1] ||= 'None';
+ if (!$ram->[$a]{'eec'} && $temp[1]){
+ $ram->[$a]{'eec'} = $temp[1];
+ }
+ }
+ elsif ($key eq 'MAX_CAPACITY'){
+ # in bytes
+ $temp[1] = $temp[1]/1024 if $temp[1] =~ /^\d+$/;
+ $ram->[$a]{'max-capacity-16'} = $temp[1];
+ }
+ elsif ($key eq 'NUM_DEVICES'){
+ $ram->[$a]{'slots-16'} = $temp[1];
+ }
+ elsif ($key eq 'USE'){
+ $temp[1] ||= 'System Memory';
+ $ram->[$a]{'use'} = $temp[1];
+ }
+ }
+ elsif ($temp[0] =~ /^MEMORY_DEVICE_(\d+)_(\S+)$/){
+ $key = $2;
+ if (!defined $d_holder){
+ $d_holder = $1;
+ }
+ if ($d_holder ne $1){
+ $i++;
+ $d_holder = $1;
+ }
+ if ($key eq 'ASSET_TAG'){
+ $temp[1] = main::clean_dmi($temp[1]);
+ $ram->[$a]{'modules'}[$i]{'asset-tag'} = $temp[1] if $temp[1] ;
+ }
+ # only way to detect > 1 array systems is NODE[x] string.
+ elsif ($key eq 'BANK_LOCATOR'){
+ $ram->[$a]{'modules'}[$i]{'bank-locator'} = $temp[1];
+ # this is VERY unreliable, but better than nothing. Update if needed and
+ # new data sources available.
+ if ($temp[1] =~ /Node[\s_-]?(\d+)/i){
+ $ram->[$a]{'modules'}[$i]{'array-id'} = $1;
+ $array_ids{$1} = 1 if !defined $array_ids{$1};
}
- $holder = $iic;
- # then since we are on a new iic device, assume new ram array.
- # this needs more data to confirm this guess.
- $arr++;
}
- if ($5){
- $addr = hex($5);
+ elsif ($key eq 'CONFIGURED_SPEED_GTS'){
+ $ram->[$a]{'modules'}[$i]{'configured-clock-speed'} = $temp[1];
+ $ram->[$a]{'modules'}[$i]{'speed-unit'} = 'GT/s';
}
- if (/(non?[\s-]parity)/i){
- $device_detail = $1;
- $ecc = 'None';
+ elsif ($key eq 'CONFIGURED_SPEED_MTS'){
+ $ram->[$a]{'modules'}[$i]{'configured-clock-speed'} = $temp[1];
+ $ram->[$a]{'modules'}[$i]{'speed-unit'} = 'MT/s';
}
- elsif (/EEC/i){
- $device_detail = 'EEC';
- $ecc = 'EEC';
+ elsif ($key eq 'CONFIGURED_VOLTAGE'){
+ if ($temp[1] =~ /^([\d\.]+)/){
+ $ram->[$a]{'modules'}[$i]{'voltage-config'} = $1;
+ }
}
- if (/\b(PC[0-9]+-\S+)\b/){
- $speed = $1;
- my $temp = speed_mapper($speed);
- if ($temp ne $speed){
- $detail = $speed;
- $speed = $temp;
+ elsif ($key eq 'DATA_WIDTH'){
+ $temp[1] = main::clean_dmi($temp[1]);
+ if ($temp[1]){
+ $temp[1] =~ s/[\s_-]?bits//;
+ $temp[1] =~ /(^[0-9]+).*/;
+ $ram->[$a]{'modules'}[$i]{'data-width'} = $1;
}
}
- # we want to avoid netbsd trying to complete @ram without real data
- if (/:(\d+[MGT])B?\s(DDR[0-9]*)\b/){
- $size = main::translate_size($1)/1024;
- $type = $2;
- if ($addr){
- $ram->[$arr]{'slots-16'} = $addr - 80 + 1 - $subtract;
- $locator = 'Slot-' . $ram->[$arr]{'slots-16'};
+ elsif ($key eq 'FIRMWARE_VERSION'){
+ $ram->[$a]{'modules'}[$i]{'firmware'} = main::clean_dmi($temp[1]);
+ }
+ elsif ($key eq 'FORM_FACTOR'){
+ $ram->[$a]{'modules'}[$i]{'form-factor'} = main::clean_dmi($temp[1]);
+ }
+ elsif ($key eq 'LOCATOR'){
+ $ram->[$a]{'modules'}[$i]{'locator'} = $temp[1];
+ }
+ elsif ($key eq 'MANUFACTURER'){
+ $temp[1] = main::clean_dmi($temp[1]);
+ $ram->[$a]{'modules'}[$i]{'manufacturer'} = $temp[1];
+ }
+ elsif ($key eq 'MAXIMUM_VOLTAGE'){
+ if ($temp[1] =~ /^([\d\.]+)/){
+ $ram->[$a]{'modules'}[$i]{'voltage-max'} = $1;
}
- $ram->[$arr]{'device-count-found'}++;
- # build up actual capacity found for override tests
- $ram->[$arr]{'max-capacity-16'} += $size;
- $ram->[$arr]{'max-cap-qualifier'} = $est;
- $ram->[$arr]{'slots-16'}++ if !$addr;
- $derived_module_size = $size if $size > $derived_module_size;
- $ram->[$arr]{'slots-qualifier'} = $est;
- $ram->[$arr]{'eec'} = $ecc;
- $ram->[$arr]{'derived-module-size'} = $derived_module_size;
- push(@{$ram->[$arr]{'modules'}},{
- 'device-type' => $type,
- 'device-type-detail' => $detail,
- 'locator' => $locator,
- 'size' => $size,
- 'speed' => $speed,
- });
+ }
+ elsif ($key eq 'MINIMUM_VOLTAGE'){
+ if ($temp[1] =~ /^([\d\.]+)/){
+ $ram->[$a]{'modules'}[$i]{'voltage-min'} = $1;
+ }
+ }
+ elsif ($key eq 'PART_NUMBER'){
+ $ram->[$a]{'modules'}[$i]{'part-number'} = main::clean_unset($temp[1],'^[0]+$|.*Module.*|PartNum.*');
+ }
+ elsif ($key eq 'PRESENT'){
+ $ram->[$a]{'modules'}[$i]{'present'} = $temp[1]; # 0/1
+ }
+ elsif ($key eq 'RANK'){
+ $ram->[$a]{'modules'}[$i]{'rank'} = $temp[1];
+ }
+ elsif ($key eq 'SERIAL_NUMBER'){
+ $ram->[$a]{'modules'}[$i]{'serial'} = main::clean_unset($temp[1],'^[0]+$|SerNum.*');
+ }
+ # only seems to appear if occupied, handle no value in process
+ elsif ($key eq 'SIZE'){
+ if ($temp[1] =~ /^\d+$/){
+ $temp[1] = $temp[1]/1024;
+ $ram->[$a]{'modules'}[$i]{'size'} = $temp[1];
+ }
+ }
+ # maybe with DDR6 or 7?
+ elsif ($key eq 'SPEED_GTS'){
+ $ram->[$a]{'modules'}[$i]{'speed'} = $temp[1];
+ $ram->[$a]{'modules'}[$i]{'speed-unit'} = 'GT/s';
+ }
+ elsif ($key eq 'SPEED_MTS'){
+ $ram->[$a]{'modules'}[$i]{'speed'} = $temp[1];
+ $ram->[$a]{'modules'}[$i]{'speed-unit'} = 'MT/s';
+ }
+ elsif ($key eq 'TOTAL_WIDTH'){
+ $temp[1] = main::clean_dmi($temp[1]);
+ if ($temp[1]){
+ $temp[1] =~ s/[\s_-]?bits//;
+ $temp[1] =~ /(^[0-9]+).*/;
+ $ram->[$a]{'modules'}[$i]{'total-width'} = $1;
+ }
+ }
+ elsif ($key eq 'TYPE'){
+ $ram->[$a]{'modules'}[$i]{'device-type'} = main::clean_dmi($temp[1]);
+ if (!$ram->[$a]{'device-type'} && $ram->[$a]{'modules'}[$i]{'device-type'}){
+ $ram->[$a]{'device-type'} = $ram->[$a]{'modules'}[$i]{'device-type'};
+ }
+ }
+ elsif ($key eq 'TYPE_DETAIL'){
+ $ram->[$a]{'modules'}[$i]{'device-type-detail'} = lc(main::clean_dmi($temp[1]));
}
}
}
- for (my $i = 0; $i++ ;scalar @$ram){
- next if ref $ram->[$i] ne 'HASH';
- # 1 slot is possible, but 3 is very unlikely due to dual channel ddr
- if ($ram->[$i]{'slots'} && $ram->[$i]{'slots'} > 2 && $ram->[$i]{'slots'} % 2 == 1){
- $ram->[$i]{'slots'}++;
- }
+ print 'udevadm pre process_data: ', Data::Dumper::Dumper $ram if $dbg[36];
+ main::log_data('dump','pre @$ram',$ram) if $b_log;
+ # bad quality output, for > 1 arrays, shows 1 array, > 1 nodes.
+ if (scalar @$ram == 1 && %array_ids && scalar keys %array_ids > 1){
+ udevadm_create_arrays($ram);
+ }
+ if (@$ram){
+ udevadm_data_process($ram);
}
- print Data::Dumper::Dumper $ram if $dbg[36];
- main::log_data('dump','@$ram',$ram) if $b_log;
process_data($ram) if @$ram;
- main::log_data('dump','@$ram',$ram) if $b_log;
- print Data::Dumper::Dumper $ram if $dbg[36];
+ main::log_data('dump','post @$ram',$ram) if $b_log;
+ print 'udevadm post process_data: ', Data::Dumper::Dumper $ram if $dbg[36];
eval $end if $b_log;
- return $ram;
}
+
+# args: 0: $ram ref;
+sub udevadm_create_arrays {
+ eval $start if $b_log;
+ my $ram = $_[0];
+ my ($id,%working);
+ # rebuild the single array into set of arrays
+ my $arr = shift @$ram;
+ foreach my $module (@{$arr->{'modules'}}){
+ $id = $module->{'array-id'};
+ push(@{$working{$id}->{'modules'}},$module);
+ }
+ # print Data::Dumper::Dumper \%working;
+ my $i = 0;
+ foreach my $key (sort {$a <=> $b} keys %working){
+ $ram->[$i]{'modules'} = $working{$key}->{'modules'};
+ foreach my $key2 (%$arr){
+ next if $key2 eq 'modules' || $key2 eq 'slots-16';
+ $ram->[$i]{$key2} = $arr->{$key2};
+ }
+ $ram->[$i]{'slots-16'} = scalar @{$working{$key}->{'modules'}};
+ $i++;
+ }
+ # print Data::Dumper::Dumper $ram;
+ eval $end if $b_log;
+}
+
+# See comments on dmidecode_data modules for logic used here
+# args: 0: $ram ref;
+sub udevadm_data_process {
+ eval $start if $b_log;
+ my $ram = $_[0];
+ my ($derived_module_size) = (0);
+ my $check = main::message('note-check');
+ # print 'post udev create: ', Data::Dumper::Dumper $ram;
+ for (my $a=0; $a < scalar @$ram; $a++){
+ # set the working data
+ $ram->[$a]{'derived-module-size'} = 0;
+ $ram->[$a]{'device-count-found'} = 0;
+ $ram->[$a]{'used-capacity'} = 0;
+ $ram->[$a]{'eec'} ||= 'None';
+ $ram->[$a]{'use'} ||= 'System Memory';
+ for (my $i=0; $i < scalar @{$ram->[$a]{'modules'}}; $i++){
+ if ($ram->[$a]{'modules'}[$i]{'size'}){
+ $derived_module_size = calculate_size($ram->[$a]{'modules'}[$i]{'size'}.'KiB',$derived_module_size);
+ $ram->[$a]{'device-count-found'}++;
+ $ram->[$a]{'slots-active'}++;
+ $ram->[$a]{'used-capacity'} += $ram->[$a]{'modules'}[$i]{'size'};
+ }
+ elsif (!$ram->[$a]{'modules'}[$i]{'size'}){
+ $ram->[$a]{'modules'}[$i]{'size'} = main::message('ram-no-module');
+ }
+ # sometimes all upper case, no idea why
+ if ($ram->[$a]{'modules'}[$i]{'manufacturer'} ||
+ $ram->[$a]{'modules'}[$i]{'part-number'}){
+ ($ram->[$a]{'modules'}[$i]{'manufacturer'},
+ $ram->[$a]{'modules'}[$i]{'vendor-id'},
+ $ram->[$a]{'modules'}[$i]{'part-number'}) = process_manufacturer(
+ $ram->[$a]{'modules'}[$i]{'manufacturer'},
+ $ram->[$a]{'modules'}[$i]{'part-number'});
+ }
+ # these are sometimes reversed
+ if ($ram->[$a]{'modules'}[$i]{'data-width'} &&
+ $ram->[$a]{'modules'}[$i]{'total-width'} &&
+ $ram->[$a]{'modules'}[$i]{'data-width'} > $ram->[$a]{'modules'}[$i]{'total-width'}){
+ my $temp = $ram->[$a]{'modules'}[$i]{'data-width'};
+ $ram->[$a]{'modules'}[$i]{'data-width'} = $ram->[$a]{'modules'}[$i]{'total-width'};
+ $ram->[$a]{'modules'}[$i]{'total-width'} = $temp;
+ }
+ if ($ram->[$a]{'modules'}[$i]{'speed'}){
+ my $result = process_speed($ram->[$a]{'modules'}[$i]{'speed-unit'},
+ $ram->[$a]{'modules'}[$i]{'speed'},
+ $ram->[$a]{'modules'}[$i]{'device-type'},$check);
+ $ram->[$a]{'modules'}[$i]{'speed'} = $result->[0];
+ $ram->[$a]{'modules'}[$i]{'speed-note'} = $result->[1];
+ }
+ if ($ram->[$a]{'modules'}[$i]{'configured-clock-speed'}){
+ my $result = process_speed($ram->[$a]{'modules'}[$i]{'speed-unit'},
+ $ram->[$a]{'modules'}[$i]{'configured-clock-speed'},
+ $ram->[$a]{'modules'}[$i]{'device-type'},$check);
+ $ram->[$a]{'modules'}[$i]{'configured-clock-speed'} = $result->[0];
+ $ram->[$a]{'modules'}[$i]{'configured-note'} = $result->[1];
+ }
+ # odd case were all value 1, which is almost certainly wrong
+ if ($ram->[$a]{'modules'}[$i]{'voltage-min'} &&
+ $ram->[$a]{'modules'}[$i]{'voltage-max'} &&
+ $ram->[$a]{'modules'}[$i]{'voltage-config'} &&
+ $ram->[$a]{'modules'}[$i]{'voltage-min'} eq '1' &&
+ $ram->[$a]{'modules'}[$i]{'voltage-max'} eq '1' &&
+ $ram->[$a]{'modules'}[$i]{'voltage-config'} eq '1'){
+ $ram->[$a]{'modules'}[$i]{'voltage-note'} = $check;
+ }
+ if ($ram->[$a]{'modules'}[$i]{'locator'} &&
+ $ram->[$a]{'modules'}[$i]{'bank-locator'}){
+ $ram->[$a]{'modules'}[$i]{'locator'} = process_locator(
+ $ram->[$a]{'modules'}[$i]{'locator'},$ram->[$a]{'modules'}[$i]{'bank-locator'});
+ }
+ }
+ $ram->[$a]{'derived-module-size'} = $derived_module_size if $derived_module_size;
+ }
+ eval $end if $b_log;
+}
+
sub process_data {
eval $start if $b_log;
my $ram = $_[0];
@@ -22037,46 +24560,52 @@ sub process_data {
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
+ # Because we use the actual array handle as the index, there will be many
+ # undefined keys.
next if ! defined $item;
my ($max_cap,$max_mod_size) = (0,0);
my ($alt_cap,$est_cap,$est_mod,$est_slots,$unit) = (0,'','','','');
$max_cap = $item->{'max-capacity-16'};
$max_cap ||= 0;
- # make sure they are integers not string if empty
+ # Make sure they are integers not string if empty.
$item->{'slots-5'} ||= 0;
$item->{'slots-16'} ||= 0;
+ $item->{'slots-active'} ||= 0;
$item->{'device-count-found'} ||= 0;
$item->{'max-capacity-5'} ||= 0;
$item->{'max-module-size'} ||= 0;
$item->{'used-capacity'} ||= 0;
- #$item->{'max-module-size'} = 0;# debugger
- # 1: if max cap 1 is null, and max cap 2 not null, use 2
+ # $item->{'max-module-size'} = 0;# debugger
+ # 1: If max cap 1 is null, and max cap 2 not null, use 2
if ($b_debug){
- print "1: mms: $item->{'max-module-size'} :dms: $item->{'derived-module-size'} :mc: $max_cap :uc: $item->{'used-capacity'}\n";
+ print "1: mms: $item->{'max-module-size'} :dms: $item->{'derived-module-size'} ";
+ print ":mc: $max_cap :uc: $item->{'used-capacity'}\n";
print "1a: s5: $item->{'slots-5'} s16: $item->{'slots-16'}\n";
}
if (!$max_cap && $item->{'max-capacity-5'}){
$max_cap = $item->{'max-capacity-5'};
}
if ($b_debug){
- print "2: mms: $item->{'max-module-size'} :dms: $item->{'derived-module-size'} :mc: $max_cap :uc: $item->{'used-capacity'}\n";
+ print "2: mms: $item->{'max-module-size'} :dms: $item->{'derived-module-size'} ";
+ print ":mc: $max_cap :uc: $item->{'used-capacity'}\n";
}
- # 2: now check to see if actually found module sizes are > than listed max module, replace if >
+ # 2: Now check to see if actually found module sizes are > than listed
+ # max module, replace if >
if ($item->{'max-module-size'} && $item->{'derived-module-size'} &&
$item->{'derived-module-size'} > $item->{'max-module-size'}){
$item->{'max-module-size'} = $item->{'derived-module-size'};
$est_mod = $est;
}
if ($b_debug){
- print "3: dcf: $item->{'device-count-found'} :dms: $item->{'derived-module-size'} :mc: $max_cap :uc: $item->{'used-capacity'}\n";
+ print "3: dcf: $item->{'device-count-found'} :dms: $item->{'derived-module-size'} ";
+ print ":mc: $max_cap :uc: $item->{'used-capacity'}\n";
}
- # note: some cases memory capacity == max module size, so one stick will fill it
- # but I think only with cases of 2 slots does this happen, so if > 2, use the count of slots.
+ # Note: some cases memory capacity == max module size, so one stick will
+ # fill it but I think only with cases of 2 slots does this happen, so
+ # if > 2, use the count of slots.
if ($max_cap && ($item->{'device-count-found'} || $item->{'slots-16'})){
- # first check that actual memory found is not greater than listed max cap, or
- # checking to see module count * max mod size is not > used capacity
+ # First check that actual memory found is not greater than listed max cap,
+ # or checking to see module count * max mod size is not > used capacity
if ($item->{'used-capacity'} && $item->{'max-capacity-16'}){
if ($item->{'used-capacity'} > $max_cap){
if ($item->{'max-module-size'} &&
@@ -22098,23 +24627,26 @@ sub process_data {
}
}
}
- # note that second case will never really activate except on virtual machines and maybe
- # mobile devices
+ # Note that second case will never really activate except on virtual
+ # machines and maybe mobile devices.
if (!$est_cap){
- # do not do this for only single modules found, max mod size can be equal to the array size
+ # Do not do this for only single modules found, max mod size can be
+ # equal to the array size.
if ($item->{'slots-16'} > 1 && $item->{'device-count-found'} > 1 &&
$max_cap < ($item->{'derived-module-size'} * $item->{'slots-16'})){
$max_cap = $item->{'derived-module-size'} * $item->{'slots-16'};
$est_cap = $est;
print "D\n" if $b_debug;
}
- elsif ($item->{'device-count-found'} > 0 && $max_cap < ($item->{'derived-module-size'} * $item->{'device-count-found'})){
+ elsif ($item->{'device-count-found'} > 0 &&
+ $max_cap < ($item->{'derived-module-size'} * $item->{'device-count-found'})){
$max_cap = $item->{'derived-module-size'} * $item->{'device-count-found'};
$est_cap = $est;
print "E\n" if $b_debug;
}
- ## handle cases where we have type 5 data: mms x device count equals type 5 max cap
- # however do not use it if cap / devices equals the derived module size
+ # Handle cases where we have type 5 data: mms x device count equals
+ # type 5 max caphowever do not use it if cap / devices equals the
+ # derived module size.
elsif ($item->{'max-module-size'} > 0 &&
($item->{'max-module-size'} * $item->{'slots-16'}) == $item->{'max-capacity-5'} &&
$item->{'max-capacity-5'} != $item->{'max-capacity-16'} &&
@@ -22126,20 +24658,23 @@ sub process_data {
}
if ($b_debug){
- print "4: mms: $item->{'max-module-size'} :dms: $item->{'derived-module-size'} :mc: $max_cap :uc: $item->{'used-capacity'}\n";
+ print "4: mms: $item->{'max-module-size'} :dms: $item->{'derived-module-size'} ";
+ print ":mc: $max_cap :uc: $item->{'used-capacity'}\n";
}
- # some cases of type 5 have too big module max size, just dump the data then since
- # we cannot know if it is valid or not, and a guess can be wrong easily
+ # Some cases of type 5 have too big module max size, just dump the data
+ # then since we cannot know if it is valid or not, and a guess can be
+ # wrong easily.
if ($item->{'max-module-size'} && $max_cap && $item->{'max-module-size'} > $max_cap){
$item->{'max-module-size'} = 0;
}
if ($b_debug){
print "5: dms: $item->{'derived-module-size'} :s16: $item->{'slots-16'} :mc: $max_cap\n";
}
- # now prep for rebuilding the ram array data
+ # Now prep for rebuilding the ram array data.
if (!$item->{'max-module-size'}){
# ie: 2x4gB
- if (!$est_cap && $item->{'derived-module-size'} > 0 && $max_cap > ($item->{'derived-module-size'} * $item->{'slots-16'} * 4)){
+ if (!$est_cap && $item->{'derived-module-size'} > 0 &&
+ $max_cap > ($item->{'derived-module-size'} * $item->{'slots-16'} * 4)){
$est_cap = $check;
print "G\n" if $b_debug;
}
@@ -22163,7 +24698,7 @@ sub process_data {
$est_mod = $est;
}
}
- # case where listed max cap is too big for actual slots x max cap, eg:
+ # Case where listed max cap is too big for actual slots x max cap, eg:
# listed max cap, 8gb, max mod 2gb, slots 2
else {
if (!$est_cap && $item->{'max-module-size'} > 0){
@@ -22174,7 +24709,7 @@ sub process_data {
}
}
}
- # no slots found due to legacy dmi probably. Note, too many logic errors
+ # No slots found due to legacy dmi probably. Note, too many logic errors
# happen if we just set a general slots above, so safest to do it here
$item->{'slots-16'} = $item->{'slots-5'} if $item->{'slots-5'} && !$item->{'slots-16'};
if (!$item->{'slots-16'} && $item->{'modules'} && ref $item->{'modules'} eq 'ARRAY'){
@@ -22182,22 +24717,26 @@ sub process_data {
$item->{'slots-16'} = scalar @{$item->{'modules'}};
print "L\n" if $b_debug;
}
- # only bsds using dmesg data
+ # Only bsds using dmesg data
elsif ($item->{'slots-qualifier'}){
$est_slots = $item->{'slots-qualifier'};
$est_cap = $est;
}
+ $ram_total += $item->{'used-capacity'};
push(@result, {
'capacity' => $max_cap,
'cap-qualifier' => $est_cap,
+ 'device-type' => $item->{'device-type'},
'eec' => $item->{'eec'},
'location' => $item->{'location'},
'max-module-size' => $item->{'max-module-size'},
'mod-qualifier' => $est_mod,
'modules' => $item->{'modules'},
'slots' => $item->{'slots-16'},
+ 'slots-active' => $item->{'slots-active'},
'slots-qualifier' => $est_slots,
'use' => $item->{'use'},
+ 'used-capacity' => $item->{'used-capacity'},
'voltage-config' => $item->{'voltage-config'},
'voltage-max' => $item->{'voltage-max'},
'voltage-min' => $item->{'voltage-min'},
@@ -22206,67 +24745,142 @@ sub process_data {
@$ram = @result;
eval $end if $b_log;
}
-sub process_speed {
- my ($speed,$device_type,$check) = @_;
- my $speed_note;
- $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)";
+
+## RAM UTILITIES ##
+
+# arg: 0: size string; 1: working size. If calculated result > $size, uses new
+# value. If $data not valid, returns 0.
+sub calculate_size {
+ eval $start if $b_log;
+ my ($data, $size) = @_;
+ # Technically k is KiB, K is KB but can't trust that.
+ if ($data =~ /^([0-9]+\s*[kKGMTP])i?B/){
+ my $working = $1;
+ # This converts it to KiB
+ my $working_size = main::translate_size($working);
+ # print "ws-a: $working_size s-1: $size\n";
+ if (main::is_numeric($working_size) && $working_size > $size){
+ $size = $working_size;
+ }
+ # print "ws-b: $working_size s-2: $size\n";
}
- # seen cases of 1 MT/s, 61690 MT/s, not sure why, bug
- # crucial is shipping 5100 MT/s now, and 6666 has been hit, so speeds can hit 10k
- if ($speed && $speed =~ /^([0-9]+)\s*M/){
- $speed_note = $check if $1 < 50 || $1 > 20000 ;
+ else {
+ $size = 0;
}
- return [$speed,$speed_note];
+ # print "d-2: $data s-3: $size\n";
+ eval $end if $b_log;
+ return $size;
+}
+
+# Because of the wide range of bank/slot type data, we will just use the
+# one that seems most likely to be right. Some have:
+# 'Bank: SO DIMM 0 slot: J6A' so we dump the useless data and use the one
+# most likely to be visibly correct.
+# Some systems show only DIMM 1 etc for locator with > 1 channels.
+# args: 0: locator; 1: bank-locator
+sub process_locator {
+ eval $start if $b_log;
+ my ($locator,$bank_locator) = @_;
+ my $main_locator;
+ if ($bank_locator && $bank_locator =~ /DIMM/){
+ $main_locator = $bank_locator;
+ }
+ else {
+ # some systems show only DIMM 1 etc for locator with > 1 channels.
+ if ($locator && $locator =~ /^DIMM[\s_-]?\d+$/ &&
+ $bank_locator && $bank_locator =~ /Channel[\s_-]?([A-Z]+)/i){
+ $main_locator = "Channel-$1 $locator";
+ }
+ else {
+ $main_locator = $locator;
+ }
+ }
+ eval $end if $b_log;
+ return $main_locator;
}
-# this should be fixed, but for now, size in RAM is in MiB, not
-# KiB like the rest of inxi.
+
+# args: 0: manufacturer; 1: part number
+sub process_manufacturer {
+ eval $start if $b_log;
+ my ($manufacturer,$part_number) = @_;
+ my $vendor_id;
+ if ($manufacturer){
+ if ($manufacturer =~ /^([a-f0-9]{4})$/i){
+ $vendor_id = lc($1);
+ $manufacturer = '';
+ }
+ elsif ($manufacturer =~ /^[A-Z]+$/){
+ $manufacturer = ucfirst(lc($manufacturer));
+ }
+ }
+ if (!$manufacturer){
+ if ($part_number){
+ my $result = ram_vendor($part_number);
+ $manufacturer = $result->[0] if $result->[0];
+ $part_number = $result->[1] if $result->[1];
+ }
+ if (!$manufacturer && $vendor_id){
+ set_ram_vendor_ids() if !$vendor_ids;
+ if ($vendor_ids->{$vendor_id}){
+ $manufacturer = $vendor_ids->{$vendor_id};
+ }
+ else {
+ $manufacturer = $vendor_id;
+ }
+ }
+ }
+ eval $end if $b_log;
+ return ($manufacturer,$vendor_id,$part_number);
+}
+
+# args: 0: size in KiB
sub process_size {
+ eval $start if $b_log;
my ($size) = @_;
my ($b_trim,$unit) = (0,'');
# print "size0: $size\n";
return 'N/A' if !$size;
- #return $size if $size =~ /\D/;
+ # we're going to preserve the bad data for output
return $size if !main::is_numeric($size);
# print "size: $size\n";
- # we only want a max 2 decimal places, and only when it's
- # a unit > 1 GiB
- $b_trim = 1 if $size > 1024;
- # switch it back to KiB for tool
- ($size,$unit) = main::get_size($size * 1024);
+ # We only want max 2 decimal places, and only when it's a unit > 1 GiB.
+ $b_trim = 1 if $size > 1024**2;
+ ($size,$unit) = main::get_size($size);
$size = sprintf("%.2f",$size) if $b_trim;
$size =~ s/\.[0]+$//;
$size = "$size $unit";
+ eval $end if $b_log;
return $size;
}
-# note that even though MB should be 1000^x it's actually
-# MiB etc. As with process_size, this uses MiB not KiB
-sub calculate_size {
- my ($data, $size) = @_;
- # technically k is KiB, K is KB but can't trust that
- if ($data =~ /^([0-9]+\s*[kKGMTP])i?B/){
- my $working = $1;
- # this converts it to KiB
- my $working_size = main::translate_size($working);
- # but we want it back in MiB for RAM, that should get fixed
- $working_size = $working_size/1024 if $working_size;
- # print "ws-a: $working_size s-1: $size\n";
- if (main::is_numeric($working_size) && $working_size > $size){
- $size = $working_size;
- }
- # print "ws-b: $working_size s-2: $size\n";
+
+# args: 0: speed unit; 1: speed (numeric); 2: device tyep; 3: check string
+sub process_speed {
+ eval $start if $b_log;
+ my ($unit,$speed,$device_type,$check) = @_;
+ my ($speed_note,$speed_orig);
+ if ($unit eq 'MHz' && $device_type && $device_type =~ /ddr/i && $speed){
+ $speed_orig = " ($speed $unit)";
+ $speed = ($speed * 2);
+ $unit = 'MT/s';
}
- else {
- $size = 0;
+ # Seen cases of 1 MT/s, 61690 MT/s, not sure why, bug. Crucial is shipping
+ # 5100 MT/s now, and 6666 has been hit, so speeds can hit 10k. DDR6 hits
+ # 12.8k-17k, DDR7?. If GT/s assume valid and working
+ if ($speed && $unit && $unit eq 'MT/s'){
+ if ($speed < 50 || $speed > 30000){
+ $speed_note = $check;
+ }
}
- # print "d-2: $data s-3: $size\n";
- return $size;
+ $speed .= " $unit";
+ $speed .= $speed_orig if $speed_orig;
+ eval $end if $b_log;
+ return [$speed,$speed_note];
}
-sub speed_mapper {
- my ($type) = @_;
- my %speeds = (
- # DDR
+
+# BSD: Map string to speed, in MT/s
+sub set_speed_maps {
+ $speed_maps = {
+ # DDR1
'PC-1600' => 200,
'PC-2100' => 266,
'PC-2400' => 300,
@@ -22278,33 +24892,61 @@ sub speed_mapper {
'PC2-5300' => 667,
'PC2-6400' => 800,
'PC2-8000' => 1000,
+ 'PC2-8500' => 1066,
# DDR3
'PC3-6400' => 800,
'PC3-8500' => 1066,
'PC3-10600' => 1333,
'PC3-12800' => 1600,
+ 'PC3-14900 ' => 1866,
+ 'PC3-17000' => 2133,
# DDR4
+ 'PC4-12800' => 1600,
+ 'PC4-14900' => 1866,
+ 'PC4-17000' => 2133,
'PC4-19200' => 2400,
'PC4-21300' => 2666,
+ 'PC4-21333' => 2666,
'PC4-23400' => 2933,
+ 'PC4-23466' => 2933,
'PC4-24000' => 3000,
'PC4-25600' => 3200,
'PC4-28800' => 3600,
'PC4-32000' => 4000,
'PC4-35200' => 4400,
# DDR5
+ 'PC5-32000' => 4000,
+ 'PC5-35200' => 4400,
'PC5-38400' => 4800,
+ 'PC5-41600' => 5200,
+ 'PC5-44800' => 5600,
+ 'PC5-48000' => 6000,
+ 'PC5-49600' => 6200,
'PC5-51200' => 6400,
+ 'PC5-54400' => 6800,
+ 'PC5-57600' => 7200,
+ 'PC5-60800' => 7600,
+ 'PC5-64000' => 8000,
# DDR6, coming...
- );
- return ($speeds{$type}) ? $speeds{$type} . ' MT/s' : $type;
+ # 'PC6-xxxxx' => 12800,
+ # 'PC6-xxxxx' => 17000, # overclocked
+ };
+}
+
+# args: 0: pc type string;
+sub speed_mapper {
+ eval $start if $b_log;
+ set_speed_maps if !$speed_maps;
+ eval $end if $b_log;
+ return ($speed_maps->{$_[0]}) ? $speed_maps->{$_[0]} . ' MT/s' : $_[0];
}
+
## START RAM VENDOR ##
sub set_ram_vendors {
$vendors = [
# A-Data xpg: AX4U; AX\d{4} for axiom
['^(A[DX]\dU|AVD|A[\s-]?Data)','A[\s-]?Data','A-Data',''],
- ['^(A[\s-]?Tech)','A[\s-]?Tech','A-Tech',''], # don't know part nu
+ ['^(A[\s-]?Tech)','A[\s-]?Tech','A-Tech',''], # Don't know part nu
['^(AX[\d]{4}|Axiom)','Axiom','Axiom',''],
['^(BD\d|Black[s-]?Diamond)','Black[s-]?Diamond','Black Diamond',''],
['^(-BN$|Brute[s-]?Networks)','Brute[s-]?Networks','Brute Networks',''],
@@ -22315,29 +24957,32 @@ sub set_ram_vendors {
['^(PE[\d]{4}|Edge)','Edge','Edge',''],
['^(Elpida|EB)','^Elpida','Elpida',''],
['^(GVT|Galvantech)','Galvantech','Galvantech',''],
- # if we get more G starters, make rules tighter
+ # If we get more G starters, make rules tighter
['^(G[A-Z]|Geil)','Geil','Geil',''],
# Note: FA- but make loose FA
['^(F4|G[\s\.-]?Skill)','G[\s\.-]?Skill','G.Skill',''],
+ ['^(GJN)','GJN','GJN',''],
['^(HP)','','HP',''], # no IDs found
['^(HX|HyperX)','HyperX','HyperX',''],
- # qimonda spun out of infineon, same ids
+ # Qimonda spun out of Infineon, same ids
# ['^(HYS]|Qimonda)','Qimonda','Qimonda',''],
['^(HY|Infineon)','Infineon','Infineon',''],#HY[A-Z]\d
['^(KSM|KVR|Kingston)','Kingston','Kingston',''],
['^(LuminouTek)','LuminouTek','LuminouTek',''],
['^(MT|Micron)','Micron','Micron',''],
- # seen: 992069 991434 997110S
+ # Seen: 992069 991434 997110S
['^(M[BLERS][A-Z][1-7]|99[0-9]{3}|Mushkin)','Mushkin','Mushkin',''],
['^(OCZ)','^OCZ\b','OCZ',''],
['^([MN]D\d|OLOy)','OLOy','OLOy',''],
['^(M[ERS]\d|Nemix)','Nemix','Nemix',''],
- # before patriot just in case
+ # Before patriot just in case
['^(MN\d|PNY)','PNY\s','PNY',''],
['^(P[A-Z]|Patriot)','Patriot','Patriot',''],
+ ['^RAMOS','^RAMOS','RAmos',''],
['^(K[1-6][ABLT]|K\d|M[\d]{3}[A-Z]|Samsung)','Samsung','Samsung',''],
['^(SP|Silicon[\s-]?Power)','Silicon[\s-]?Power','Silicon Power',''],
['^(STK|Simtek)','Simtek','Simtek',''],
+ ['^(Simmtronics|Gamex)','^Simmtronics','Simmtronics',''],
['^(HM[ACT]|SK[\s-]?Hynix)','SK[\s-]?Hynix','SK-Hynix',''],
# TED TTZD TLRD TDZAD TF4D4 TPD4 TXKD4 seen: HMT but could by skh
#['^(T(ED|D[PZ]|F\d|LZ|P[DR]T[CZ]|XK)|Team[\s-]?Group)','Team[\s-]?Group','TeamGroup',''],
@@ -22347,7 +24992,8 @@ sub set_ram_vendors {
['^(Yangtze|Zhitai|YMTC)','(Yangtze(\s*Memory)?|YMTC)','YMTC',''],
];
}
-# note: many of these are pci ids, not confirmed valid for ram
+
+# Note: many of these are pci ids, not confirmed valid for ram
sub set_ram_vendor_ids {
$vendor_ids = {
'01f4' => 'Transcend',# confirmed
@@ -22377,6 +25023,7 @@ sub set_ram_vendor_ids {
'80ce' => 'Samsung',# confirmed
'8551' => 'Qimonda',# confirmed
'8564' => 'Transcend',
+ '859b' => 'Crucial', # confirmed
'ad00' => 'SK-Hynix',# confirmed
'c0a9' => 'Crucial',
'ce00' => 'Samsung',# confirmed
@@ -22384,8 +25031,9 @@ sub set_ram_vendor_ids {
}
}
## END RAM VENDOR ##
+
sub ram_vendor {
- eval $end if $b_log;
+ eval $start if $b_log;
my ($id) = $_[0];
set_ram_vendors() if !$vendors;
my ($vendor);
@@ -22414,10 +25062,10 @@ sub ram_vendor {
## RepoItem
{
package RepoItem;
-
# easier to keep these package global, but undef after done
-my (@dbg_files,$debugger_dir);
+my (@dbg_files,$debugger_dir,%repo_keys);
my $num = 0;
+
sub get {
eval $start if $b_log;
($debugger_dir) = @_;
@@ -22428,7 +25076,7 @@ sub get {
$rows->[0]{$_} = $packages->{$_};
}
}
- my $start = scalar @$rows; # to test if we found more rows after
+ my $rows_start = scalar @$rows; # to test if we found more rows after
$num = 0;
if ($bsd_type){
get_repos_bsd($rows);
@@ -22440,9 +25088,10 @@ sub get {
@$rows = @dbg_files;
undef @dbg_files;
undef $debugger_dir;
+ undef %repo_keys;
}
else {
- if ($start == scalar @$rows){
+ if ($rows_start == scalar @$rows){
my $pm_missing;
if ($bsd_type){
$pm_missing = main::message('repo-data-bsd',$uname[0]);
@@ -22456,6 +25105,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub get_repos_linux {
eval $start if $b_log;
my $rows = $_[0];
@@ -22469,16 +25119,23 @@ sub get_repos_linux {
my $dnf_conf = '/etc/dnf/dnf.conf';
my $dnf_repo_dir = '/etc/dnf.repos.d/';
my $eopkg_dir = '/var/lib/eopkg/';
+ my $netpkg = '/etc/netpkg.conf';
+ my $netpkg_dir = '/etc/netpkg.d';
my $nix = '/etc/nix/nix.conf';
my $pacman = '/etc/pacman.conf';
my $pacman_g2 = '/etc/pacman-g2.conf';
my $pisi_dir = '/etc/pisi/';
my $portage_dir = '/etc/portage/repos.conf/';
my $portage_gentoo_dir = '/etc/portage-gentoo/repos.conf/';
+ my $sbopkg = '/etc/sbopkg/sbopkg.conf';
+ my $sboui_backend = '/etc/sboui/sboui-backend.conf';
my $scratchpkg = '/etc/scratchpkg.repo';
my $slackpkg = '/etc/slackpkg/mirrors';
my $slackpkg_plus = '/etc/slackpkg/slackpkgplus.conf';
my $slapt_get = '/etc/slapt-get/';
+ my $slpkg = '/etc/slpkg/repositories.toml';
+ my $tazpkg = '/etc/slitaz/tazpkg.conf';
+ my $tazpkg_mirror = '/var/lib/tazpkg/mirror';
my $tce_app = '/usr/bin/tce';
my $tce_file = '/opt/tcemirror';
my $tce_file2 = '/opt/localmirrors';
@@ -22488,8 +25145,8 @@ sub get_repos_linux {
my $xbps_dir_2 = '/usr/share/xbps.d/';
my $zypp_repo_dir = '/etc/zypp/repos.d/';
my $b_test = 0;
- # apt - debian, buntus, also sometimes some yum/rpm repos may create
- # apt repos here as well
+ ## apt: Debian, *buntus + derived (deb files);AltLinux, PCLinuxOS (rpm files)
+ # Sometimes some yum/rpm repos may create apt repos here as well
if (-f $apt || -d "$apt.d"){
my ($apt_arch,$apt_comp,$apt_suites,$apt_types,@apt_urls,@apt_working,
$b_apt_enabled,$file,$string);
@@ -22594,7 +25251,7 @@ sub get_repos_linux {
}
@files = ();
}
- # pacman: Arch and derived
+ ## pacman, pacman-g2: Arch + derived, Frugalware
if (-f $pacman || -f $pacman_g2){
$repo = 'pacman';
if (-f $pacman_g2){
@@ -22635,15 +25292,98 @@ sub get_repos_linux {
);
}
}
- # slackware
- if (-f $slackpkg || -f $slackpkg_plus || -d $slapt_get){
- #$slackpkg = "$ENV{HOME}/bin/scripts/inxi/data/repo/slackware/slackpkg-2.conf";
+ ## netpkg: Zenwalk, Slackware
+ if (-f $netpkg){
+ my @data2 = ($netpkg);
+ if (-d $netpkg_dir){
+ @data3 = main::globber("$netpkg_dir/*");
+ @data3 = grep {!/\/local$/} @data3 if @data3; # package directory
+ push(@data2,@data3) if @data3;
+ }
+ foreach my $file (@data2){
+ $data = repo_builder($file,'netpkg','^URL\s*=','\s*=\s*',1);
+ push(@$rows,@$data);
+ }
+ }
+ ## sbopkg, sboui, slackpkg, slackpkg+, slapt_get, slpkg: Slackware + derived
+ # $slpkg = "$fake_data_dir/repo/slackware/slpkg-2.toml";
+ # $sbopkg = "$fake_data_dir/repo/slackware/sbopkg-2.conf";
+ # $sboui_backend = "$fake_data_dir/repo/slackware/sboui-backend-1.conf";
+ if (-f $slackpkg || -f $slackpkg_plus || -d $slapt_get || -f $slpkg ||
+ -f $sbopkg || -f $sboui_backend){
+ if (-f $sbopkg){
+ my $sbo_root = '/root/.sbopkg.conf';
+ # $sbo_root = "$fake_data_dir/repo/slackware/sbopkg-root-1.conf";
+ @files = ($sbopkg);
+ # /root not readable as user, unless it is, so just check if readable
+ push(@files,$sbo_root) if -r $sbo_root;
+ my ($branch,$name);
+ # SRC_REPO repo URL not used, not what we think
+ foreach my $file (@files){
+ foreach my $row (main::reader($file,'strip')){
+ if ($row =~ /^REPO_NAME=(\S\{REPO_NAME:-)?(.*?)\}?$/){
+ $name = $2;
+ }
+ elsif ($row =~ /^REPO_BRANCH=(\S\{REPO_BRANCH:-)?(.*?)\}?$/){
+ $branch = $2;
+ }
+ }
+ }
+ # First found overridden by next, so we don't care where the value came
+ # from. We do care if 1 file and not root however, since might be wrong.
+ if ($branch && $name){
+ if ($b_root || scalar @files == 2){
+ $key = repo_data('active','sbopkg');
+ }
+ else {
+ $key = repo_data('active-permissions','sbopkg');
+ }
+ @content = ("$name ~ $branch");
+ }
+ else {
+ $key = repo_data('missing','sbopkg');
+ }
+ my @data = (
+ {main::key($num++,1,1,$key) => join(', ',@files)},
+ [@content],
+ );
+ push(@$rows,@data);
+ (@content,@files) = ();
+ }
+ if (-f $sboui_backend){
+ my ($branch,$repo);
+ # Note: sboui also has a sboui.conf file, with the package_manager string
+ # but that is too hard to handle clearly in output so leaving aside.
+ foreach my $row (main::reader($sboui_backend,'strip')){
+ if ($row =~ /^REPO\s*=\s*["']?(\S+?)["']?\s*$/){
+ $repo = $1;
+ }
+ elsif ($row =~ /^BRANCH\s*=\s*["']?(\S+?)["']?\s*$/){
+ $branch = $1;
+ }
+ }
+ if ($repo){
+ $key = repo_data('active','sboui');
+ $branch = 'current' if !$branch || $repo =~ /ponce/i;
+ @content = ("SBo $branch ~ $repo"); # we want SBo name to show
+ }
+ else {
+ $key = repo_data('missing','sboui');
+ }
+ my @data = (
+ {main::key($num++,1,1,$key) => $sboui_backend},
+ [@content],
+ );
+ push(@$rows,@data);
+ @content = ();
+ }
if (-f $slackpkg){
$data = repo_builder($slackpkg,'slackpkg','^[[:space:]]*[^#]+');
push(@$rows,@$data);
}
if (-d $slapt_get){
@data2 = main::globber("${slapt_get}*");
+ @data2 = grep {!/pubring/} @data2 if @data2;
foreach my $file (@data2){
$data = repo_builder($file,'slaptget','^\s*SOURCE','\s*=\s*',1);
push(@$rows,@$data);
@@ -22671,23 +25411,76 @@ sub get_repos_linux {
}
}
}
- if (! @content){
+ if (!@content){
$key = repo_data('missing','slackpkg+');
}
else {
clean_url(\@content);
$key = repo_data('active','slackpkg+');
}
- my @data = (
+ my @data = (
{main::key($num++,1,1,$key) => $slackpkg_plus},
[@content],
);
- clean_url(\@data);
push(@$rows,@data);
@content = ();
}
+ if (-f $slpkg){
+ my ($active,$name,$repo);
+ my $holder = '';
+ @data2 = main::reader($slpkg);
+ # We can't rely on the presence of empty lines as block separator.
+ push(@data2,'-eof-') if @data2;
+ # print Data::Dumper::Dumper \@data2;
+ # old: "https://download.salixos.org/x86_64/slackware-15.0/"
+ # new: ["https://slac...nl/people/alien/sbrepos/", "15.0/", "x86_64/"]
+ foreach (@data2){
+ next if /^\s*([#\[]|$)/;
+ $_ = lc($_);
+ if (/^\s*(\S+?)_(repo(|_name|_mirror))\s*=\s*[\['"]{0,2}(.*?)[\]'"]{0,2}\s*$/ ||
+ $_ eq '-eof-'){
+ my ($key,$value) = ($2,$4);
+ if (($1 && $holder ne $1) || $_ eq '-eof-'){
+ $holder = $1;
+ if ($name && $repo){
+ if (!$active || $active =~ /^(true|1|yes)$/i){
+ push(@content,"$name ~ $repo");
+ }
+ ($active,$name,$repo) = ();
+ }
+ }
+ if ($key){
+ if ($key eq 'repo'){
+ $active = $value;}
+ elsif ($key eq 'repo_name'){
+ $name = $value;}
+ elsif ($key eq 'repo_mirror'){
+ # map new form to a real url
+ $value =~ s/['"],\s*['"]//g;
+ $repo = $value;}
+ }
+ }
+ }
+ if (!@content){
+ $key = repo_data('missing','slpkg');
+ }
+ else {
+ # Special case, sbo and ponce true, dump sbo, they conflict.
+ # slpkg does this internally so no other way to handle.
+ if (grep {/^ponce ~/} @content){
+ @content = grep {!/sbo ~/} @content;
+ }
+ clean_url(\@content);
+ $key = repo_data('active','slpkg');
+ }
+ push(@$rows,
+ {main::key($num++,1,1,$key) => $slpkg},
+ [@content],
+ );
+ (@content,@data2,@data3) = ();
+ }
}
- # redhat/suse
+ ## dnf, yum, zypp: Redhat, Suse + derived (rpm based)
if (-f $dnf_conf ||-d $dnf_repo_dir|| -d $yum_repo_dir || -f $yum_conf ||
-d $zypp_repo_dir){
@files = ();
@@ -22753,8 +25546,7 @@ sub get_repos_linux {
if ($url && $title && $enabled){
push(@content, "$title ~ $url");
}
-
- if (! @content){
+ if (!@content){
$key = repo_data('missing',$repo);
}
else {
@@ -22770,7 +25562,7 @@ sub get_repos_linux {
}
# print Data::Dumper::Dumper \@$rows;
}
- # gentoo
+ # emerge, portage: Gentoo + derived
if ((-d $portage_dir || -d $portage_gentoo_dir) && main::check_program('emerge')){
@files = (main::globber("$portage_dir*.conf"),main::globber("$portage_gentoo_dir*.conf"));
$repo = 'portage';
@@ -22832,17 +25624,27 @@ sub get_repos_linux {
}
}
}
- # Alpine linux
- if (-f $apk){
- $data = repo_builder($apk,'apk','^\s*[^#]+');
- push(@$rows,@$data);
+ ## apk: Alpine, Chimera
+ if (-f $apk || -d "$apk.d"){
+ @files = main::globber("$apk.d/*.list");
+ push(@files, $apk);
+ # prefilter list for logging
+ @files = grep {-f $_} @files; # may not have $apk file.
+ main::log_data('data',"apk repo files:\n" . main::joiner(\@files, "\n", 'unset')) if $b_log;
+ foreach (sort @files){
+ # -r to be on safe side
+ if (-r $_){
+ $data = repo_builder($_,'apk','^\s*[^#]+');
+ push(@$rows,@$data);
+ }
+ }
}
- # Venom
+ ## scratchpkg: Venom
if (-f $scratchpkg){
$data = repo_builder($scratchpkg,'scratchpkg','^[[:space:]]*[^#]+');
push(@$rows,@$data);
}
- # cards/nutyx
+ # cards: Nutyx
if (-f $cards){
@data3 = main::reader($cards,'clean');
push(@dbg_files, $cards) if $debugger_dir;
@@ -22852,7 +25654,7 @@ sub get_repos_linux {
push(@content, "$1 ~ $type");
}
}
- if (! @content){
+ if (!@content){
$key = repo_data('missing','cards');
}
else {
@@ -22865,7 +25667,12 @@ sub get_repos_linux {
);
@content = ();
}
- # TinyCore
+ ## tazpkg: Slitaz
+ if (-e $tazpkg || -e $tazpkg_mirror){
+ $data = repo_builder($tazpkg_mirror,'tazpkg','^\s*[^#]+');
+ push(@$rows,@$data);
+ }
+ ## tce: TinyCore
if (-e $tce_app || -f $tce_file || -f $tce_file2){
if (-f $tce_file){
$data = repo_builder($tce_file,'tce','^\s*[^#]+');
@@ -22876,7 +25683,7 @@ sub get_repos_linux {
push(@$rows,@$data);
}
}
- # Void
+ ## xbps: Void
if (-d $xbps_dir_1 || -d $xbps_dir_2){
@files = main::globber("$xbps_dir_1*.conf");
push(@files,main::globber("$xbps_dir_2*.conf")) if -d $xbps_dir_2;
@@ -22888,22 +25695,22 @@ sub get_repos_linux {
}
}
}
- # Mandriva/Mageia using: urpmq
+ ## urpmq: Mandriva, Mageia
if ($path = main::check_program('urpmq')){
- @data2 = main::grabber("$path --list-media active --list-url","\n",'strip');
+ @data2 = main::grabber("$path --list-media active --list-url 2>/dev/null","\n",'strip');
main::writer("$debugger_dir/system-repo-data-urpmq.txt",\@data2) if $debugger_dir;
- # now we need to create the structure: repo info: repo path
- # we do that by looping through the lines of the output and then
- # putting it back into the <data>:<url> format print repos expects to see
- # note this structure in the data, so store first line and make start of line
- # then when it's an http line, add it, and create the full line collection.
+ # Now we need to create the structure: repo info: repo path. We do that by
+ # looping through the lines of the output and then putting it back into the
+ # <data>:<url> format print repos expects to see. Note this structure in the
+ # data, so store first line and make start of line then when it's an http
+ # line, add it, and create the full line collection.
# Contrib ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2011/x86_64/media/contrib/release
# Contrib Updates ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2011/x86_64/media/contrib/updates
# Non-free ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2011/x86_64/media/non-free/release
# Non-free Updates ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2011/x86_64/media/non-free/updates
# Nonfree Updates (Local19) /mnt/data/mirrors/mageia/distrib/cauldron/x86_64/media/nonfree/updates
foreach (@data2){
- # need to dump leading/trailing spaces and clear out color codes for irc output
+ # Need to dump leading/trailing spaces and clear out color codes for irc output
$_ =~ s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g;
$_ =~ s/\e\[([0-9];)?[0-9]+m//g;
# urpmq output is the same each line, repo name space repo url, can be:
@@ -22915,14 +25722,14 @@ sub get_repos_linux {
# get the repo
$repo = $2;
push(@$rows,
- {main::key($num++,1,1,'urpmq repo') => $repo},
+ {main::key($num++,1,1,'urpm repo') => $repo},
[@content],
);
@content = ();
}
}
}
- # Pardus/Solus
+ # pisi: Pardus, Solus
if ((-d $pisi_dir && ($path = main::check_program('pisi'))) ||
(-d $eopkg_dir && ($path = main::check_program('eopkg')))){
#$path = 'eopkg';
@@ -22932,11 +25739,11 @@ sub get_repos_linux {
# @data2 = main::reader($file,'strip');
@data2 = main::grabber("$cmd 2>/dev/null","\n",'strip');
main::writer("$debugger_dir/system-repo-data-$which.txt",\@data2) if $debugger_dir;
- # now we need to create the structure: repo info: repo path
- # we do that by looping through the lines of the output and then
- # putting it back into the <data>:<url> format print repos expects to see
- # note this structure in the data, so store first line and make start of line
- # then when it's an http line, add it, and create the full line collection.
+ # Now we need to create the structure: repo info: repo path
+ # We do that by looping through the lines of the output and then putting it
+ # back into the <data>:<url> format print repos expects to see. Note this
+ # structure in the data, so store first line and make start of line then
+ # when it's an http line, add it, and create the full line collection.
# Pardus-2009.1 [Aktiv]
# http://packages.pardus.org.tr/pardus-2009.1/pisi-index.xml.bz2
# Contrib [Aktiv]
@@ -22977,6 +25784,7 @@ sub get_repos_linux {
);
}
}
+ ## nix: General pm for Linux/Unix
if (-f $nix && ($path = main::check_program('nix-channel'))){
@content = main::grabber("$path --list 2>/dev/null","\n",'strip');
main::writer("$debugger_dir/system-repo-data-nix.txt",\@content) if $debugger_dir;
@@ -22998,6 +25806,7 @@ sub get_repos_linux {
# print Dumper $rows;
eval $end if $b_log;
}
+
sub get_repos_bsd {
eval $start if $b_log;
my $rows = $_[0];
@@ -23088,31 +25897,31 @@ sub get_repos_bsd {
push(@$rows,@$data);
}
# I don't think this is right, have to find out, for midnightbsd
-# if (-f $mports){
-# @data = main::reader($mports,'strip');
-# main::writer("$debugger_dir/system-repo-data-mports.txt",\@data) if $debugger_dir;
-# for (@data){
-# if (!/^MASTER_SITE_INDEX/){
-# next;
-# }
-# else {
-# push(@data3,(split(/=\s*/,$_))[1]);
-# }
-# last if /^INDEX/;
-# }
-# if (!@data3){
-# $key = repo_data('missing','mports');
-# }
-# else {
-# clean_url(\@data3);
-# $key = repo_data('active','mports');
-# }
-# push(@$rows,
-# {main::key($num++,1,1,$key) => $mports},
-# [@data3],
-# );
-# @data3 = ();
-# }
+ # if (-f $mports){
+ # @data = main::reader($mports,'strip');
+ # main::writer("$debugger_dir/system-repo-data-mports.txt",\@data) if $debugger_dir;
+ # for (@data){
+ # if (!/^MASTER_SITE_INDEX/){
+ # next;
+ # }
+ # else {
+ # push(@data3,(split(/=\s*/,$_))[1]);
+ # }
+ # last if /^INDEX/;
+ # }
+ # if (!@data3){
+ # $key = repo_data('missing','mports');
+ # }
+ # else {
+ # clean_url(\@data3);
+ # $key = repo_data('active','mports');
+ # }
+ # push(@$rows,
+ # {main::key($num++,1,1,$key) => $mports},
+ # [@data3],
+ # );
+ # @data3 = ();
+ # }
# BSDs do not default always to having repo files, so show correct error
# mesage in that case
if (!@$rows){
@@ -23135,10 +25944,10 @@ sub get_repos_bsd {
}
eval $start if $b_log;
}
-sub repo_data {
+
+sub set_repo_keys {
eval $start if $b_log;
- my ($status,$type) = @_;
- my %keys = (
+ %repo_keys = (
'apk-active' => 'APK repo',
'apk-missing' => 'No active APK repos in',
'apt-active' => 'Active apt repos in',
@@ -23163,6 +25972,8 @@ sub repo_data {
'netbsd-active' => 'NetBSD pkg servers',
'netbsd-files-missing' => 'No NetBSD pkg server files found',
'netbsd-missing' => 'No NetBSD pkg servers in',
+ 'netpkg-active' => 'Active netpkg repos in',
+ 'netpkg-missing' => 'No active netpkg repos in',
'nix-active' => 'Active nix channels for user',
'nix-missing' => 'No nix channels found for user',
'openbsd-active' => 'OpenBSD pkg mirror',
@@ -23178,6 +25989,11 @@ sub repo_data {
'portage-missing' => 'No enabled portage sources in',
'portsnap-active' => 'Ports server',
'portsnap-missing' => 'No ports servers in',
+ 'sbopkg-active' => 'Active sbopkg repo',
+ 'sbopkg-active-permissions' => 'Active sbopkg repo (confirm with root)',
+ 'sbopkg-missing' => 'No sbopkg repo',
+ 'sboui-active' => 'Active sboui repo',
+ 'sboui-missing' => 'No sboui repo',
'scratchpkg-active' => 'scratchpkg repos in',
'scratchpkg-missing' => 'No active scratchpkg repos in',
'slackpkg-active' => 'slackpkg mirror in',
@@ -23186,6 +26002,10 @@ sub repo_data {
'slackpkg+-missing' => 'No active slackpkg+ repos in',
'slaptget-active' => 'slapt-get repos in',
'slaptget-missing' => 'No active slapt-get repos in',
+ 'slpkg-active' => 'Active slpkg repos in',
+ 'slpkg-missing' => 'No active slpkg repos in',
+ 'tazpkg-active' => 'tazpkg mirrors in',
+ 'tazpkg-missing' => 'No tazpkg mirrors in',
'tce-active' => 'tce mirrors in',
'tce-missing' => 'No tce mirrors in',
'xbps-active' => 'Active xbps repos in',
@@ -23196,8 +26016,16 @@ sub repo_data {
'zypp-missing' => 'No active zypp repos in',
);
eval $end if $b_log;
- return $keys{$type . '-' . $status};
}
+
+sub repo_data {
+ eval $start if $b_log;
+ my ($status,$type) = @_;
+ set_repo_keys() if !%repo_keys;
+ eval $end if $b_log;
+ return $repo_keys{$type . '-' . $status};
+}
+
sub repo_builder {
eval $start if $b_log;
my ($file,$type,$search,$split,$count) = @_;
@@ -23227,21 +26055,26 @@ sub repo_builder {
[@content],
];
}
+
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/\[\s+/[/g; # [ signed-by
+ $_ =~ s/\s+\]/]/g;
$_ =~ s/^(.*\/.*) #.*/$1/;
$_;} @{$_[0]};
}
-# clean if irc
+
+# Clean if irc
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) = @_;
my ($working);
@@ -23259,6 +26092,7 @@ package SensorItem;
my $gpu_data = [];
my $sensors_raw = {};
my $max_fan = 15000;
+
sub get {
eval $start if $b_log;
my ($b_data,$b_ipmi,$b_no_lm,$b_no_sys);
@@ -23370,6 +26204,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub sensors_output {
eval $start if $b_log;
my ($rows,$source,$sensors) = @_;
@@ -23435,7 +26270,7 @@ sub sensors_output {
@fan_main = @{$sensors->{'fan-main'}} if $sensors->{'fan-main'};
@fan_default = @{$sensors->{'fan-default'}} if $sensors->{'fan-default'};
my $fan_def = (!@fan_main && !@fan_default) ? 'N/A' : '';
- $rows->[$j]{main::key($num++,1,$l1,'Fan Speeds (RPM)')} = $fan_def;
+ $rows->[$j]{main::key($num++,1,$l1,'Fan Speeds (rpm)')} = $fan_def;
my $b_cpu = 0;
for (my $i = 0; $i < scalar @fan_main; $i++){
next if $i == 0;# starts at 1, not 0
@@ -23546,6 +26381,7 @@ sub sensors_output {
eval $end if $b_log;
return $b_result;
}
+
sub ipmi_data {
eval $start if $b_log;
my ($program) = @_;
@@ -23555,19 +26391,19 @@ sub ipmi_data {
my $sensors = {};
if ($fake{'ipmi'}){
## ipmitool ##
- # $file = "$fake_data_dir/ipmitool/ipmitool-sensors-archerseven-1.txt";$program='ipmitool';
- # $file = "$fake_data_dir/ipmitool/ipmitool-sensors-epyc-1.txt";$program='ipmitool';
- # $file = "$fake_data_dir/ipmitool/ipmitool-sensors-RK016013.txt";$program='ipmitool';
- # $file = "$fake_data_dir/ipmitool/ipmitool-sensors-freebsd-offsite-backup.txt";
- # $file = "$fake_data_dir/ipmitool/ipmitool-sensor-shom-1.txt";$program='ipmitool';
- # $file = "$fake_data_dir/ipmitool/ipmitool-sensor-shom-2.txt";$program='ipmitool';
- # $file = "$fake_data_dir/ipmitool/ipmitool-sensor-tyan-1.txt";$program='ipmitool';
+ # $file = "$fake_data_dir/sensors/ipmitool/ipmitool-sensors-archerseven-1.txt";$program='ipmitool';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmitool-sensors-epyc-1.txt";$program='ipmitool';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmitool-sensors-RK016013.txt";$program='ipmitool';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmitool-sensors-freebsd-offsite-backup.txt";
+ # $file = "$fake_data_dir/sensorsipmitool/ipmitool-sensor-shom-1.txt";$program='ipmitool';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmitool-sensor-shom-2.txt";$program='ipmitool';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmitool-sensor-tyan-1.txt";$program='ipmitool';
# ($b_ipmitool,$i_key,$i_value,$i_unit) = (1,0,1,2); # ipmitool sensors
## ipmi-sensors ##
- # $file = "$fake_data_dir/ipmitool/ipmi-sensors-epyc-1.txt";$program='ipmi-sensors';
- # $file = "$fake_data_dir/ipmitool/ipmi-sensors-lathander.txt";$program='ipmi-sensors';
- # $file = "$fake_data_dir/ipmitool/ipmi-sensors-zwerg.txt";$program='ipmi-sensors';
- # $file = "$fake_data_dir/ipmitool/ipmi-sensors-arm-server-1.txt";$program='ipmi-sensors';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmi-sensors-epyc-1.txt";$program='ipmi-sensors';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmi-sensors-lathander.txt";$program='ipmi-sensors';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmi-sensors-zwerg.txt";$program='ipmi-sensors';
+ # $file = "$fake_data_dir/sensorsipmitool/ipmi-sensors-arm-server-1.txt";$program='ipmi-sensors';
# ($b_ipmitool,$i_key,$i_value,$i_unit) = (0,1,3,4); # ipmi-sensors
# @data = main::reader($file);
}
@@ -23734,6 +26570,7 @@ sub ipmi_data {
print Data::Dumper::Dumper $sensors if $dbg[31];
return $sensors;
}
+
sub linux_sensors_data {
eval $start if $b_log;
my $sensors = {};
@@ -23936,7 +26773,6 @@ sub linux_sensors_data {
}
}
}
-
print Data::Dumper::Dumper $sensors if $dbg[31];
process_data($sensors) if %$sensors;
main::log_data('dump','lm-sensors: %sensors',$sensors) if $b_log;
@@ -23944,26 +26780,27 @@ sub linux_sensors_data {
eval $end if $b_log;
return $sensors;
}
+
sub load_lm_sensors {
eval $start if $b_log;
my (@sensors_data,@values);
my ($adapter,$holder,$type) = ('','','');
if ($fake{'sensors'}){
# my $file;
- # $file = "$fake_data_dir/sensors/amdgpu-w-fan-speed-stretch-k10.txt";
- # $file = "$fake_data_dir/sensors/peci-tin-geggo.txt";
- # $file = "$fake_data_dir/sensors/sensors-w-other-biker.txt";
- # $file = "$fake_data_dir/sensors/sensors-asus-chassis-1.txt";
- # $file = "$fake_data_dir/sensors/sensors-devnull-1.txt";
- # $file = "$fake_data_dir/sensors/sensors-jammin1.txt";
- # $file = "$fake_data_dir/sensors/sensors-mx-incorrect-1.txt";
- # $file = "$fake_data_dir/sensors/sensors-maximus-arch-1.txt";
- # $file = "$fake_data_dir/sensors/kernel-58-sensors-ant-1.txt";
- # $file = "$fake_data_dir/sensors/sensors-zenpower-nvme-2.txt";
- # $file = "$fake_data_dir/sensors/sensors-pch-intel-1.txt";
- # $file = "$fake_data_dir/sensors/sensors-ppc-sr71.txt";
- # $file = "$fake_data_dir/sensors/sensors-coretemp-acpitz-1.txt";
- # $file = "$fake_data_dir/sensors/sensors-applesmc-1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/amdgpu-w-fan-speed-stretch-k10.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/peci-tin-geggo.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-w-other-biker.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-asus-chassis-1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-devnull-1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-jammin1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-mx-incorrect-1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-maximus-arch-1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/kernel-58-sensors-ant-1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-zenpower-nvme-2.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-pch-intel-1.txt";
+ # $file = "$fake_data_dir/sensors/slm-sensors/ensors-ppc-sr71.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-coretemp-acpitz-1.txt";
+ # $file = "$fake_data_dir/sensors/lm-sensors/sensors-applesmc-1.txt";
# @sensors_data = main::reader($file);
}
else {
@@ -24027,6 +26864,7 @@ sub load_lm_sensors {
main::log_data('dump','lm-sensors data: %$sensors_raw',$sensors_raw) if $b_log;
eval $end if $b_log;
}
+
sub load_sys_data {
eval $start if $b_log;
my ($device,$mon,$name,$label,$unit,$value,@values,%hwmons);
@@ -24126,15 +26964,16 @@ sub load_sys_data {
my $adapter = $hwmons{$hwmon}->{'name'};
$hwmons{$hwmon}->{'device'} =~ s/^0000://;
$adapter .= '-' . $hwmons{$hwmon}->{'device'};
- @values = ();
+ ($unit,$value,@values) = ();
foreach my $item (@{$hwmons{$hwmon}->{'sensors'}}){
+ next if !defined $item->{'id'};
my $name = ($item->{'label'}) ? $item->{'label'}: $item->{'id'};
if ($item->{'id'} =~ /^temp/){
$unit = 'C';
$value = sprintf('%0.1f',$item->{'value'}/1000);
}
elsif ($item->{'id'} =~ /^fan/){
- $unit = 'RPM';
+ $unit = 'rpm';
$value = $item->{'value'};
}
# note: many sensors require further math on value, so these will be wrong
@@ -24163,15 +27002,17 @@ sub load_sys_data {
$unit = 'W';
$value = sprintf('%0.1f',$item->{'value'}/1000);
}
- my $string = $name . ':' . $value . " $unit";
- push(@values,$string);
+ if (defined $value && defined $unit){
+ my $string = $name . ':' . $value . " $unit";
+ push(@values,$string);
+ }
}
-# if ($hwmons{$hwmon}->{'type'} eq 'acpitz' && $hwmons{$hwmon}->{'device'}){
-# my $tz ='/sys/class/thermal/' . $hwmons{$hwmon}->{'device'} . '/type';
-# if (-e $tz){
-# my $tz_type = main::reader($tz,'strip',0),"\n";
-# }
-# }
+ # if ($hwmons{$hwmon}->{'type'} eq 'acpitz' && $hwmons{$hwmon}->{'device'}){
+ # my $tz ='/sys/class/thermal/' . $hwmons{$hwmon}->{'device'} . '/type';
+ # if (-e $tz){
+ # my $tz_type = main::reader($tz,'strip',0),"\n";
+ # }
+ # }
if (@values){
$sensors_raw->{$hwmons{$hwmon}->{'type'}}{$adapter} = [@values];
}
@@ -24255,6 +27096,7 @@ sub sysctl_data {
eval $end if $b_log;
return $sensors;
}
+
sub set_temp_unit {
my ($sensors,$working) = @_;
my $return_unit = '';
@@ -24525,6 +27367,7 @@ sub process_data {
}
eval $end if $b_log;
}
+
sub gpu_sensor_data {
eval $start if $b_log;
my ($cmd,@data,@data2,$path,@screens,$temp);
@@ -24655,6 +27498,7 @@ sub gpu_sensor_data {
{
package SlotItem;
my ($sys_slots);
+
sub get {
eval $start if $b_log;
my ($data,$key1,$val1);
@@ -24688,6 +27532,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub slot_output {
eval $start if $b_log;
my ($rows,$data) = @_;
@@ -24767,6 +27612,7 @@ sub children_output {
}
}
}
+
sub slot_data_dmi {
eval $start if $b_log;
my $i = 0;
@@ -24878,6 +27724,7 @@ sub slot_data_dmi {
eval $end if $b_log;
return $slots;
}
+
sub slot_data_sys {
eval $start if $b_log;
my $path = '/sys/devices/pci0000:*/00*';
@@ -24892,6 +27739,7 @@ sub slot_data_sys {
main::log_data('dump','$sys_slots',$sys_slots) if $b_log;
eval $end if $b_log;
}
+
sub slot_data_recursive {
eval $start if $b_log;
my $path = shift @_;
@@ -24927,6 +27775,7 @@ sub slot_data_recursive {
eval $end if $b_log;
return $info;
}
+
sub slot_children {
eval $start if $b_log;
my ($bus_id,$slots) = @_;
@@ -24938,6 +27787,7 @@ sub slot_children {
eval $end if $b_log;
return $children;
}
+
sub slot_children_recursive {
my ($bus_id,$slots) = @_;
my $children;
@@ -24969,6 +27819,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub create_output {
eval $start if $b_log;
my $rows = $_[0];
@@ -24996,6 +27847,16 @@ sub create_output {
if (defined $row->{'cache-pressure'}){
$rows->[$j]{main::key($num++,0,2,'cache-pressure')} = $row->{'cache-pressure'};
}
+ $row->{'zswap-enabled'} ||= 'N/A';
+ $rows->[$j]{main::key($num++,1,2,'zswap')} = $row->{'zswap-enabled'};
+ if ($row->{'zswap-enabled'} eq 'yes'){
+ if (defined $row->{'zswap-compressor'}){
+ $rows->[$j]{main::key($num++,0,1,'compressor')} = $row->{'zswap-compressor'};
+ }
+ if (defined $row->{'zswap-max-pool-percent'}){
+ $rows->[$j]{main::key($num++,0,1,'max-pool')} = $row->{'zswap-max-pool-percent'} . '%';
+ }
+ }
}
else {
$rows->[$j]{main::key($num++,0,1,'Message')} = main::message('swap-admin');
@@ -25027,6 +27888,17 @@ sub create_output {
if ($extra > 1 && defined $row->{'priority'}){
$rows->[$j]{main::key($num++,0,2,'priority')} = $row->{'priority'};
}
+ if ($b_admin && $row->{'swap-type'} eq 'zram'){
+ if ($row->{'zram-comp'}){
+ $rows->[$j]{main::key($num++,1,2,'comp')} = $row->{'zram-comp'};
+ if ($row->{'zram-comp-avail'}){
+ $rows->[$j]{main::key($num++,0,3,'avail')} = $row->{'zram-comp-avail'};
+ }
+ }
+ if ($row->{'zram-max-comp-streams'}){
+ $rows->[$j]{main::key($num++,0,3,'max-streams')} = $row->{'zram-max-comp-streams'};
+ }
+ }
$row->{'mount'} =~ s|/home/[^/]+/(.*)|/home/$filter_string/$1| if $row->{'mount'} && $use{'filter'};
$rows->[$j]{main::key($num++,1,2,$dev)} = ($row->{'mount'}) ? $row->{'mount'} : 'N/A';
if ($b_admin && $row->{'maj-min'}){
@@ -25052,7 +27924,6 @@ sub create_output {
}
eval $end if $b_log;
}
-
}
## UnmountedItem
@@ -25110,13 +27981,14 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub create_output {
eval $start if $b_log;
my ($rows,$unmounted) = @_;
my ($fs);
my ($j,$num) = (0,0);
@$unmounted = sort { $a->{'dev-base'} cmp $b->{'dev-base'} } @$unmounted;
- my $fs_skip = PartitionItem::fs_excludes('label-uuid');
+ my $fs_skip = PartitionItem::get_filters('fs-skip');
foreach my $row (@$unmounted){
$num = 1;
my $size = ($row->{'size'}) ? main::get_size($row->{'size'},'string') : 'N/A';
@@ -25168,6 +28040,7 @@ sub create_output {
}
eval $end if $b_log;
}
+
sub proc_data {
eval $start if $b_log;
my ($dev_mapped,$fs,$label,$maj_min,$size,$uuid,$part);
@@ -25249,6 +28122,7 @@ sub proc_data {
eval $end if $b_log;
return $unmounted;
}
+
sub bsd_data {
eval $start if $b_log;
my ($fs,$label,$size,$uuid,%part);
@@ -25283,6 +28157,7 @@ sub bsd_data {
eval $end if $b_log;
return $unmounted;
}
+
sub get_mounted {
eval $start if $b_log;
my (@arrays);
@@ -25317,6 +28192,7 @@ sub get_mounted {
eval $end if $b_log;
return $mounted;
}
+
# bsds do not seem to return any useful data so only for linux
sub unmounted_filesystem {
eval $start if $b_log;
@@ -25355,6 +28231,7 @@ sub unmounted_filesystem {
## UsbItem
{
package UsbItem;
+
sub get {
eval $start if $b_log;
my ($key1,$val1);
@@ -25379,10 +28256,10 @@ sub get {
$key1 = $alerts{'usbconfig'}->{'action'};
$val1 = $alerts{'usbconfig'}->{'message'};
}
-# elsif ($alerts{'lsusb'}->{'action'} eq 'missing'){
-# $key1 = $alerts{'lsusb'}->{'action'};
-# $val1 = $alerts{'lsusb'}->{'message'};
-# }
+ # elsif ($alerts{'lsusb'}->{'action'} eq 'missing'){
+ # $key1 = $alerts{'lsusb'}->{'action'};
+ # $val1 = $alerts{'lsusb'}->{'message'};
+ # }
}
$key1 = ucfirst($key1);
@$rows = ({main::key($num++,0,1,$key1) => $val1});
@@ -25399,26 +28276,27 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub usb_output {
eval $start if $b_log;
return if !$usb{'main'};
my $rows = $_[0];
- my ($b_hub,$bus_id,$chip_id,$driver,$ind_sc,$path_id,$ports,$product,$serial,
- $speed,$type);
+ my ($b_hub,$bus_id,$chip_id,$driver,$ind_rc,$ind_sc,$path_id,$ports,$product,
+ $rev,$serial,$speed_si,$type);
my $num = 0;
my $j = 0;
# note: the data has been presorted in UsbData:
# bus alpah id, so we don't need to worry about the order
foreach my $id (@{$usb{'main'}}){
$j = scalar @$rows;
- ($b_hub,$ind_sc,$num) = (0,3,1);
- ($driver,$path_id,$ports,$product,
- $serial,$speed,$type) = ('','','','','','','');
- $speed = (main::is_numeric($id->[8])) ? sprintf("%1.1f",$id->[8]) : $id->[8] if $id->[8];
+ ($b_hub,$ind_rc,$ind_sc,$num) = (0,4,3,1);
+ ($driver,$path_id,$ports,$product,$rev,$serial,$speed_si,
+ $type) = ('','','','','','','','','');
+ $rev = $id->[8] if $id->[8];
$product = main::clean($id->[13]) if $id->[13];
$serial = main::filter($id->[16]) if $id->[16];
$product ||= 'N/A';
- $speed ||= 'N/A';
+ $rev ||= 'N/A';
$path_id = $id->[2] if $id->[2];
$bus_id = "$path_id:$id->[1]";
# it's a hub
@@ -25430,9 +28308,9 @@ sub usb_output {
main::key($num++,1,1,'Hub') => $bus_id,
main::key($num++,0,2,'info') => $product,
main::key($num++,0,2,'ports') => $ports,
- main::key($num++,0,2,'rev') => $speed,
},);
$b_hub = 1;
+ $ind_rc =3;
$ind_sc =2;
}
# it's a device
@@ -25451,30 +28329,43 @@ sub usb_output {
if ($extra > 2 && $id->[9]){
$rows->[$j]{main::key($num++,0,3,'interfaces')} = $id->[9];
}
- $rows->[$j]{main::key($num++,0,3,'rev')} = $speed;
}
# for either hub or device
- if ($extra > 1 && main::is_numeric($id->[17])){
- my $speed = $id->[17];
- if ($speed >= 1000){$speed = ($id->[17]/1000) . " Gb/s"}
- else {$speed = $id->[17] . " Mb/s"}
- $rows->[$j]{main::key($num++,0,$ind_sc,'speed')} = $speed;
- }
- if ($extra > 2 && $id->[19] && $id->[19] ne '0mA'){
- $rows->[$j]{main::key($num++,0,$ind_sc,'power')} = $id->[19];
- }
- if ($extra > 1){
+ $rows->[$j]{main::key($num++,1,$ind_sc,'rev')} = $rev;
+ if ($extra > 0){
+ $speed_si = ($id->[17]) ? $id->[17] : 'N/A';
+ $speed_si .= " ($id->[25])" if ($b_admin && $id->[25]);
+ $rows->[$j]{main::key($num++,0,$ind_rc,'speed')} = $speed_si;
+ if ($extra > 1){
+ if ($id->[24]){
+ if ($id->[23] == $id->[24]){
+ $rows->[$j]{main::key($num++,0,$ind_rc,'lanes')} = $id->[24];
+ }
+ else {
+ $rows->[$j]{main::key($num++,1,$ind_rc,'lanes')} = '';
+ $rows->[$j]{main::key($num++,0,($ind_rc+1),'rx')} = $id->[23];
+ $rows->[$j]{main::key($num++,0,($ind_rc+1),'tx')} = $id->[24];
+ }
+ }
+ }
+ # 22 is only available if 23 and 24 are present as well
+ if ($b_admin && $id->[22]){
+ $rows->[$j]{main::key($num++,0,$ind_rc,'mode')} = $id->[22];
+ }
+ if ($extra > 2 && $id->[19] && $id->[19] ne '0mA'){
+ $rows->[$j]{main::key($num++,0,$ind_sc,'power')} = $id->[19];
+ }
$chip_id = $id->[7];
$chip_id ||= 'N/A';
$rows->[$j]{main::key($num++,0,$ind_sc,'chip-ID')} = $chip_id;
- }
- if ($extra > 2 && defined $id->[5] && $id->[5] ne ''){
- my $id = sprintf("%02s",$id->[4]) . sprintf("%02s", $id->[5]);
- $rows->[$j]{main::key($num++,0,$ind_sc,'class-ID')} = $id;
- }
- if (!$b_hub && $extra > 2){
- if ($serial){
- $rows->[$j]{main::key($num++,0,$ind_sc,'serial')} = main::filter($serial);
+ if ($extra > 2 && defined $id->[5] && $id->[5] ne ''){
+ my $id = sprintf("%02s",$id->[4]) . sprintf("%02s", $id->[5]);
+ $rows->[$j]{main::key($num++,0,$ind_sc,'class-ID')} = $id;
+ }
+ if (!$b_hub && $extra > 2){
+ if ($serial){
+ $rows->[$j]{main::key($num++,0,$ind_sc,'serial')} = main::filter($serial);
+ }
}
}
}
@@ -25487,12 +28378,14 @@ sub usb_output {
# add metric / imperial (us) switch
{
package WeatherItem;
+
sub get {
eval $start if $b_log;
my $rows = [];
my $num = 0;
my $location = [];
location_data($location);
+ # print Data::Dumper::Dumper $location;exit;
if (!$location->[0]){
@$rows = ({
main::key($num++,0,1,'Message') => main::message('weather-null','current location')
@@ -25522,6 +28415,7 @@ sub get {
eval $end if $b_log;
return $rows;
}
+
sub weather_output {
eval $start if $b_log;
my ($rows,$location,$weather) = @_;
@@ -25651,6 +28545,7 @@ sub weather_output {
}
eval $end if $b_log;
}
+
sub process_elevation {
eval $start if $b_log;
my ($meters,$feet) = @_;
@@ -25676,6 +28571,7 @@ sub process_elevation {
eval $end if $b_log;
return $result;
}
+
sub process_unit {
eval $start if $b_log;
my ($primary,$metric,$m_unit,$imperial,$i_unit) = @_;
@@ -25701,6 +28597,7 @@ sub process_unit {
eval $end if $b_log;
return $result;
}
+
sub process_wind {
eval $start if $b_log;
my ($primary,$direction,$mph,$ms,$gust_mph,$gust_ms) = @_;
@@ -25760,6 +28657,7 @@ sub process_wind {
eval $end if $b_log;
return $result;
}
+
sub get_weather {
eval $start if $b_log;
my ($location) = @_;
@@ -25914,9 +28812,9 @@ sub get_weather {
$working[1] =~ /^([0-9\.]+)\sF\s\(([0-9\.]+)\sC\)/;
$weather->{'temp-c'} = $2;;
$weather->{'temp-f'} = $1;
-# $weather->{'temp'} =~ s/\sF/\xB0 F/; # B0
-# $weather->{'temp'} =~ s/\sF/\x{2109}/;
-# $weather->{'temp'} =~ s/\sC/\x{2103}/;
+ # $weather->{'temp'} =~ s/\sF/\xB0 F/; # B0
+ # $weather->{'temp'} =~ s/\sF/\x{2109}/;
+ # $weather->{'temp'} =~ s/\sC/\x{2103}/;
}
elsif ($working[0] eq 'temp_f'){
$weather->{'temp-f'} = $working[1];
@@ -26010,6 +28908,7 @@ sub get_weather {
eval $end if $b_log;
return $weather;
}
+
sub download_weather {
eval $start if $b_log;
my ($now,$file_cached,$location) = @_;
@@ -26035,7 +28934,8 @@ sub download_weather {
eval $end if $b_log;
return $weather;
}
-# resolve wide character issue, if detected, switch to iso
+
+# Rsolve wide character issue, if detected, switch to iso
# date format, we won't try to be too clever here.
sub test_locale_date {
my ($date_time,$location,$epoch) = @_;
@@ -26081,6 +28981,7 @@ sub location_data {
}
eval $end if $b_log;
}
+
sub get_location {
eval $start if $b_log;
my $location = $_[0];
@@ -26170,6 +29071,7 @@ sub get_location {
# print ($loc_arg,"\n", join("\n", @loc_data), "\n",scalar @loc_data, "\n");
eval $end if $b_log;
}
+
sub complete_location {
eval $start if $b_log;
my ($location,$city,$state,$country) = @_;
@@ -26237,85 +29139,38 @@ sub set_build_prop {
eval $end if $b_log;
}
-## CompilerVersion
-{
-package CompilerVersion;
-sub get {
- eval $start if $b_log;
- my $compiler = [];
- if (my $file = $system_files{'proc-version'}){
- version_proc($compiler,$file);
- }
- elsif ($bsd_type){
- version_bsd($compiler);
- }
- eval $end if $b_log;
- return $compiler;
-}
-
-sub version_bsd {
+# Return all detected compiler versions
+# args: 0: compiler
+sub get_compiler_data {
eval $start if $b_log;
my $compiler = $_[0];
- my (@working);
- if ($alerts{'sysctl'}->{'action'} && $alerts{'sysctl'}->{'action'} eq 'use'){
- if ($sysctl{'kernel'}){
- my @working;
- foreach (@{$sysctl{'kernel'}}){
- # Not every line will have a : separator though the processor should make
- # most have it. This appears to be 10.x late feature add, I don't see it
- # on earlier BSDs
- if (/^kern.compiler_version/){
- @working = split(/:\s*/, $_);
- $working[1] =~ /.*(gcc|clang)\sversion\s([\S]+)\s.*/;
- @$compiler = ($1,$2);
- last;
+ my $compiler_version;
+ my $compilers = [];
+ # NOTE: see %program_values for regex used for different gcc syntax
+ if (my $program = check_program($compiler)){
+ (my $name,$compiler_version) = ProgramData::full($compiler,$program);
+ }
+ if ($extra > 1){
+ # glob /usr/bin,/usr/local/bin for ccs, strip out all non numeric values
+ if (my @temp = globber("/usr/{local/,}bin/${compiler}{-,}[0-9]*")){
+ # usually: gcc-11, sometimes: gcc-11.2.0, gcc-2.8, gcc48 [FreeBSD]
+ foreach (@temp){
+ if (/\/${compiler}-?(\d+\.\d+|\d+)(\.\d+)?/){
+ # freebsd uses /usr/local/bin/gcc48, gcc34 for old gccs. Why?
+ my $working = ($bsd_type && $1 >= 30) ? $1/10 : $1;
+ if (!$compiler_version || $compiler_version !~ /^$working\b/){
+ push(@$compilers, $working);
+ }
}
}
- }
- # OpenBSD doesn't show compiler data in sysctl or dboot but it's going to
- # be Clang until way into the future, and it will be the installed version.
- if (!@$compiler){
- if (my $path = main::check_program('clang')){
- $compiler->[0] = 'clang';
- $compiler->[1] = main::program_version($path,'clang',3,'--version');
- }
- }
- }
- main::log_data('dump','@$compiler',$compiler) if $b_log;
- eval $end if $b_log;
-}
-sub version_proc {
- eval $start if $b_log;
- my ($compiler,$file) = @_;
- my ($version);
- my @data = main::reader($file);
- my $result = $data[0] if @data;
- if ($result){
- if ($fake{'compiler'}){
- # $result = $result =~ /\*(gcc|clang)\*eval\*/;
- # $result='Linux version 5.4.0-rc1 (sourav@archlinux-pc) (clang version 9.0.0 (tags/RELEASE_900/final)) #1 SMP PREEMPT Sun Oct 6 18:02:41 IST 2019';
- # $result='Linux version 5.8.3-fw1 (fst@x86_64.frugalware.org) ( OpenMandriva 11.0.0-0.20200819.1 clang version 11.0.0 (/builddir/build/BUILD/llvm-project-release-11.x/clang 2a0076812cf106fcc34376d9d967dc5f2847693a), LLD 11.0.0)';
- # $result='Linux version 5.8.0-18-generic (buildd@lgw01-amd64-057) (gcc (Ubuntu 10.2.0-5ubuntu2) 10.2.0, GNU ld (GNU Binutils for Ubuntu) 2.35) #19-Ubuntu SMP Wed Aug 26 15:26:32 UTC 2020';
- # $result='Linux version 5.8.9-fw1 (fst@x86_64.frugalware.org) (gcc (Frugalware Linux) 9.2.1 20200215, GNU ld (GNU Binutils) 2.35) #1 SMP PREEMPT Tue Sep 15 16:38:57 CEST 2020';
- # $result='Linux version 5.8.0-2-amd64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.0-9) 10.2.0, GNU ld (GNU Binutils for Debian) 2.35) #1 SMP Debian 5.8.10-1 (2020-09-19)';
- # $result='Linux version 5.9.0-5-amd64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-1) 10.2.1 20201207, GNU ld (GNU Binutils for Debian) 2.35.1) #1 SMP Debian 5.9.15-1 (2020-12-17)';
- # $result='Linux version 2.6.1 (GNU 0.9 GNU-Mach 1.8+git20201007-486/Hurd-0.9 i686-AT386)';
- # $result='NetBSD version 9.1 (netbsd@localhost) (gcc version 7.5.0) NetBSD 9.1 (GENERIC) #0: Sun Oct 18 19:24:30 UTC 2020';
- }
- if ($result =~ /(gcc|clang).*version\s([^\s\)]+)/){
- $version = $2;
- $version ||= 'N/A';
- @$compiler = ($1,$version);
- }
- elsif ($result =~ /\((gcc|clang)[^\(]*\([^\)]+\)\s+([0-9\.]+)(\s[^.]*)?,\s*/){
- $version = $2;
- $version ||= 'N/A';
- @$compiler = ($1,$version);
+ @$compilers = sort {$a <=> $b} @$compilers if @$compilers;
}
}
- main::log_data('dump','@$compiler',$compiler) if $b_log;
+ unshift(@$compilers, $compiler_version) if $compiler_version;
+ log_data('dump','@$compilers',$compilers) if $b_log;
+ print "$compiler\n", Data::Dumper::Dumper $compilers if $dbg[62];
eval $end if $b_log;
-}
+ return $compilers;
}
sub set_dboot_data {
@@ -26327,14 +29182,14 @@ sub set_dboot_data {
$file = $system_files{'dmesg-boot'};
}
else {
- # $file = "$fake_data_dir/dmesg-boot/bsd-disks-diabolus.txt";
- # $file = "$fake_data_dir/dmesg-boot/freebsd-disks-solestar.txt";
- # $file = "$fake_data_dir/dmesg-boot/freebsd-enceladus-1.txt";
+ # $file = "$fake_data_dir/bsd/dmesg-boot/bsd-disks-diabolus.txt";
+ # $file = "$fake_data_dir/bsd/dmesg-boot/freebsd-disks-solestar.txt";
+ # $file = "$fake_data_dir/bsd/dmesg-boot/freebsd-enceladus-1.txt";
## matches: toshiba: openbsd-5.6-sysctl-2.txt
- # $file = "$fake_data_dir/dmesg-boot/openbsd-5.6-dmesg.boot-1.txt";
+ # $file = "$fake_data_dir/bsd/dmesg-boot/openbsd-5.6-dmesg.boot-1.txt";
## matches: compaq: openbsd-5.6-sysctl-1.txt"
- # $file = "$fake_data_dir/dmesg-boot/openbsd-dmesg.boot-1.txt";
- $file = "$fake_data_dir/dmesg-boot/openbsd-6.8-battery-sensors-1.txt";
+ # $file = "$fake_data_dir/bsd/dmesg-boot/openbsd-dmesg.boot-1.txt";
+ # $file = "$fake_data_dir/bsd/dmesg-boot/openbsd-6.8-battery-sensors-1.txt";
}
if ($file){
return if ! -r $file;
@@ -26497,260 +29352,176 @@ sub set_dboot_data {
eval $end if $b_log;
}
-## DesktopEnvironment
+## DesktopData
# returns array:
-# 0 - desktop name
-# 1 - version
-# 2 - toolkit
-# 3 - toolkit version
-# 4 - info extra desktop data
-# 5 - wm
-# 6 - wm version
+# 0: desktop name
+# 1: version
+# 2: toolkit
+# 3: toolkit version
+# 4: de/wm components: panels, docks, menus, etc
+# 5: wm
+# 6: wm version
+# 7: tools: screensavers/lockers: running
+# 8: tools: screensavers/lockers: all not running, installed
+# 9: de advanced data type [eg. kde frameworks]
+# 10: de advanced data version
{
-package DesktopEnvironment;
-my ($b_gtk,$b_qt,$b_xprop,$desktop_session,$gdmsession,$kde_session_version,
-$xdg_desktop,@data,@xprop);
+package DesktopData;
+my ($b_dbg_de,$desktop_session,$gdmsession,$kde_full_session,
+$kde_session_version,$tk_test,$xdg_desktop,@data,%xprop);
my $desktop = [];
+
sub get {
eval $start if $b_log;
- set_desktop_values();
- main::set_ps_gui() if !$loaded{'ps-gui'};
- get_kde_trinity_data();
+ $b_dbg_de = 1 if $dbg[63] || $b_log;
+ PsData::set_de_wm() if !$loaded{'ps-gui'};
+ set_env_data();
+ # the order of these tests matters, go from most to least common
+ de_kde_tde_data();
+ de_env_data() if !@$desktop;
if (!@$desktop){
- get_env_de_data();
- }
- if (!@$desktop){
- get_env_xprop_gnome_based_data();
+ # NOTE: Always add to set_prop the search term if you add an item!!
+ set_xprop() if !$loaded{'xprop'};
+ de_gnome_based_data();
+ }
+ de_xfce_data() if !@$desktop;
+ de_enlightenment_based_data() if !@$desktop;
+ de_misc_data() if !@$desktop;
+ # last try, get it from ps data
+ de_ps_data() if !@$desktop;
+ if ($extra > 2 && @$desktop){
+ components_data(); # bars, docks, menu, panels, trays etc
+ tools_data(); # screensavers, lockers
}
- if (!@$desktop && $b_xprop){
- get_env_xprop_non_gnome_based_data();
+ if ($b_display && !$force{'display'} && $extra > 1){
+ wm_data();
+ }
+ # we want tk, but no previous methods got it
+ if ($extra > 1 && !$desktop->[3] && $tk_test){
+ if ($tk_test eq 'gtk'){
+ tk_gtk_data();}
+ elsif ($tk_test eq 'qt'){
+ tk_qt_data();}
+ else {
+ tk_misc_data();}
}
- if (!@$desktop){
- get_ps_de_data();
+ # try to avoid repeat version calls for wm/compostors
+ if ($show{'graphic'} && @$desktop){
+ $comps{lc($desktop->[0])} = [$desktop->[0],$desktop->[1]] if $desktop->[0];
+ $comps{lc($desktop->[5])} = [$desktop->[5],$desktop->[6]] if $desktop->[5];
}
- if ($extra > 2 && @$desktop){
- set_info_data();
+ if ($b_log){
+ main::log_data('dump','@$desktop', $desktop);
+ main::log_data('dump','%comps', \%comps);
}
- if ($b_display && !$force{'display'} && $extra > 1){
- get_wm();
+ if ($dbg[59]){
+ print '$desktop: ', Data::Dumper::Dumper $desktop;
+ print '%comps: ', Data::Dumper::Dumper \%comps;
}
- set_gtk_data() if $b_gtk && $extra > 1;
- set_qt_data() if $b_qt && $extra > 1;
- main::log_data('dump','@$desktop', $desktop) if $b_log;
- # ($b_xprop,$kde_session_version,$xdg_desktop,@data,@xprop) = ();
eval $end if $b_log;
return $desktop;
}
-sub set_desktop_values {
- # NOTE $XDG_CURRENT_DESKTOP envvar is not reliable, but it shows certain desktops better.
- # most desktops are not using it as of 2014-01-13 (KDE, UNITY, LXDE. Not Gnome)
- $desktop_session = ($ENV{'DESKTOP_SESSION'}) ? prep_desktop_value($ENV{'DESKTOP_SESSION'}) : '';
- $xdg_desktop = ($ENV{'XDG_CURRENT_DESKTOP'}) ? prep_desktop_value($ENV{'XDG_CURRENT_DESKTOP'}) : '';
- $kde_session_version = ($ENV{'KDE_SESSION_VERSION'}) ? $ENV{'KDE_SESSION_VERSION'} : '';
- # for fallback to fallback protections re false gnome id
- $gdmsession = ($ENV{'GDMSESSION'}) ? prep_desktop_value($ENV{'GDMSESSION'}) : '';
-}
-# note: an ubuntu regresssion replaces or adds 'ubuntu' string to
-# real value. Since ubuntu is the only distro I know that does this,
-# will add more distro type filters as/if we come across them
-sub prep_desktop_value {
- $_[0] = lc(main::trimmer($_[0]));
- $_[0] =~ s/\b(arch|debian|fedora|manjaro|mint|opensuse|ubuntu):?\s*//;
- return $_[0];
-}
-sub get_kde_trinity_data {
+
+## DE SPECIFIC IDS ##
+
+# ENLIGHTENMENT/MOKSHA #
+sub de_enlightenment_based_data {
eval $start if $b_log;
- my ($kded,$kded_name,$program,@version_data,@version_data2);
- my $kde_full_session = ($ENV{'KDE_FULL_SESSION'}) ? $ENV{'KDE_FULL_SESSION'} : '';
- # we can't rely on 3 using kded3, it could be kded
- if ($kde_full_session && ($program = main::check_program('kded' . $kde_full_session))){
- $kded = $program;
- $kded_name = 'kded' . $kde_full_session;
- }
- elsif ($program = main::check_program('kded')){
- $kded = $program;
- $kded_name = 'kded';
- }
- # note: if TDM is used to start kde, can pass ps tde test
- if ($desktop_session eq 'trinity' || $xdg_desktop eq 'trinity' ||
- (!$desktop_session && !$xdg_desktop && (grep {/^tde/} @ps_gui))){
- $desktop->[0] = 'Trinity';
- if ($program = main::check_program('kdesktop')){
- @version_data = main::grabber("$program --version 2>/dev/null");
- $desktop->[1] = main::awk(\@version_data,'^TDE:',2,'\s+') if @version_data;
- }
- if ($extra > 1 && @version_data){
- $desktop->[2] = 'Qt';
- $desktop->[3] = main::awk(\@version_data,'^Qt:',2,'\s+') if @version_data;
- }
- }
- # works on 4, assume 5 will id the same, why not, no need to update in future
- # KDE_SESSION_VERSION is the integer version of the desktop
- # NOTE: as of plasma 5, the tool: about-distro MAY be available, that will show
- # actual desktop data, so once that's in debian/ubuntu, if it gets in, add that test
- elsif ($desktop_session eq 'kde-plasma' || $xdg_desktop eq 'kde' ||
- $kde_session_version){
- if ($kde_session_version && $kde_session_version <= 4){
- @data = ($kded_name) ? main::program_values($kded_name) : ();
- if (@data){
- $desktop->[0] = $data[3];
- $desktop->[1] = main::program_version($kded,$data[0],$data[1],$data[2],$data[5],$data[6]);
- # kded exists, so we can now get the qt data string as well
- if ($desktop->[1] && $kded){
- @version_data = main::grabber("$kded --version 2>/dev/null");
- }
- }
- $desktop->[0] = 'KDE' if !$desktop->[0];
- }
- else {
- # NOTE: this command string is almost certain to change, and break, with next
- # major plasma desktop, ie, 6.
- # qdbus org.kde.plasmashell /MainApplication org.qtproject.Qt.QCoreApplication.applicationVersion
- # Qt: 5.4.2
- # KDE Frameworks: 5.11.0
- # kf5-config: 1.0
- # for QT, and Frameworks if we use it
- if (!@version_data && ($program = main::check_program("kf$kde_session_version-config"))){
- @version_data = main::grabber("$program --version 2>/dev/null");
- }
- if (!@version_data && ($program = main::check_program("kf-config"))){
- @version_data = main::grabber("$program --version 2>/dev/null");
- }
- # hope we don't use this fallback, not the same version as kde always
- if (!@version_data && $kded){
- @version_data = main::grabber("$kded --version 2>/dev/null");
- }
- if ($program = main::check_program("plasmashell")){
- @version_data2 = main::grabber("$program --version 2>/dev/null");
- $desktop->[1] = main::awk(\@version_data2,'^plasmashell',-1,'\s+');
- }
- $desktop->[0] = 'KDE Plasma';
- }
- if (!$desktop->[1]){
- $desktop->[1] = ($kde_session_version) ? $kde_session_version : main::message('unknown-desktop-version');
+ # print 'de evn xprop: ', Data::Dumper::Dumper \%xprop;
+ my ($v_src,$program);
+ # earlier moksha fully ID as enlightenment
+ if ($xdg_desktop eq 'moksha' || $gdmsession eq 'moksha' ||
+ ($xprop{'moksha'} &&
+ (main::check_program('enlightenment') || main::check_program('moksha')))){
+ # ENLIGHTENMENT_VERSION(STRING) = "Moksha 0.2.0.15989"
+ # note: toolkit: EFL
+ # later releases have -version
+ if ($v_src = main::check_program('moksha')){
+ ($desktop->[0],$desktop->[1]) = ProgramData::full('moksha',$v_src);
}
- # print Data::Dumper::Dumper \@version_data;
- if ($extra > 1){
- if (@version_data){
- $desktop->[3] = main::awk(\@version_data,'^Qt:', 2,'\s+');
- }
- # qmake can have variants, qt4-qmake, qt5-qmake, also qt5-default but not tested
- if (!$desktop->[3] && main::check_program("qmake")){
- # note: this program has issues, it may appear to be in /usr/bin, but it
- # often fails to execute, so the below will have null output, but use as a
- # fall back test anyway.
- ($desktop->[2],$desktop->[3]) = main::program_data('qmake');
- }
- $desktop->[2] ||= 'Qt';
+ # Earlier: no -v or --version but version is in xprop -root
+ if (!$desktop->[1] && $xprop{'moksha'}){
+ $v_src = 'xprop';
+ $desktop->[1] = main::awk($xprop{'moksha'}->{'lines'},
+ '(enlightenment|moksha)_version',2,'\s+=\s+');
+ $desktop->[1] =~ s/"?(moksha|enlightenment)\s([^"]+)"?/$2/ if $desktop->[1];
}
+ $desktop->[0] ||= 'Moksha';
}
- # KDE_FULL_SESSION property is only available since KDE 3.5.5.
- elsif ($kde_full_session eq 'true'){
- @version_data = ($kded) ? main::grabber("$kded --version 2>/dev/null") : ();
- $desktop->[0] = 'KDE';
- $desktop->[1] = main::awk(\@version_data,'^KDE:',2,'\s+') if @version_data;
- if (!$desktop->[1]){
- $desktop->[1] = '3.5';
- }
- if ($extra > 1 && @version_data){
- $desktop->[2] = 'Qt';
- $desktop->[3] = main::awk(\@version_data,'^Qt:',2,'\s+') if @version_data;
+ elsif ($xdg_desktop eq 'enlightenment' || $gdmsession eq 'enlightenment' ||
+ ($xprop{'enlightenment'} && main::check_program('enlightenment'))){
+ # no -v or --version but version is in xprop -root
+ # ENLIGHTENMENT_VERSION(STRING) = "Enlightenment 0.16.999.49898"
+ $desktop->[0] = 'Enlightenment';
+ if ($xprop{'enlightenment'}){
+ $v_src = 'xprop';
+ $desktop->[1] = main::awk($xprop{'enlightenment'}->{'lines'},
+ '(enlightenment|moksha)_version',2,'\s+=\s+');
+ $desktop->[1] =~ s/"?(moksha|enlightenment)\s([^"]+)"?/$2/ if $desktop->[1];
}
}
- eval $end if $b_log;
-}
-sub get_env_de_data {
- eval $start if $b_log;
- my ($program,@version_data);
- if (!$desktop->[0]){
- # 0: 1/0; 1: env var search; 2: data; 3: gtk tk; 4: qt tk; 5: ps_gui search
- my @desktops =(
- [1,'unity','unity',0,0],
- [0,'budgie','budgie-desktop',0,0],
- # debian package: lxde-core.
- # NOTE: some distros fail to set XDG data for root
- [1,'lxde','lxpanel',0,0,',^lxsession$'],
- [1,'razor','razor-session',0,1,'^razor-session$'],
- # BAD: lxqt-about opens dialogue, sigh.
- # Checked, lxqt-panel does show same version as lxqt-about
- [1,'lxqt','lxqt-panel',0,1,'^lxqt-session$'],
- [0,'^(razor|lxqt)$','lxqt-variant',0,1,'^(razor-session|lxqt-session)$'],
- # note, X-Cinnamon value strikes me as highly likely to change, so just
- # search for the last part
- [0,'cinnamon','cinnamon',1,0],
- # these so far have no cli version data
- [1,'deepin','deepin',0,1], # version comes from file read
- [1,'leftwm','leftwm',0,0],
- [1,'pantheon','pantheon',0,0],
- [1,'penrose','penrose',0,0],# unknown, just guessing
- [1,'lumina','lumina-desktop',0,1],
- [0,'manokwari','manokwari',1,0],
- [1,'ukui','ukui-session',0,1],
- );
- foreach my $item (@desktops){
- # Check if in xdg_desktop OR desktop_session OR if in $item->[6] and in ps_gui
- if ((($item->[0] && ($xdg_desktop eq $item->[1] || $desktop_session eq $item->[1])) ||
- (!$item->[0] && ($xdg_desktop =~ /$item->[1]/ || $desktop_session =~ /$item->[1]/))) ||
- ($item->[5] && @ps_gui && (grep {/$item->[5]/} @ps_gui))){
- ($desktop->[0],$desktop->[1]) = main::program_data($item->[2]);
- $b_gtk = $item->[3];
- $b_qt = $item->[4];
- last;
- }
+ if ($desktop->[0]){
+ if ($extra > 1 && ($program = main::check_program('efl-version'))){
+ ($desktop->[2],$desktop->[3]) = ProgramData::full('efl-version',$program);
}
+ $desktop->[2] ||= 'EFL' if $extra > 1;
+ main::feature_debugger('de ' . $desktop->[0] . ' v_src,program,desktop',
+ [$v_src,$program,$desktop],$dbg[63]) if $b_dbg_de;
}
eval $end if $b_log;
}
-sub get_env_xprop_gnome_based_data {
+
+# GNOME/CINNAMON/MATE #
+sub de_gnome_based_data {
eval $start if $b_log;
- my ($program,$value,@version_data);
- # NOTE: Always add to set_prop the search term if you add an item!!
- set_xprop();
# add more as discovered
return if $xdg_desktop eq 'xfce' || $gdmsession eq 'xfce';
+ my ($program,$value,@version_data);
# note that cinnamon split from gnome, and and can now be id'ed via xprop,
# but it will still trigger the next gnome true case, so this needs to go
# before gnome test eventually this needs to be better organized so all the
# xprop tests are in the same section, but this is good enough for now.
# NOTE: was checking for 'muffin' but that's not part of cinnamon
if ($xdg_desktop eq 'cinnamon' || $gdmsession eq 'cinnamon' ||
- (main::check_program('muffin') || main::check_program('cinnamon-session')) &&
- ($b_xprop && main::awk(\@xprop,'_muffin'))){
- ($desktop->[0],$desktop->[1]) = main::program_data('cinnamon','cinnamon',0);
- $b_gtk = 1;
+ (($xprop{'muffin'} || $xprop{'mutter'}) &&
+ (main::check_program('muffin') || main::check_program('cinnamon-session')))){
+ ($desktop->[0],$desktop->[1]) = ProgramData::full('cinnamon','cinnamon',0);
+ $tk_test = 'gtk';
$desktop->[0] ||= 'Cinnamon';
+ main::feature_debugger('gnome test 1 $desktop',$desktop,$dbg[63]) if $b_dbg_de;
}
- elsif ($xdg_desktop eq 'mate' || $gdmsession eq 'mate' ||
- ($b_xprop && main::awk(\@xprop,'_marco'))){
+ elsif ($xdg_desktop eq 'mate' || $gdmsession eq 'mate' || $xprop{'marco'}){
# NOTE: mate-about and mate-sesssion vary which has the higher number, neither
# consistently corresponds to the actual MATE version, so check both.
my %versions = ('mate-about' => '','mate-session' => '');
foreach my $key (keys %versions){
if ($program = main::check_program($key)){
- @data = main::program_data($key,$program,0);
- $desktop->[0] = $data[0];
- $versions{$key} = $data[1];
+ ($desktop->[0],$versions{$key}) = ProgramData::full($key,$program,0);
}
}
# no consistent rule about which version is higher, so just compare them and take highest
$desktop->[1] = main::compare_versions($versions{'mate-about'},$versions{'mate-session'});
- # $b_gtk = 1;
+ # $tk_test = 'gtk';
$desktop->[0] ||= 'MATE';
+ main::feature_debugger('gnome test 2 $desktop',$desktop,$dbg[63]) if $b_dbg_de;
}
# See sub for logic and comments
elsif (check_gnome()){
if (main::check_program('gnome-about')){
- ($desktop->[0],$desktop->[1]) = main::program_data('gnome-about');
+ ($desktop->[0],$desktop->[1]) = ProgramData::full('gnome-about');
}
elsif (main::check_program('gnome-shell')){
- ($desktop->[0],$desktop->[1]) = main::program_data('gnome','gnome-shell');
+ ($desktop->[0],$desktop->[1]) = ProgramData::full('gnome','gnome-shell');
}
- $b_gtk = 1;
+ $tk_test = 'gtk';
$desktop->[0] ||= 'GNOME';
+ main::feature_debugger('gnome test 3 $desktop $desktop',$desktop,
+ $dbg[63]) if $b_dbg_de;
}
eval $end if $b_log;
}
-# note, GNOME_DESKTOP_SESSION_ID is deprecated so we'll see how that works out
+
+# Note, GNOME_DESKTOP_SESSION_ID is deprecated so we'll see how that works out
# https://bugzilla.gnome.org/show_bug.cgi?id=542880.
# NOTE: manjaro is leaving XDG data null, which forces the manual check for gnome, sigh...
# some gnome programs can trigger a false xprop gnome ID
@@ -26763,7 +29534,7 @@ sub check_gnome {
$b_gnome = 1;
}
# should work as long as string contains gnome, eg: peppermint:gnome
- # filtered explicitly in set_desktop_values
+ # filtered explicitly in set_env_data
elsif ($xdg_desktop && $xdg_desktop !~ /gnome/){
$detection = 'xdg_current_desktop';
}
@@ -26786,296 +29557,499 @@ sub check_gnome {
$b_gnome = 1;
}
# maybe use ^_gnome_session instead? try it for a while
- elsif ($b_xprop && main::check_program('gnome-shell') && main::awk(\@xprop,'^_gnome_session')){
+ elsif ($xprop{'gnome_session'} && main::check_program('gnome-shell')){
$detection = 'xprop-root';
$b_gnome = 1;
}
+ if ($b_dbg_de && $b_gnome){
+ main::feature_debugger('gnome $detection','detect-type: ' . $detection,$dbg[63]);
+ }
main::log_data('data','$detection:$b_gnome>>' . $detection . ":$b_gnome") if $b_log;
eval $end if $b_log;
return $b_gnome;
}
-sub get_env_xprop_non_gnome_based_data {
+
+# KDE/TRINITY #
+sub de_kde_tde_data {
+ eval $start if $b_log;
+ my ($kded,$kded_name,$program,$tk_src,$v_data,$v_src);
+ # we can't rely on 3 using kded3, it could be kded
+ if ($kde_session_version && ($program = main::check_program('kded' . $kde_session_version))){
+ $kded = $program;
+ $kded_name = 'kded' . $kde_session_version;
+ }
+ elsif ($program = main::check_program('kded')){
+ $kded = $program;
+ $kded_name = 'kded';
+ }
+ # note: if TDM is used to start kde, can pass ps tde test
+ if ($desktop_session eq 'trinity' || $xdg_desktop eq 'trinity' ||
+ (!$desktop_session && !$xdg_desktop && @{$ps_data{'de-ps-detect'}} &&
+ (grep {/^tde/} @{$ps_data{'de-ps-detect'}}))){
+ if ($program = main::check_program('kdesktop')){
+ ($desktop->[0],$desktop->[1],$v_data) = ProgramData::full('kdesktop-trinity',$program,0,'raw');
+ }
+ if ($extra > 1 && $v_data && @$v_data){
+ ($desktop->[2],$desktop->[3]) = item_from_version($v_data,['^Qt:',2,'Qt']);
+ }
+ $desktop->[0] ||= 'Trinity';
+ $desktop->[2] ||= 'Qt' if $extra > 1;
+ main::feature_debugger('kde trinity $program,$v_data,$desktop',
+ [$program,$v_data,$desktop],$dbg[63]) if $b_dbg_de;
+ }
+ # works on 4, assume 5 will id the same, why not, no need to update in future
+ # KDE_SESSION_VERSION is the integer version of the desktop
+ # NOTE: as of plasma 5, the tool: about-distro MAY be available, that will show
+ # actual desktop data, so once that's in debian/ubuntu, if it gets in, add that test
+ elsif ($desktop_session eq 'kde-plasma' || $desktop_session eq 'plasma' ||
+ $xdg_desktop eq 'kde' || $kde_session_version){
+ # KDE <= 4
+ if ($kde_session_version && $kde_session_version <= 4){
+ if ($program = main::check_program($kded_name)){
+ ($desktop->[0],$desktop->[1],$v_data) = ProgramData::full($kded_name,$program,0,'raw');
+ if ($extra > 1 && $v_data && @$v_data){
+ ($desktop->[2],$desktop->[3]) = item_from_version($v_data,['^Qt:',2,'Qt']);
+ }
+ }
+ $desktop->[0] ||= 'KDE';
+ $desktop->[2] ||= 'Qt' if $extra > 1;
+ main::feature_debugger('kde 4 program,v_data,$desktop',
+ [$program,$v_data,$desktop],$dbg[63]) if $b_dbg_de;
+ }
+ # KDE >= 5
+ else {
+ # no qt data, just the kde version as of 5, not in kde4
+ my $fw_src;
+ if (!$desktop->[0] &&
+ ($v_src = $program = main::check_program("plasmashell"))){
+ ($desktop->[0],$desktop->[1]) = ProgramData::full('plasmashell',$program);
+ }
+ # kwin through version 4 showed full kde/qt data, 5 only shows plasma version
+ if (!$desktop->[0] &&
+ ($v_src = $program = main::check_program("kwin"))){
+ ($desktop->[0],$desktop->[1]) = ProgramData::full('kwin-kde',$program);
+ }
+ $desktop->[0] = 'KDE Plasma';
+ if (!$desktop->[1]){
+ $desktop->[1] = ($kde_session_version) ?
+ $kde_session_version : main::message('unknown-desktop-version');
+ }
+ # NOTE: this command string is almost certain to change, and break, with next
+ # major plasma desktop, ie, 6.
+ # qdbus org.kde.plasmashell /MainApplication org.qtproject.Qt.QCoreApplication.applicationVersion
+ # kde 4: kwin,kded4 (KDE:); kde5: kf5-config (KDE Frameworks:)
+ # Qt: 5.4.2
+ # KDE Frameworks: 5.11.0
+ # kf5-config: 1.0
+ # for QT, and Frameworks if we use it. Frameworks v is NOT same as KDE v.
+ if ($extra > 1){
+ if ($tk_src = $program = main::check_program("kf$kde_session_version-config")){
+ ($desktop->[2],$desktop->[3],$v_data) = ProgramData::full(
+ "kf-config-qt",$program,0,'raw');
+ }
+ if (!$desktop->[3] && (!$v_data || !@$v_data) &&
+ ($tk_src = $program = main::check_program("kf-config"))){
+ ($desktop->[2],$desktop->[3],$v_data) = ProgramData::full(
+ "kf-config-qt",$program,0,'raw');
+ }
+ $desktop->[2] ||= 'Qt';
+ if ($b_admin){
+ if ($v_data && @$v_data){
+ $fw_src = $tk_src;
+ ($desktop->[9],$desktop->[10]) = item_from_version($v_data,
+ ['^KDE Frameworks:',3,'frameworks']);
+ }
+ # This has Frameworks version as of kde 5
+ if ($kded && !$desktop->[10]){
+ $fw_src = $kded;
+ ($desktop->[9],$desktop->[10]) = ProgramData::full($kded_name . '-frameworks',$kded);
+ }
+ }
+ }
+ main::feature_debugger('kde >= 5 v_src,tk_src,fw_src,v_data,$desktop',
+ [$v_src,$tk_src,$fw_src,$v_data,$desktop],$dbg[63]) if $b_dbg_de;
+ }
+ }
+ # KDE_FULL_SESSION property is only available since KDE 3.5.5. This will only
+ # trigger for KDE 3.5, since above conditions catch >= 4
+ elsif ($kde_full_session eq 'true'){
+ # this is going to be bad data since new kdedX is different version from kde
+ ($desktop->[0],$desktop->[1],$v_data) = ProgramData::full($kded_name,$kded,0,'raw');
+ $desktop->[1] ||= '3.5';
+ if ($extra > 1 && $v_data && @$v_data){
+ ($desktop->[2],$desktop->[3]) = item_from_version($v_data,['^Qt:',2,'Qt']);
+
+ }
+ $desktop->[2] ||= 'Qt' if $extra > 1;
+ main::feature_debugger('kde 3.5 de+qt $desktop',$desktop,$dbg[63]) if $b_dbg_de;
+ }
+ eval $end if $b_log;
+}
+
+# XFCE #
+# Not strictly dependent on xprop data, which is not necessarily always present
+sub de_xfce_data {
eval $start if $b_log;
- my ($program,@version_data,$version);
- # print join("\n", @xprop), "\n";
+ my ($program,$v_data);
+ # print 'de-xfce-env: ', Data::Dumper::Dumper \%xprop;
# String: "This is xfdesktop version 4.2.12"
# alternate: xfce4-about --version > xfce4-about 4.10.0 (Xfce 4.10)
- # note: some distros/wm (e.g. bunsen) set xdg to xfce to solve some other
- # issues so don't test for that. $xdg_desktop eq 'xfce'
+ # note: some distros/wm (e.g. bunsen) set $xdg_desktop to xfce to solve some
+ # other issues so but are OpenBox. Not inxi issue.
+ # $xdg_desktop can be /usr/bin/startxfce4
+ # print "xdg_d: $xdg_desktop gdms: $gdmsession\n";
if ($xdg_desktop eq 'xfce' || $gdmsession eq 'xfce' ||
- (main::check_program('xfdesktop')) && main::awk(\@xprop,'^(xfdesktop|xfce)')){
- # this is a very expensive test that doesn't usually result in a find
- # talk to xfce to see what id they will be using for xfce 5
-# if (main::awk(\@xprop, 'xfce4')){
-# $version = '4';
-# }
- if (main::awk(\@xprop, 'xfce5')){
- $version = '5';
- }
- else {
- $version = '4';
- }
- @data = main::program_values('xfdesktop');
- $desktop->[0] = $data[3];
- # xfdesktop --version out of x fails to get display, so no data
- @version_data = main::grabber('xfdesktop --version 2>/dev/null');
- # out of x, this error goes to stderr, so it's an empty result
- $desktop->[1] = main::awk(\@version_data,$data[0],$data[1],'\s+');
- #$desktop->[1] = main::program_version('xfdesktop',$data[0],$data[1],$data[2],$data[5],$data[6]);
+ (($xprop{'xfdesktop'} || $xprop{'xfce'}) && main::check_program('xfdesktop'))){
+ ($desktop->[0],$desktop->[1],$v_data) = ProgramData::full('xfdesktop','',0,'raw');
if (!$desktop->[1]){
- @data = main::program_values("xfce${version}-panel");
- # print Data::Dumper::Dumper \@data;
+ my $version = '4'; # just assume it's 4, we tried
+ if ($program = main::check_program('xfce4-panel')){
+ $version = '4';
+ }
+ # talk to xfce to see what id they will be using for xfce 5
+ elsif ($program = main::check_program('xfce5-panel')){
+ $version = '5';
+ }
+ # they might get rid of number, we'll see
+ elsif ($program = main::check_program('xfce-panel')){
+ $version = '';
+ }
+ # xfce4-panel does not show built with gtk [version]
# this returns an error message to stdout in x, which breaks the version
# xfce4-panel --version out of x fails to get display, so no data
- $desktop->[1] = main::program_version("xfce${version}-panel",$data[0],$data[1],$data[2],$data[5],$data[6]);
# out of x this kicks out an error: xfce4-panel: Cannot open display
- $desktop->[1] = '' if $desktop->[1] !~ /[0-9]\./;
+ ($desktop->[0],$desktop->[1]) = ProgramData::full("xfce${version}-panel",$program);
}
$desktop->[0] ||= 'Xfce';
$desktop->[1] ||= ''; # xfce isn't going to be 4 forever
- if ($extra > 1){
- @data = main::program_values('xfdesktop-toolkit');
- #$desktop->[3] = main::program_version('xfdesktop',$data[0],$data[1],$data[2],$data[5],$data[6]);
- $desktop->[3] = main::awk(\@version_data,$data[0],$data[1],'\s+');
- $desktop->[2] = $data[3];
+ if ($extra > 1 && $v_data && @$v_data){
+ ($desktop->[2],$desktop->[3]) = item_from_version($v_data,['^Built with GTK',4,'Gtk']);
}
+ main::feature_debugger('xfce $program,$desktop',[$program,$desktop],
+ $dbg[63]) if $b_dbg_de;
}
- elsif ($xdg_desktop eq 'moksha' || $gdmsession eq 'moksha' ||
- (main::check_program('enlightenment') || main::check_program('moksha')) && main::awk(\@xprop,'moksha')){
- # no -v or --version but version is in xprop -root
- # ENLIGHTENMENT_VERSION(STRING) = "Moksha 0.2.0.15989"
- $desktop->[0] = 'Moksha';
- $desktop->[1] = main::awk(\@xprop,'(enlightenment|moksha)_version',2,'\s+=\s+');
- $desktop->[1] =~ s/"?(Moksha|Enlightenment)\s([^"]+)"?/$2/i if $desktop->[1];
- }
- elsif ($xdg_desktop eq 'enlightenment' || $gdmsession eq 'enlightenment' ||
- (main::check_program('enlightenment') && main::awk(\@xprop,'enlightenment'))){
- # no -v or --version but version is in xprop -root
- # ENLIGHTENMENT_VERSION(STRING) = "Enlightenment 0.16.999.49898"
- $desktop->[0] = 'Enlightenment';
- $desktop->[1] = main::awk(\@xprop,'(enlightenment|moksha)_version',2,'\s+=\s+');
- $desktop->[1] =~ s/"?(Moksha|Enlightenment)\s([^"]+)"?/$2/i if $desktop->[1];
- }
- # the sequence here matters, some desktops like icewm, razor, let you set different
- # wm, so we want to get the main controlling desktop first, then fall back to the wm
- # detections. get_ps_de_data() and get_wm() will handle alternate wm detections.
+ eval $end if $b_log;
+}
+
+## GENERAL DE TESTS ##
+sub de_env_data {
+ eval $start if $b_log;
if (!$desktop->[0]){
- # 0 check program; 1 xprop search; 2: data; 3 - optional: ps_gui search
+ my $v_data;
+ # 0: 0/1 regex/eq; 1: env var search; 2: PD full; 3: [PD version cmd];
+ # 4: tk; 5: ps search;
+ # 6: [toolkits data sourced from full version [search,position,print]]
my @desktops =(
- ['icewm','icewm','icewm'],
- # debian package: i3-wm
- ['i3','i3','i3'],
- ['mwm','^_motif','mwm'],
- # debian package name: wmaker
- ['WindowMaker','^_?windowmaker','wmaker'],
- ['wm2','^_wm2','wm2'],
- ['herbstluftwm','herbstluftwm','herbstluftwm'],
- ['fluxbox','blackbox_pid','fluxbox','^fluxbox$'],
- ['blackbox','blackbox_pid','blackbox'],
- ['openbox','openbox_pid','openbox'],
- ['amiwm','amiwm','amiwm'],
+ [1,'unity','unity','',''],
+ [0,'budgie','budgie-desktop','','gtk'],
+ # debian package: lxde-core.
+ # NOTE: some distros fail to set XDG data for root, ps may get it
+ [1,'lxde','lxpanel','','gtk-na',',^lxsession$'], # no gtk v data, not same as system
+ [1,'razor','razor-session','','qt','^razor-session$'],
+ # BAD: lxqt-about opens dialogue, sigh.
+ # Checked, lxqt-panel does show same version as lxqt-about/session
+ [1,'lxqt','lxqt-panel','','qt','^lxqt-session$',['Qt',2,'Qt']],
+ [0,'^(razor|lxqt)$','lxqt-variant','','qt','^(razor-session|lxqt-session)$'],
+ [1,'fvwm-crystal','fvwm-crystal','fvwm',''],
+ [1,'hyprland','hyprctl','',''],
+ [1,'blackbox','blackbox','',''],
+ # note, X-Cinnamon value strikes me as highly likely to change, so just
+ # search for the last part
+ [1,'nscde','nscde','',''],# has to go before cde
+ [0,'cde','cde','','motif'],
+ [0,'cinnamon','cinnamon','','gtk'],
+ # these so far have no cli version data
+ [1,'deepin','deepin','','qt'], # version comes from file read
+ [1,'draco','draco','','qt'],
+ [1,'leftwm','leftwm','',''],
+ [1,'mlvwm','mlvwm','',''],
+ [0,'^(motif\s?window|mwm)','mwm','','motif'],
+ [1,'pantheon','pantheon','','gtk'],
+ [1,'penrose','penrose','',''],# unknown, just guessing
+ [1,'lumina','lumina-desktop','','qt'],
+ [0,'manokwari','manokwari','','gtk'],
+ [1,'ukui','ukui-session','','qt'],
+ [0,'wmaker|windowmaker','windowmaker','wmaker',''],
);
foreach my $item (@desktops){
- if (main::check_program($item->[0]) && main::awk(\@xprop,$item->[1]) &&
- (!$item->[4] || (@ps_gui && (grep {/$item->[4]/} @ps_gui)))){
- ($desktop->[0],$desktop->[1]) = main::program_data($item->[2]);
+ # Check if in xdg_desktop OR desktop_session OR if in $item->[5] and in ps_gui
+ if ((($item->[0] &&
+ ($xdg_desktop eq $item->[1] || $desktop_session eq $item->[1])) ||
+ (!$item->[0] &&
+ ($xdg_desktop =~ /$item->[1]/ || $desktop_session =~ /$item->[1]/))) ||
+ ($item->[5] &&
+ @{$ps_data{'de-ps-detect'}} && (grep {/$item->[5]/} @{$ps_data{'de-ps-detect'}}))){
+ ($desktop->[0],$desktop->[1],$v_data) = ProgramData::full($item->[2],$item->[3],0,$item->[6]);
+ if ($extra > 1){
+ if ($item->[6] && $v_data && @$v_data){
+ ($desktop->[2],$desktop->[3]) = item_from_version($v_data,$item->[6]);
+ }
+ $tk_test = $item->[4] if !$desktop->[3];
+ }
+ main::feature_debugger('env de-wm',$desktop,$dbg[63]) if $b_dbg_de;
last;
}
}
}
- # need to check starts line because it's so short
eval $end if $b_log;
}
-sub get_ps_de_data {
+
+# These require data from xprop.
+sub de_misc_data {
eval $start if $b_log;
- my ($program,@version_data);
- main::set_ps_gui() if !$loaded{'ps-gui'};
- if (@ps_gui){
- # the sequence here matters, some desktops like icewm, razor, let you set different
- # wm, so we want to get the main controlling desktop first
- # icewm and any other that permits alternate wm to be used need to go first
- # in this list.
- # unverfied: 2bwm catwm mcwm penrose snapwm uwm wmfs wmfs2 wingo wmii2
- # xfdesktoo is fallback in case not in xprop
- my @wms = qw(icewm 2bwm 9wm aewm aewm\+\+ afterstep amiwm antiwm awesome
- blackbox bspwm calmwm catwm cde ctwm dwm echinus evilwm fluxbox fvwm
- hackedbox herbstluftwm instantwm i3 ion3 jbwm jwm larswm leftwm lwm
- matchbox-window-manager mcwm mini musca mvwm mwm nawm notion nscde
- openbox pekwm penrose qvwm ratpoison
- sawfish scrotwm snapwm spectrwm tinywm tvtwm twm uwm
- windowlab wmfs wmfs2 wingo wmii2 wmii wmx xmonad yeahwm);
- my $matches = join('|',@wms) . $wl_compositors;
- # note: use my $psg to avoid bizarre return from program_data to ps_gui write
- foreach my $psg (@ps_gui){
+ # print 'de evn xprop: ', Data::Dumper::Dumper \%xprop;
+ # the sequence here matters, some desktops like icewm, razor, let you set different
+ # wm, so we want to get the main controlling desktop first, then fall back to the wm
+ # detections. de_ps_data() and wm_data() will handle alternate wm detections.
+ if (%xprop){
+ # order matters! These are the primary xprop detected de/wm
+ my $program;
+ my @desktops = qw(icewm i3 mwm windowmaker wm2 herbstluftwm fluxbox blackbox
+ openbox amiwm);
+ foreach my $de (@desktops){
+ if ($xprop{$de} &&
+ (($program = main::check_program($xprop{$de}->{'name'})) ||
+ ($xprop{$de}->{'vname'} && ($program = main::check_program($xprop{$de}->{'vname'}))))){
+ ($desktop->[0],$desktop->[1]) = ProgramData::full($xprop{$de}->{'name'},$program);
+ main::feature_debugger('de misc $program,$desktop',
+ [$program,$desktop],$dbg[63]) if $b_dbg_de;
+ last;
+ }
+ }
+ }
+ # need to check starts line because it's so short
+ eval $end if $b_log;
+}
+
+sub de_ps_data {
+ eval $start if $b_log;
+ my ($v_data,@working);
+ # The sequence here matters, some desktops like icewm, razor, let you set different
+ # wm, so we want to get the main controlling desktop first
+ # icewm and any other that permits alternate wm to be used need to go first
+ push(@working,@{$ps_data{'wm-parent'}}) if @{$ps_data{'wm-parent'}};
+ push(@working,@{$ps_data{'wm-compositors'}}) if @{$ps_data{'wm-compositors'}};
+ push(@working,@{$ps_data{'wm-main'}}) if @{$ps_data{'wm-main'}};
+ if (@working){
+ # order matters, these have alternate search patterns from default name
+ # 0: check program; 1: ps_gui search; 2: PD full; 3: [PD version cmd]
+ my @wms =(
+ ['WindowMaker','(WindowMaker|wmaker)','wmaker',''],
+ ['cwm','(openbsd-)?cwm','cwm',''],
+ ['flwm','flwm(_topside)?','flwm',''],
+ ['fvwm-crystal','fvwm.*-crystal\S*','fvwm-crystal','fvwm'],
+ ['hyprland','[Hh]yprland','hyprctl',''],
+ ['xfdesktop','xfdesktop','xfdesktop','',['^Built with GTK',4,'Gtk']],
+ );
+ # note: use my $item to avoid bizarre return from program_data to ps_gui write
+ foreach my $item (@wms){
# no need to use check program with short list of ps_gui
- if ($psg =~ /^($matches)$/){
- my $item = $1;
- ($desktop->[0],$desktop->[1]) = main::program_data($item);
- if ($extra > 1 && $item eq 'xfdesktop'){
- ($desktop->[2],$desktop->[3]) = main::program_data('xfdesktop-toolkit',$item,1);
- }
+ # print "1: $item->[1]\n";
+ if (grep {/^$item->[1]$/i} @working){
+ # print "2: $item->[1]\n";
+ ($desktop->[0],$desktop->[1],$v_data) = ProgramData::full($item->[2],$item->[3],0,$item->[4]);
+ if ($extra > 1 && $item->[4] && $v_data && @$v_data){
+ ($desktop->[2],$desktop->[3]) = item_from_version($v_data,$item->[4]);
+ }
+ main::feature_debugger('ps de test 1 $desktop',
+ $desktop,$dbg[63]) if $b_dbg_de;
last;
}
}
if (!$desktop->[0]){
- # order matters, these have alternate search patterns from default name
- # 1 check program; 2 ps_gui search; 3 data; 4: trigger alternate values/version
- @wms =(
- ['WindowMaker','WindowMaker','wmaker',''],
- ['clfswm','.*(sh|c?lisp)?.*clfswm','clfswm',''],
- ['cwm','(openbsd-)?cwm','cwm',''],
- ['flwm','flwm','flwm',''],
- ['flwm','flwm_topside','flwm',''],
- ['fvwm-crystal','fvwm.*-crystal','fvwm-crystal','fvwm'],
- ['fvwm1','fvwm1','fvwm1',''],
- ['fvwm2','fvwm2','fvwm2',''],
- ['fvwm3','fvwm3','fvwm3',''],
- ['fvwm95','fvwm95','fvwm95',''],
- ['qtile','.*(python.*)?qtile','qtile',''],
- ['stumpwm','(sh|c?lisp)?.*stumpwm','stumpwm',''],
- );
- foreach my $item (@wms){
- # no need to use check program with short list of ps_gui
- if (grep {/^$item->[1]$/} @ps_gui){
- ($desktop->[0],$desktop->[1]) = main::program_data($item->[2],$item->[3]);
- if ($extra > 1 && $item->[0] eq 'xfdesktop'){
- ($desktop->[2],$desktop->[3]) = main::program_data('xfdesktop-toolkit',$item->[0],1);
- }
- last;
- }
- }
+ # we're relying on the stack order to get primary before secondary wm
+ my $de = shift(@working);
+ ($desktop->[0],$desktop->[1]) = ProgramData::full($de);
+ main::feature_debugger('ps de test 2 $desktop',
+ $desktop,$dbg[63]) if $b_dbg_de;
}
}
eval $end if $b_log;
}
+
+## TOOLKIT DATA ##
# NOTE: used to use a super slow method here, but gtk-launch returns
# the gtk version I believe
-sub set_gtk_data {
+sub tk_gtk_data {
eval $start if $b_log;
if (main::check_program('gtk-launch')){
- ($desktop->[2],$desktop->[3]) = main::program_data('gtk-launch');
+ ($desktop->[2],$desktop->[3]) = ProgramData::full('gtk-launch');
+ main::feature_debugger('gtk $desktop 2,3',
+ [$desktop->[2],$desktop->[3]],$dbg[63]) if $b_dbg_de;
}
eval $end if $b_log;
}
-sub set_qt_data {
+
+# This handles stray tooltips that won't get versions, yet anyway.
+sub tk_misc_data {
eval $start if $b_log;
- my ($program,@data,@version_data);
+ if ($tk_test eq 'gtk-na'){
+ $desktop->[2] = 'Gtk';
+ }
+ else {
+ $desktop->[2] = ucfirst($tk_test);
+ }
+ eval $end if $b_log;
+}
+
+# Note ideally most of these are handled by item_from_version, but these will
+# handle as fallback detections as those are updated, if possible.
+sub tk_qt_data {
+ eval $start if $b_log;
+ my $program;
my $kde_version = $kde_session_version;
- $program = '';
if (!$kde_version){
- if ($program = main::check_program("kded6")){$kde_version = 6;}
- elsif ($program = main::check_program("kded5")){$kde_version = 5;}
- elsif ($program = main::check_program("kded4")){$kde_version = 4;}
- elsif ($program = main::check_program("kded")){$kde_version = '';}
+ if ($program = main::check_program("kded6")){
+ $kde_version = 6;}
+ elsif ($program = main::check_program("kded5")){
+ $kde_version = 5;}
+ elsif ($program = main::check_program("kded4")){
+ $kde_version = 4;}
+ elsif ($program = main::check_program("kded")){
+ $kde_version = '';}
}
# alternate: qt4-default, qt4-qmake or qt5-default, qt5-qmake
# often this exists, is executable, but actually is nothing, shows error
- if (!$desktop->[3] && main::check_program('qmake')){
- ($desktop->[2],$desktop->[3]) = main::program_data('qmake');
+ if (!$desktop->[3] && ($program = main::check_program('qmake'))){
+ ($desktop->[2],$desktop->[3]) = ProgramData::full('qmake-qt',$program);
}
- if (!$desktop->[3] && main::check_program('qtdiag')){
- ($desktop->[2],$desktop->[3]) = main::program_data('qtdiag');
+ if (!$desktop->[3] && ($program = main::check_program('qtdiag'))){
+ ($desktop->[2],$desktop->[3]) = ProgramData::full('qtdiag-qt',$program);
}
if (!$desktop->[3] && ($program = main::check_program("kf$kde_version-config"))){
- @version_data = main::grabber("$program --version 2>/dev/null");
- $desktop->[2] = 'Qt';
- $desktop->[3] = main::awk(\@version_data,'^Qt:',2) if @version_data;
+ ($desktop->[2],$desktop->[3]) = ProgramData::full('kf-config-qt',$program);
}
# note: qt 5 does not show qt version in kded5, sigh
if (!$desktop->[3] && ($program = main::check_program("kded$kde_version"))){
- @version_data = main::grabber("$program --version 2>/dev/null");
- $desktop->[2] = 'Qt';
- $desktop->[3] = main::awk(\@version_data,'^Qt:',2) if @version_data;
+ ($desktop->[2],$desktop->[3]) = ProgramData::full('kded-qt',$program);
+ }
+ if ($b_dbg_de && ($desktop->[2] || $desktop->[3])){
+ main::feature_debugger('qt $program,qt,v $desktop 2,3',
+ [$program,$desktop->[2],$desktop->[3]],$dbg[63]);
}
eval $end if $b_log;
}
-sub get_wm {
+## WM DATA ##
+sub wm_data {
eval $start if $b_log;
+ my $b_wm;
if (!$force{'wmctrl'}){
- get_wm_main();
+ set_xprop() if !$loaded{'xprop'};
+ wm_ps_xprop_data(\$b_wm);
}
# note, some wm, like cinnamon muffin, do not appear in ps aux, but do in wmctrl
- if ((!$desktop->[5] || $force{'wmctrl'}) && (my $program = main::check_program('wmctrl'))){
- get_wm_wmctrl($program);
- }
- eval $end if $b_log;
-}
-sub get_wm_main {
- eval $start if $b_log;
- my ($wms,$working);
- # xprop is set only if not kde/gnome/cinnamon/mate/budgie/lx..
- if ($b_xprop){
- #KWIN_RUNNING
- $wms = 'amiwm|blackbox|bspwm|compiz|kwin_wayland|kwin_x11|kwinft|kwin|marco|';
- $wms .= 'motif|muffin|openbox|herbstluftwm|twin|ukwm|wm2|windowmaker|i3';
- foreach (@xprop){
- if (/($wms)/){
- $working = $1;
- $working = 'wmaker' if $working eq 'windowmaker';
- last;
- }
+ if (((!$b_wm && !$desktop->[5]) || $force{'wmctrl'}) &&
+ (my $program = main::check_program('wmctrl'))){
+ wm_wmctrl_data($program);
+ }
+ eval $end if $b_log;
+}
+
+# args: 0: $b_wm ref
+sub wm_ps_xprop_data {
+ eval $start if $b_log;
+ my $b_wm = $_[0];
+ my @wms;
+ # order matters, see above logic
+ push(@wms,@{$ps_data{'de-wm-compositors'}}) if @{$ps_data{'de-wm-compositors'}};
+ push(@wms,@{$ps_data{'wm-compositors'}}) if @{$ps_data{'wm-compositors'}};
+ push(@wms,@{$ps_data{'wm-main'}}) if @{$ps_data{'wm-main'}};
+ # eg: blackbox parent of icewm, icewm parent of blackbox
+ push(@wms,@{$ps_data{'wm-parent'}}) if @{$ps_data{'wm-parent'}};
+ # leave off parent since that would always be primary
+ foreach my $wm (@wms){
+ if ($wm eq 'windowmaker'){
+ $wm = 'wmaker';}
+ wm_version('manual',$wm,$b_wm);
+ if ($desktop->[5]){
+ main::feature_debugger('ps wm,v $desktop 5,6',
+ [$desktop->[5],$desktop->[6]],$dbg[63]) if $b_dbg_de;
+ last;
}
}
- if (!$desktop->[5]){
- main::set_ps_gui() if !$loaded{'ps-gui'};
- # order matters, see above logic
- # due to lisp/python starters, clfswm/stumpwm/qtile will not detect here
- my @wms = qw(2bwm 9wm aewm aewm\+\+ afterstep amiwm antiwm awesome blackbox
- calmwm catwm clfswm compiz ctwm (openbsd-)?cwm fluxbox bspwm budgie-wm
- deepin-wm dwm echinus evilwm flwm fvwm-crystal fvwm1 fvwm2 fvwm3 fvwm95
- fvwm gala gnome-shell hackedbox i3 instantwm ion3 jbwm jwm twin kwin_wayland
- kwin_x11 kwinft kwin larswm leftwm lwm matchbox-window-manager marco mcwm mini
- muffin musca deepin-mutter mutter deepin-metacity metacity mvwm mwm
- nawm notion openbox qtile qvwm penrose ratpoison sawfish scrotwm snapwm
- spectrwm stumpwm tinywm tvtwm twm ukwm windowlab WindowMaker wingo wmfs2?
- wmii2? wmx xfwm[45]? xmonad yeahwm);
- my $wms = join('|',@wms) . $wl_compositors;
- foreach my $psg (@ps_gui){
- if ($psg =~ /^($wms)$/){
- $working = $1;
+ # xprop is set only if not kde/gnome/cinnamon/mate/budgie/lx. Issues with
+ # fluxbox blackbox_pid false detection, so run this as fallback.
+ if (!$desktop->[5] && %xprop){
+ # print "wm ps xprop: ", Data::Dumper::Dumper \%xprop;
+ # KWIN_RUNNING, note: the actual xprop filters handle position and _ type syntax
+ # don't use i3, it's not unique enough in this test, can trigger false positive
+ @wms = qw(amiwm blackbox bspwm compiz kwin_x11 kwinft kwin
+ marco motif muffin mutter openbox herbstluftwm twin ukwm wm2 windowmaker);
+ my $working;
+ foreach my $wm (@wms){
+ last if $desktop->[0] && $wm eq lc($desktop->[0]); # catch odd stuff like wmaker
+ if ($xprop{$wm}){
+ $working = $wm;
+ if ($working eq 'mutter' && $desktop->[0] && lc($desktop->[0]) eq 'cinnamon'){
+ $working = 'muffin';
+ }
+ $working = $xprop{$wm}->{'vname'} if $xprop{$wm}->{'vname'};
+ wm_version('manual',$working,$b_wm);
+ main::feature_debugger('xprop wm,v $desktop 5,6',
+ [$desktop->[5],$desktop->[6]],$dbg[63]) if $b_dbg_de;
last;
}
}
}
- get_wm_version('manual',$working) if $working;
- $desktop->[5] = $working if !$desktop->[5] && $working;
eval $end if $b_log;
}
-sub get_wm_wmctrl {
+
+sub wm_wmctrl_data {
eval $start if $b_log;
my ($program) = @_;
my $cmd = "$program -m 2>/dev/null";
my @data = main::grabber($cmd,'','strip');
main::log_data('dump','@data',\@data) if $b_log;
$desktop->[5] = main::awk(\@data,'^Name',2,'\s*:\s*');
- $desktop->[5] = '' if $desktop->[5] && $desktop->[5] eq 'N/A';
+ # qtile,scrotwm,spectrwm have an odd fake wmctrl wm for irrelevant reasons
+ # inxi doesn't support lg3d, if support added update this, but assume bad
+ if ($desktop->[5] && ($desktop->[5] eq 'N/A' ||
+ ($desktop->[0] && $desktop->[5] eq 'LG3D'))){
+ $desktop->[5] = '';
+ }
if ($desktop->[5]){
# variants: gnome shell;
# IceWM 1.3.8 (Linux 3.2.0-4-amd64/i686) ; Metacity (Marco) ; Xfwm4
$desktop->[5] =~ s/\d+\.\d\S+|[\[\(].*\d+\.\d.*[\)\]]//g;
$desktop->[5] = main::trimmer($desktop->[5]);
# change Metacity (Marco) to marco
- if ($desktop->[5] =~ /marco/i){$desktop->[5] = 'marco'}
- elsif ($desktop->[5] =~ /muffin/i){$desktop->[5] = 'muffin'}
- elsif (lc($desktop->[5]) eq 'gnome shell'){$desktop->[5] = 'gnome-shell'}
- elsif ($desktop_session eq 'trinity' && lc($desktop->[5]) eq 'kwin'){$desktop->[5] = 'Twin'}
- get_wm_version('wmctrl',$desktop->[5]);
+ if ($desktop->[5] =~ /marco/i){
+ $desktop->[5] = 'marco';}
+ elsif ($desktop->[5] =~ /muffin/i){
+ $desktop->[5] = 'muffin';}
+ elsif (lc($desktop->[5]) eq 'gnome shell'){
+ $desktop->[5] = 'gnome-shell';}
+ elsif ($desktop_session eq 'trinity' && lc($desktop->[5]) eq 'kwin'){
+ $desktop->[5] = 'Twin';}
+ wm_version('wmctrl',$desktop->[5]);
+ main::feature_debugger('wmctrl wm,v $desktop 5,6',
+ [$desktop->[5],$desktop->[6]],$dbg[63]) if $b_dbg_de;
}
eval $end if $b_log;
}
-sub get_wm_version {
+
+# args: 0: manual/wmctrl; 1: wm; 2: $b_wm ref
+sub wm_version {
eval $start if $b_log;
- my ($type,$wm) = @_;
+ my ($type,$wm,$b_wm) = @_;
# we don't want the gnome-shell version, and the others have no --version
# we also don't want to run --version again on stuff we already have tested
- return if !$wm || $wm =~ /^(budgie-wm|gnome-shell)$/ || ($desktop->[0] && lc($desktop->[0]) eq lc($wm));
+ if (!$wm || ($desktop->[0] && lc($desktop->[0]) eq lc($wm))){
+ # we don't want to run wmctrl if we got a matching de/wm set
+ $$b_wm = 1 if $wm;
+ return;
+ }
+ elsif ($wm && $wm =~ /^(budgie-wm|gnome-shell)$/){
+ $desktop->[5] = $wm;
+ return;
+ }
my $temp = (split(/\s+/, $wm))[0];
if ($temp){
$temp = (split(/\s+/, $temp))[0];
$temp = lc($temp);
$temp = 'wmaker' if $temp eq 'windowmaker';
- my @data = main::program_data($temp,$temp,3);
+ my @data = ProgramData::full($temp,$temp,3);
return if !$data[0];
# print Data::Dumper::Dumper \@data;
$desktop->[5] = $data[0] if $type eq 'manual';
@@ -27084,80 +30058,177 @@ sub get_wm_version {
eval $end if $b_log;
}
-sub set_info_data {
+## PARTS/TOOLS DATA ##
+sub components_data {
eval $start if $b_log;
- main::set_ps_gui() if !$loaded{'ps-gui'};
- my (@data,@info,$item);
- my $pattern = 'alltray|awn|bar|bmpanel|bmpanel2|budgie-panel|cairo-dock|';
- $pattern .= 'dde-dock|dmenu|dockbarx|docker|docky|dzen|dzen2|';
- $pattern .= 'fancybar|fbpanel|fspanel|glx-dock|gnome-panel|hpanel|';
- $pattern .= 'i3bar|i3status|i3-status-rs|icewmtray|';
- $pattern .= 'kdocker|kicker|';
- $pattern .= 'latte|latte-dock|lemonbar|ltpanel|luastatus|lxpanel|lxqt-panel|';
- $pattern .= 'matchbox-panel|mate-panel|nwg-bar|nwg-dock|nwg-panel|ourico|';
- $pattern .= 'perlpanel|plank|plasma-desktop|plasma-netbook|polybar|pypanel|';
- $pattern .= 'razor-panel|razorqt-panel|rootbar|sfwbar|stalonetray|swaybar|';
- $pattern .= 'taskbar|tint2|trayer|';
- $pattern .= 'ukui-panel|vala-panel|wapanel|waybar|wbar|wharf|wingpanel|witray|';
- $pattern .= 'xfce4-panel|xfce5-panel|xmobar|yabar|yambar';
- if (@data = grep {/^($pattern)$/} @ps_gui){
- # only one entry per type, can be multiple
- foreach $item (@data){
- if (! grep {$item =~ /$_/} @info){
- $item = main::trimmer($item);
- $item =~ s/.*\///;
- push(@info, (split(/\s+/, $item))[0]);
+ if (@{$ps_data{'components-active'}}){
+ main::make_list_value($ps_data{'components-active'},\$desktop->[4],',','sort');
+ }
+ eval $end if $b_log;
+}
+
+sub tools_data {
+ eval $start if $b_log;
+ # these are running/active
+ if (@{$ps_data{'tools-active'}}){
+ main::make_list_value($ps_data{'tools-active'},\$desktop->[7],',','sort');
+ }
+ # now check if any are available but not running/services
+ if ($b_admin){
+ my %test;
+ my $installed = [];
+ if ($desktop->[7]){
+ foreach my $tool (@{$ps_data{'tools-active'}}){
+ $test{$tool} = 1;
+ }
+ }
+ foreach my $item (@{$ps_data{'tools-test'}}){
+ next if $test{$item};
+ if (main::check_program($item)){
+ push(@$installed,$item);
}
}
+ if (@$installed){
+ main::make_list_value($installed,\$desktop->[8],',','sort');
+ }
}
- if (@info){
- main::uniq(\@info);
- $desktop->[4] = join(', ', @info);
+ eval $end if $b_log;
+}
+
+## UTILITIES ##
+
+# args: 0: raw $version data ref; 1: [search regex, split pos, print name]
+# returns item print name, version
+sub item_from_version {
+ eval $start if $b_log;
+ my ($item,$version);
+ if (!$_[0] || !$_[1] || ref $_[0] ne 'ARRAY'){
+ eval $end if $b_log;
+ return;
+ }
+ foreach my $line (@{$_[0]}){
+ # print "line: $line\n";
+ if ($line =~ /${$_[1]}[0]/){
+ my @data = split(/\s+/,$line);
+ # print 'ifv main: ', Data::Dumper::Dumper \@data;
+ ($item,$version) = (${$_[1]}[2],$data[${$_[1]}[1] - 1]);
+ last;
+ }
}
+ $version =~ s/[,_\.-]$//g if $version; # trim off gunk
eval $end if $b_log;
+ return ($item,$version);
+}
+
+# note: for tests, all values are lowercased.
+sub set_env_data {
+ # NOTE $XDG_CURRENT_DESKTOP envvar is not reliable, but it shows certain desktops better.
+ # most desktops are not using it as of 2014-01-13 (KDE, UNITY, LXDE. Not Gnome)
+ $desktop_session = ($ENV{'DESKTOP_SESSION'}) ? clean_env($ENV{'DESKTOP_SESSION'}) : '';
+ $xdg_desktop = ($ENV{'XDG_CURRENT_DESKTOP'}) ? clean_env($ENV{'XDG_CURRENT_DESKTOP'}) : '';
+ $kde_full_session = ($ENV{'KDE_FULL_SESSION'}) ? clean_env($ENV{'KDE_FULL_SESSION'}) : '';
+ $kde_session_version = ($ENV{'KDE_SESSION_VERSION'}) ? $ENV{'KDE_SESSION_VERSION'} : '';
+ # for fallback to fallback protections re false gnome id
+ $gdmsession = ($ENV{'GDMSESSION'}) ? clean_env($ENV{'GDMSESSION'}) : '';
+ main::feature_debugger('desktop-scalars',
+ ['$desktop_session: ' . $desktop_session,
+ '$xdg_desktop: ' . $xdg_desktop,
+ '$kde_full_session: ' . $kde_full_session,
+ '$kde_session_version: ' . $kde_session_version,
+ '$gdmsession: ' . $gdmsession],$dbg[63]) if $b_dbg_de;
+}
+
+# Note: an ubuntu regresssion replaces or adds 'ubuntu' string to
+# real value. Since ubuntu is the only distro I know that does this,
+# will add more distro type filters as/if we come across them
+# args: 0:
+sub clean_env {
+ $_[0] = lc(main::trimmer($_[0]));
+ $_[0] =~ s/\b(arch|debian|fedora|manjaro|mint|opensuse|ubuntu):?\s*//i;
+ return $_[0];
}
sub set_xprop {
eval $start if $b_log;
+ $loaded{'xprop'} = 1;
+ my $data;
if (my $program = main::check_program('xprop')){
- @xprop = main::grabber("xprop -root $display_opt 2>/dev/null");
- if (@xprop){
- # add wm / de as required, but only add what is really tested for above
+ $data = main::grabber("xprop -root $display_opt 2>/dev/null",'','strip','ref');
+ if ( @$data){
+ my $pattern = '_(MIT|QT_DESKTOP|WIN|XROOTPMAP)_|_NET_(CLIENT|SUPPORTED)|';
+ $pattern .= '(AT_SPI|ESETROOT|GDK_VISUALS|GNOME_SM|PULSE|RESOURCE_|XKLAVIER';
+ @$data = grep {!/^($pattern))/} @$data;
+ }
+ if ($data && @$data){
+ $_ = lc for @$data;
+ # Add wm / de as required, but only add what is really tested for above
+ # index: 0: PD full name; 1: xprop search; 2: PD version name
+ my @info = (
+ ['amiwm','^amiwm',''],
+ # leads to false IDs since other wm have this too
+ # ['blackbox','blackbox_pid',''], # fluxbox, forked from blackbox, has this
+ ['bspwm','bspwm',''],
+ ['compiz','compiz',''],
+ ['enlightenment','enlightenment',''], # gets version from line
+ ['gnome-session','^_gnome_session',''],
+ ['herbstluftwm','herbstluftwm',''],
+ ['i3','^i3_',''],
+ ['icewm','icewm',''],
+ ['kde','^kde_','kwin'],
+ ['kwin','^kwin_',''],
+ ['marco','_marco',''],
+ ['moksha','moksha',''], # gets version from line
+ # cde's dtwm is based on mwm, leads to bad ID, look for them with env/ps
+ # ['motif','^_motif_wm','mwm'],
+ ['muffin','_muffin',''],
+ ['mutter','_mutter',''],
+ ['openbox','openbox_pid',''], # lxde, lxqt, razor _may_ have this
+ ['ukwm','^_ukwm',''],
+ ['windowmaker','^_?windowmaker','wmaker'],
+ ['wm2','^_wm2',''],
# XFDESKTOP_IMAGE_FILE; XFCE_DESKTOP
- my $pattern = '^amiwm|blackbox_pid|bspwm|compiz|enlightenment|^_gnome|';
- $pattern .= 'herbstluftwm|^kwin_|^i3_|icewm|_marco|moksha|^_motif|_muffin|';
- $pattern .= 'openbox_pid|^_ukwm|^_?windowmaker|^_wm2|^(xfdesktop|xfce)';
- # let's only do these searches once
- @xprop = grep {/^\S/ && /($pattern)/i} @xprop;
- $_ = lc for @xprop;
- $b_xprop = 1 if scalar @xprop > 0;
+ ['xfce','^xfce','xfdesktop'],
+ ['xfdesktop','^xfdesktop',''],
+ );
+ foreach my $item (@info){
+ foreach my $line (@$data){
+ if ($line =~ /$item->[1]/){
+ $xprop{$item->[0]} = {
+ 'name' => $item->[0],
+ 'vname' => $item->[2],
+ } if !$xprop{$item->[0]};
+ # we can have > 1 results for each search, and we want those lines
+ push(@{$xprop{$item->[0]}->{'lines'}},$line);
+ }
+ }
+ }
}
}
- # print "@xprop\n";
+ main::feature_debugger('xprop data: working, results',
+ [$data,\%xprop],$dbg[63]) if $b_dbg_de;
eval $end if $b_log;
}
-
}
## DeviceData
# creates arrays: $devices{'audio'}; $devices{'graphics'}; $devices{'hwraid'};
# $devices{'network'}; $devices{'timer'} and local @devices for logging/debugging
-# 0 type
-# 1 type_id
-# 2 bus_id
-# 3 sub_id
-# 4 device
-# 5 vendor_id
-# 6 chip_id
-# 7 rev
-# 8 port
-# 9 driver
-# 10 modules
-# 11 driver_nu [bsd, like: em0 - driver em; nu 0. Used to match IF in -n
-# 12 subsystem/vendor
-# 13 subsystem vendor_id:chip id
-# 14 soc handle
-# 15 serial number
+# 0: type
+# 1: type_id
+# 2: bus_id
+# 3: sub_id
+# 4: device
+# 5: vendor_id
+# 6: chip_id
+# 7: rev
+# 8: port
+# 9: driver
+# 10: modules
+# 11: driver_nu [bsd, like: em0 - driver em; nu 0. Used to match IF in -n
+# 12: subsystem/vendor
+# 13: subsystem vendor_id:chip id
+# 14: soc handle
+# 15: serial number
{
package DeviceData;
my (@bluetooth,@devices,@files,@full_names,@pcis,@temp,@temp2,@temp3,%lspci_n);
@@ -27312,7 +30383,8 @@ sub lspci_data {
main::log_data('dump','lspci @devices',\@devices) if $b_log;
eval $end if $b_log;
}
-# arg: $1 - busID
+
+# args: 0: busID
# returns if valid busID: (classID,vendorID,productID,revNu)
# almost never used, only in case of lspci -nnv line truncation bug
sub lspci_n_data {
@@ -27322,8 +30394,8 @@ sub lspci_n_data {
$b_lspci_n = 1;
my (@data);
if ($fake{'lspci'}){
- # my $file = "$fake_data_dir/lspci/steve-mint-topaz-lspci-n.txt";
- # my $file = "$fake_data_dir/lspci/ben81-hwraid-lspci-n.txt";
+ # my $file = "$fake_data_dir/pci/lspci/steve-mint-topaz-lspci-n.txt";
+ # my $file = "$fake_data_dir/pci/lspci/ben81-hwraid-lspci-n.txt";
# @data = main::reader($file,'strip');
}
else {
@@ -27458,6 +30530,7 @@ sub pcidump_data {
main::log_data('dump','pcidump @devices',\@devices) if $b_log;
eval $end if $b_log;
}
+
sub pcidump_driver {
eval $start if $b_log;
my $bus_id = $_[0];
@@ -27472,6 +30545,7 @@ sub pcidump_driver {
eval $end if $b_log;
return ($driver,$nu);
}
+
sub pcictl_data {
eval $start if $b_log;
my $data = pci_grabber('pcictl');
@@ -27523,38 +30597,38 @@ sub pci_grabber {
# 2.2.8 lspci did not support -k, added in 2.2.9, but -v turned on -k
$args = ' -nnv';
$path = $alerts{'lspci'}->{'path'};
- $pattern = qr/^[0-9a-f]+:/;
+ $pattern = q/^[0-9a-f]+:/; # i only added perl 5.14, don't use qr/
}
elsif ($program eq 'pciconf'){
$args = ' -lv';
$path = $alerts{'pciconf'}->{'path'};
- $pattern = qr/^([^@]+)\@pci/;
+ $pattern = q/^([^@]+)\@pci/; # i only added perl 5.14, don't use qr/
}
elsif ($program eq 'pcidump'){
$args = ' -v';
$path = $alerts{'pcidump'}->{'path'};
- $pattern = qr/^[0-9a-f]+:/;
+ $pattern = q/^[0-9a-f]+:/; # i only added perl 5.14, don't use qr/
}
elsif ($program eq 'pcictl'){
$args = ' pci0 list -N';
$path = $alerts{'pcictl'}->{'path'};
- $pattern = qr/^[0-9a-f:]+:/;
+ $pattern = q/^[0-9a-f:]+:/; # i only added perl 5.14, don't use qr/
}
elsif ($program eq 'pcictl-n'){
$args = ' pci0 list -n';
$path = $alerts{'pcictl'}->{'path'};
- $pattern = qr/^[0-9a-f:]+:/;
+ $pattern = q/^[0-9a-f:]+:/; # i only added perl 5.14, don't use
}
if ($fake{'lspci'} || $fake{'pciconf'} || $fake{'pcictl'} || $fake{'pcidump'}){
- # my $file = "$fake_data_dir/pciconf/pci-freebsd-8.2-2";
- # my $file = "$fake_data_dir/pcidump/pci-openbsd-6.1-vm.txt";
- # my $file = "$fake_data_dir/pcictl/pci-netbsd-9.1-vm.txt";
- # my $file = "$fake_data_dir/lspci/racermach-1-knnv.txt";
- # my $file = "$fake_data_dir/lspci/rk016013-knnv.txt";
- # my $file = "$fake_data_dir/lspci/kot--book-lspci-nnv.txt";
- # my $file = "$fake_data_dir/lspci/steve-mint-topaz-lspci-nnkv.txt";
- # my $file = "$fake_data_dir/lspci/ben81-hwraid-lspci-nnv.txt";
- # my $file = "$fake_data_dir/lspci/gx78b-lspci-nnv.txt";
+ # my $file = "$fake_data_dir/pci/pciconf/pci-freebsd-8.2-2";
+ # my $file = "$fake_data_dir/pci/pcidump/pci-openbsd-6.1-vm.txt";
+ # my $file = "$fake_data_dir/pci/pcictl/pci-netbsd-9.1-vm.txt";
+ # my $file = "$fake_data_dir/pci/lspci/racermach-1-knnv.txt";
+ # my $file = "$fake_data_dir/pci/lspci/rk016013-knnv.txt";
+ # my $file = "$fake_data_dir/pci/lspci/kot--book-lspci-nnv.txt";
+ # my $file = "$fake_data_dir/pci/lspci/steve-mint-topaz-lspci-nnkv.txt";
+ # my $file = "$fake_data_dir/pci/lspci/ben81-hwraid-lspci-nnv.txt";
+ # my $file = "$fake_data_dir/pci/lspci/gx78b-lspci-nnv.txt";
# $data = main::reader($file,'strip','ref');
}
else {
@@ -27585,6 +30659,7 @@ sub soc_data {
main::log_data('dump','soc @devices',\@devices) if $b_log;
eval $end if $b_log;
}
+
# 1: /sys/devices/platform/soc/1c30000.ethernet/uevent:["DRIVER=dwmac-sun8i", "OF_NAME=ethernet",
# "OF_FULLNAME=/soc/ethernet@1c30000", "OF_COMPATIBLE_0=allwinner,sun8i-h3-emac",
# "OF_COMPATIBLE_N=1", "OF_ALIAS_0=ethernet0", # "MODALIAS=of:NethernetT<NULL>Callwinner,sun8i-h3-emac"]
@@ -27699,6 +30774,7 @@ sub soc_devices {
}
eval $end if $b_log;
}
+
sub soc_devicetree {
eval $start if $b_log;
# now we want to fill in stuff that was not in /sys/devices/
@@ -27736,6 +30812,7 @@ sub soc_devicetree {
}
eval $end if $b_log;
}
+
sub set_bluetooth {
# special case of pi bt on ttyAMA0
$b_bt_check = 1;
@@ -27744,6 +30821,7 @@ sub set_bluetooth {
@bluetooth = grep {!/usb/} @bluetooth if @bluetooth; # we only want non usb bt
main::log_data('dump','soc bt: @bluetooth', \@bluetooth) if $b_log;
}
+
sub assign_data {
my ($tool,$data) = @_;
if (check_graphics($data->[0],$data->[1])){
@@ -27775,7 +30853,8 @@ sub assign_data {
# $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()
+
+# Note: for SOC these have been converted in soc_type()
sub check_audio {
if (($_[1] && length($_[1]) == 4 && $_[1] =~ /^04/) ||
($_[0] && $_[0] =~ /^(audio|hdmi|multimedia|sound)$/i)){
@@ -27783,6 +30862,7 @@ sub check_audio {
}
else {return 0}
}
+
sub check_bluetooth {
if (($_[1] && length($_[1]) == 4 && $_[1] eq '0d11') ||
($_[0] && $_[0] =~ /^(bluetooth)$/i)){
@@ -27790,6 +30870,7 @@ sub check_bluetooth {
}
else {return 0}
}
+
sub check_graphics {
# note: multimedia class 04 is video if 0400. 'tv' is risky I think
if (($_[1] && length($_[1]) == 4 && ($_[1] =~ /^03/ || $_[1] eq '0400' ||
@@ -27799,9 +30880,11 @@ sub check_graphics {
}
else {return 0}
}
+
sub check_hwraid {
return 1 if ($_[1] && $_[1] eq '0104');
}
+
# NOTE: class 06 subclass 80
# https://www-s.acm.illinois.edu/sigops/2007/roll_your_own/7.c.1.html
# 0d20: 802.11a 0d21: 802.11b 0d80: other wireless
@@ -27812,9 +30895,11 @@ sub check_network {
}
else {return 0}
}
+
sub check_timer {
return 1 if ($_[0] && $_[0] eq 'timer');
}
+
sub check_vm {
if ($_[0] && $_[0] =~ /(innotek|vbox|virtualbox|vmware|qemu)/i){
return $1
@@ -27863,6 +30948,7 @@ sub soc_type {
}
return $type;
}
+
sub pci_class {
eval $start if $b_log;
my ($id) = @_;
@@ -27923,7 +31009,8 @@ sub get_device_temp {
# disklabel: partID, block-size, fs, size
{
package DiskDataBSD;
-# sets initial pure dboot data, and fills it in with
+
+# Sets initial pure dboot data, and fills it in with
# disklabel/gpart partition and advanced data
sub set {
eval $start if $b_log;
@@ -27939,6 +31026,7 @@ sub set {
}
eval $end if $b_log;
}
+
sub get {
eval $start if $b_log;
my $id = $_[0];
@@ -27965,6 +31053,7 @@ sub get {
eval $end if $b_log;
return $data;
}
+
sub set_dboot_disks {
eval $start if $b_log;
my ($working,@temp);
@@ -28039,6 +31128,7 @@ sub set_dboot_disks {
main::log_data('dump','%disks_bsd',\%disks_bsd) if $b_log;
eval $end if $b_log;
}
+
sub bioctl_data {
eval $start if $b_log;
my $id = $_[0];
@@ -28055,6 +31145,7 @@ sub bioctl_data {
eval $end if $b_log;
return $serial;
}
+
sub set_disklabel_data {
eval $start if $b_log;
my ($cmd,@data,@working);
@@ -28129,6 +31220,7 @@ sub set_disklabel_data {
main::log_data('dump', '%disks_bsd', \%disks_bsd) if $b_log;
eval $end if $b_log;
}
+
sub fdisk_data {
eval $start if $b_log;
my $id = $_[0];
@@ -28147,6 +31239,7 @@ sub fdisk_data {
eval $start if $b_log;
return $scheme;
}
+
# 2021-03: openbsd: n/a; dragonfly: no 'list'; freebsd: yes
sub set_gpart_data {
eval $start if $b_log;
@@ -28224,22 +31317,34 @@ sub set_gpart_data {
}
}
-sub get_display_manager {
+## DmData
+# Public method: get()
+# returns hash ref of array of arrays for dm/lm
+# hash: dm, lm
+# 0: dm/lm print name
+# 1: dm/lm version
+# 2: dm/lm status
+{
+package DmData;
+my ($found,@glob);
+
+sub get {
+ eval $start if $b_log;
+ set_glob();
+ $found = {};
+ get_dm_lm('dm');
+ if (!$found->{'dm'}){
+ test_ps_dm()
+ }
+ get_dm_lm('lm') if !$found->{'dm'};
+ print 'dm data: ', Data::Dumper::Dumper $found if $dbg[60];
+ main::log_data('dump','display manager: %$found',$found) if $b_log;
+ eval $end if $b_log;
+ return $found;
+}
+
+sub set_glob {
eval $start if $b_log;
- my (@data,@glob,$link,$path,@temp);
- my $found = [];
- # ldm - LTSP display manager. Note that sddm does not appear to have a .pid
- # extension in Arch. Guessing on cdm, qingy. pcdm uses vt, PCDM-vt9.pid
- # Not verified: qingy emptty; greetd.run verified, but alternate:
- # greetd-684.sock if no .run seen. Add Ly in case they add run file/directory.
- # greetd frontends: agreety dlm gtkgreet qtgreet tuigreet wlgreet
- # mlogin may be mlogind, not verified
- my @dms = qw(brzdm cdm clogin emptty entranced gdm gdm3 greetd kdm kdm3 kdmctl
- ldm lightdm lxdm ly mdm mlogin nodm pcdm qingy sddm slim slimski tbsm tdm
- udm wdm xdm xdmctl xenodm xlogin);
- # these are the only one I know of so far that have version info. xlogin /
- # clogin do, -V, brzdm -v, but syntax not verified.
- my @dms_version = qw(gdm gdm3 lightdm ly slim);
my $pattern = '';
if (-d '/run'){
$pattern .= '/run';
@@ -28254,9 +31359,32 @@ sub get_display_manager {
$pattern .= '/var/run/rc.d';
}
if ($pattern){
- $pattern = '{' . $pattern . '/*}' if $pattern;
+ $pattern = '{' . $pattern . '}/*';
# for dm.pid type file or dm directory names, like greetd-684.sock
- @glob = globber($pattern) if $pattern;
+ @glob = main::globber($pattern);
+ main::uniq(\@glob) if @glob;
+ }
+ print '@glob: ', Data::Dumper::Dumper \@glob if $dbg[60];
+ main::log_data('dump','dm @glob:',\@glob) if $b_log;
+ eval $end if $b_log;
+}
+
+# args: 0: dm/lm, first test for dms, then if no dms, test for lms
+sub get_dm_lm {
+ eval $start if $b_log;
+ my $type = $_[0];
+ my (@dms,@glob_working,@temp);
+ # See: docs/inxi-desktops-wm.txt for Display/login manager info.
+ # Guessing on cdm, qingy. pcdm uses vt, PCDM-vt9.pid
+ # Add Ly in case they add run file/directory.
+ if ($type eq 'dm'){
+ @dms = qw(brzdm cdm emptty entranced gdm gdm3 kdm kdm3 kdmctl ldm lemurs
+ lightdm loginx lxdm ly mdm mlogind nodm pcdm qingy sddm slim slimski tdm
+ udm wdm x3dm xdm xdmctl xenodm);
+ }
+ # greetd frontends: agreety dlm gtkgreet qtgreet tuigreet wlgreet
+ else {
+ @dms = qw(elogind greetd seatd tbsm);
}
# print Data::Dumper::Dumper \@glob;
# used to test for .pid/lock type file or directory, now just see if the
@@ -28264,175 +31392,226 @@ sub get_display_manager {
# if directory existed previously anyway.
if (@glob){
my $search = join('|',@dms);
- @glob = grep {/\/($search)\b/} @glob;
- # $search = join('|',@glob);
- if (@glob){
- uniq(\@glob);
- foreach my $item (@glob){
+ @glob_working = grep {/\/($search)\b/} @glob;
+ if (@glob_working){
+ foreach my $item (@glob_working){
my @id = grep {$item =~ /\/$_\b/} @dms;
push(@temp,@id) if @id;
}
# note: there were issues with duplicated dm's, using uniq will handle those
- uniq(\@temp) if @temp;
+ main::uniq(\@temp) if @temp;
}
}
@dms = @temp;
- my (@dm_info);
+ my @dm_info;
# print Data::Dumper::Dumper \@dms;
# we know the files or directories exist so no need for further checks here
foreach my $dm (@dms){
- # do nothing, we just wanted the path
- if ($extra > 2 && (grep {$dm eq $_} @dms_version) &&
- ($path = check_program($dm))){}
- else {$path = $dm}
- # print "$path $extra\n";
@dm_info = ();
- @data = program_data($dm,$path,3);
- $dm_info[0] = $data[0];
- $dm_info[1] = $data[1];
+ ($dm_info[0],$dm_info[1]) = ProgramData::full($dm,'',3);
if (scalar @dms > 1 && (my $temp = ServiceData::get('status',$dm))){
- $dm_info[2] = message('stopped') if $temp && $temp =~ /stopped|disabled/;
+ $dm_info[2] = main::message('stopped') if $temp && $temp =~ /stopped|disabled/;
}
- push(@$found,[@dm_info]);
+ push(@{$found->{$type}},[@dm_info]);
}
- if (!@$found){
+ eval $end if $b_log;
+}
+
+sub test_ps_dm {
+ eval $start if $b_log;
+ PsData::set_dm();
+ if (@{$ps_data{'dm-active'}}){
+ my @dm_info;
# ly does not have a run/pid file
- if (grep {$_ eq 'ly'} @ps_gui){
- @data = program_data('ly','ly',3);
- $dm_info[0] = $data[0];
- $dm_info[1] = $data[1];
- $found->[0] = [@dm_info];
+ if (grep {$_ eq 'ly'} @{$ps_data{'dm-active'}}){
+ ($dm_info[0],$dm_info[1]) = ProgramData::full('ly','ly',3);
+ $found->{'dm'}[0] = [@dm_info];
}
- elsif (grep {/startx$/} @ps_gui){
- $found->[0] = ['startx'];
+ elsif (grep {/startx$/} @{$ps_data{'dm-active'}}){
+ $found->{'dm'}[0] = ['startx'];
}
- elsif (grep {$_ eq 'xinit'} @ps_gui){
- $found->[0] = ['xinit'];
+ elsif (grep {$_ eq 'xinit'} @{$ps_data{'dm-active'}}){
+ $found->{'dm'}[0] = ['xinit'];
}
}
- # might add this in, but the rate of new dm's makes it more likely it's an
- # unknown dm, so we'll keep output to N/A
- # print Data::Dumper::Dumper \@found;
- log_data('dump','display manager: @$found',$found) if $b_log;
eval $end if $b_log;
- return $found;
+}
}
## DistroData
{
package DistroData;
-my (@distro_files,@osr,@working);
-my ($distro,$distro_file,$distro_id,$system_base) = ('','','','');
+my ($id_src,@osr,@working);
my ($etc_issue,$lc_issue,$os_release) = ('','','/etc/os-release');
+my $distro = {
+'base' => '',
+'base-files' => [],
+'base-method' => [],
+'file' => '',
+'files' => [],
+'id' => '',
+'method' => [],
+'name' => '',
+};
+
sub get {
eval $start if $b_log;
+ if ($dbg[66] || $b_log){
+ $distro->{'dbg'} = 1;
+ }
if ($bsd_type){
- get_bsd_os();
+ get_distro_bsd();
}
else {
- get_linux_distro();
+ get_distro_linux();
}
eval $end if $b_log;
- return ($distro,$system_base);
+ return $distro;
}
-sub get_bsd_os {
+## BSD ##
+sub get_distro_bsd {
eval $start if $b_log;
# used to parse /System/Library/CoreServices/SystemVersion.plist for Darwin
# but dumping that since it broke, just using standard BSD uname 0 2 name.
- if (!$distro){
+ if (!$distro->{'name'}){
my $bsd_type_osr = 'dragonfly';
- @osr = main::reader($os_release) if -r $os_release;
- if (@osr && $bsd_type =~ /($bsd_type_osr)/ && (grep {/($bsd_type_osr)/i} @osr)){
- $distro = get_os_release();
- $distro_id = lc($1);
+ if (-r $os_release){
+ @osr = main::reader($os_release);
+ push(@{$distro->{'files'}},$os_release) if $distro->{'dbg'};
+ if (@osr && $bsd_type =~ /($bsd_type_osr)/ && (grep {/($bsd_type_osr)/i} @osr)){
+ $distro->{'name'} = get_osr();
+ $distro->{'id'} = lc($1);
+ push(@{$distro->{'method'}},$os_release);
+ }
}
}
- if (!$distro){
+ if (!$distro->{'name'}){
my $bsd_type_version = 'truenas';
my ($version_file,$version_info) = ('/etc/version','');
- $version_info = main::reader($version_file,'strip') if -r $version_file;
- if ($version_info && $version_info =~ /($bsd_type_version)/i){
- $distro = $version_info;
- $distro_id = lc($1);
+ if (-r $version_file){
+ $version_info = main::reader($version_file,'strip');
+ push(@{$distro->{'files'}},$version_file) if $distro->{'dbg'};
+ if ($version_info && $version_info =~ /($bsd_type_version)/i){
+ $distro->{'name'} = $version_info;
+ $distro->{'id'} = lc($1);
+ push(@{$distro->{'method'}},$version_file);
+ }
}
}
- if (!$distro){
+ if (!$distro->{'name'}){
# seen a case without osx file, or was it permissions?
# this covers all the other bsds anyway, no problem.
- $distro = "$uname[0] $uname[2]";
- $distro_id = lc($uname[0]);
+ $distro->{'name'} = "$uname[0] $uname[2]";
+ $distro->{'id'} = lc($uname[0]);
+ push(@{$distro->{'method'}},'uname 0, 2');
}
- if ($distro &&
+ if ($distro->{'name'} &&
(-e '/etc/pkg/GhostBSD.conf' || -e '/usr/local/etc/pkg/repos/GhostBSD.conf') &&
- $distro =~ /freebsd/i){
+ $distro->{'name'} =~ /freebsd/i){
my $version = (main::grabber("pkg query '%v' os-generic-userland-base 2>/dev/null"))[0];
# only swap if we get result from the query
if ($version){
- $system_base = $distro;
- $distro = "GhostBSD $version";
+ $distro->{'base'} = $distro->{'name'};
+ $distro->{'name'} = "GhostBSD $version";
+ push(@{$distro->{'method'}},'pkg query');
}
}
+ if ($distro->{'dbg'}){
+ dbg_distro_files('BSD',$distro->{'files'});
+ main::feature_debugger('name: $distro: pre-base [bsd]',$distro);
+ }
system_base_bsd() if $extra > 0;
eval $end if $b_log;
}
-sub get_linux_distro {
+sub system_base_bsd {
+ eval $start if $b_log;
+ # ghostbsd is handled in main bsd section
+ if (lc($uname[1]) eq 'nomadbsd' && $distro->{'id'} eq 'freebsd'){
+ $distro->{'base'} = $distro->{'name'};
+ $distro->{'name'} = $uname[1];
+ push(@{$distro->{'method-base'}},'uname 1');
+ }
+ elsif (-f '/etc/pkg/HardenedBSD.conf' && $distro->{'id'} eq 'freebsd'){
+ $distro->{'base'} = $distro->{'name'};
+ $distro->{'name'} = 'HardenedBSD';
+ push(@{$distro->{'method-base'}},'/etc/pkg/HardenedBSD.conf');
+ }
+ elsif ($distro->{'id'} =~ /^(truenas)$/){
+ $distro->{'base'} = "$uname[0] $uname[2]";
+ push(@{$distro->{'method-base'}},'uname 0 + 2');
+ }
+ main::feature_debugger('system-base: $distro [bsd]',$distro) if $distro->{'dbg'};
+ eval $end if $b_log;
+}
+
+# GNU/LINUX ##
+sub get_distro_linux {
+ # NOTE: increasingly no distro release files are present, so this logic is
+ # deprecated, but still works often.
# order matters!
my @derived = qw(antix-version aptosid-version bodhibuilder.conf kanotix-version
knoppix-version pclinuxos-release mandrake-release manjaro-release mx-version
- pardus-release porteus-version q4os_version sabayon-release siduction-version
- sidux-version slax-version slint-version slitaz-release solusos-release
- turbolinux-release zenwalk-version);
- my $derived_s = join('|', @derived);
+ pardus-release porteus-version q4os_version sabayon-release
+ siduction-version sidux-version slax-version slint-version slitaz-release
+ solusos-release turbolinux-release zenwalk-version);
+ my $derived_str = join('|', @derived);
my @primary = qw(altlinux-release arch-release gentoo-release redhat-release
slackware-version SuSE-release);
- my $primary_s = join('|', @primary);
- my $exclude_s = 'debian_version|devuan_version|ubuntu_version';
+ my $primary_str = join('|', @primary);
+ my $exclude_str = 'debian_version|devuan_version|ubuntu_version';
# note, pclinuxos has all these mandrake/mandriva files, careful!
- my $lsb_good_s = 'mandrake-release|mandriva-release|mandrakelinux-release|';
- $lsb_good_s .= 'manjaro-release';
- my $os_release_good_s = 'altlinux-release|arch-release|mageia-release|';
- $os_release_good_s .= 'pclinuxos-release|rpi-issue|SuSE-release';
- # we need these empirically verified one by one as they appear, but always remember
+ my $lsb_good_str = 'mandrake-release|mandriva-release|mandrakelinux-release|';
+ $lsb_good_str .= 'manjaro-release';
+ my $osr_good_str = 'altlinux-release|arch-release|mageia-release|';
+ $osr_good_str .= 'pclinuxos-release|rpi-issue|SuSE-release';
+ # We need these empirically verified one by one as they appear, but always remember
# that stuff changes, legacy, deprecated, but these ideally are going to be right
- my $osr_good = 'manjaro|antergos|chakra|guix|mageia|pclinuxos|raspberry pi os|';
- $osr_good .= 'slint|zorin';
- # force use of pretty name because that's only location of derived distro name
- my $osr_pretty = 'zinc';
- my ($b_issue,$b_lsb,$b_osr_pretty,$b_skip_issue,$b_skip_osr);
+ my $osr_good = 'antergos|chakra|fedora|guix|mageia|manjaro|oracle|pclinuxos|';
+ $osr_good .= 'porteux|raspberry pi os|slint|zorin';
+ # Force use of pretty name because that's only location of derived distro name
+ # devuan should catch many devuans spins, which often put their names in pretty
+ my $osr_pretty = 'devuan|slackel|zinc';
+ my $dist_file_no_name = 'slitaz'; # these may not have the distro name in the file
my ($issue,$lsb_release) = ('/etc/issue','/etc/lsb-release');
- $b_issue = 1 if -f $issue;
- $b_lsb = 1 if -f $lsb_release;
- # note: OpenSuse Tumbleweed 2018-05 has made /etc/issue created by sym link to /run/issue
+ # Note: OpenSuse Tumbleweed 2018-05 has made /etc/issue created by sym link to /run/issue
# and then made that resulting file 700 permissions, which is obviously a mistake
$etc_issue = main::reader($issue,'strip',0) if -r $issue;
# debian issue can end with weird escapes like \n \l
# antergos: Antergos Linux \r (\l)
$etc_issue = main::clean_characters($etc_issue) if $etc_issue;
- # note: always exceptions, so wild card after release/version:
+ # Note: always exceptions, so wild card after release/version:
# /etc/lsb-release-crunchbang
- # wait to handle since crunchbang file is one of the few in the world that
+ # Wait to handle since crunchbang file is one of the few in the world that
# uses this method
- @distro_files = main::globber('/etc/*[-_]{[rR]elease,[vV]ersion,issue}*');
- push(@distro_files, '/etc/bodhibuilder.conf') if -r '/etc/bodhibuilder.conf';
+ @{$distro->{'files'}} = main::globber('/etc/{*[-_]{[rR]elease,[vV]ersion}*,issue}');
+ push(@{$distro->{'files'}}, '/etc/bodhibuilder.conf') if -r '/etc/bodhibuilder.conf'; # legacy
@osr = main::reader($os_release) if -r $os_release;
- if ($etc_issue){
+ if (-f '/etc/bodhi/info'){
+ $lsb_release = '/etc/bodhi/info';
+ $distro->{'file'} = $lsb_release;
+ $distro->{'issue-skip'} = 1;
+ push(@{$distro->{'files'}}, $lsb_release);
+ }
+ $distro->{'issue'} = $issue if -f $issue;
+ $distro->{'lsb'} = $lsb_release if -f $lsb_release;
+ if (!$distro->{'issue-skip'} && $etc_issue){
$lc_issue = lc($etc_issue);
if ($lc_issue =~ /(antergos|grml|linux lite|openmediavault)/){
- $distro_id = $1;
- $b_skip_issue = 1;
+ $distro->{'id'} = $1;
+ $distro->{'issue-skip'} = 1;
}
- # this raspbian detection fails for raspberry pi os
+ # This raspbian detection fails for raspberry pi os
elsif ($lc_issue =~ /(raspbian|peppermint)/){
- $distro_id = $1;
- $distro_file = $os_release if @osr;
+ $distro->{'id'} = $1;
+ $distro->{'file'} = $os_release if @osr;
}
- # note: wrong fix, applies to both raspbian and raspberry pi os
+ # Note: wrong fix, applies to both raspbian and raspberry pi os
# assumption here is that r pi os fixes this before stable release
elsif ($lc_issue =~ /^debian/ && -e '/etc/apt/sources.list.d/raspi.list' &&
(grep {/[^#]+raspberrypi\.org/} main::reader('/etc/apt/sources.list.d/raspi.list'))){
- $distro_id = 'raspios' ;
+ $distro->{'id'} = 'raspios' ;
}
}
# Note that antergos changed this around # 2018-05, and now lists
@@ -28440,340 +31619,424 @@ sub get_linux_distro {
# if it contains their names. Last check below
if (@osr){
if (grep {/($osr_good)/i} @osr){
- $distro_file = $os_release;
+ $distro->{'file'} = $os_release;
}
elsif (grep {/($osr_pretty)/i} @osr){
- $b_osr_pretty = 1;
+ $distro->{'osr-pretty'} = 1;
+ $distro->{'file'} = $os_release;
}
}
- if (grep {/armbian/} @distro_files){
- $distro_id = 'armbian' ;
+ if (grep {/armbian/} @{$distro->{'files'}}){
+ $distro->{'id'} = 'armbian' ;
}
- main::log_data('dump','@distro_files',\@distro_files) if $b_log;
- main::log_data('data',"distro_file-1: $distro_file") if $b_log;
- if (!$distro_file){
- if (scalar @distro_files == 1){
- $distro_file = $distro_files[0];
+ $distro->{'file-for-0'} = $distro->{'file'};
+ dbg_distro_files('Linux',$distro->{'files'}) if $distro->{'dbg'};
+ if (!$distro->{'file'}){
+ if (scalar @{$distro->{'files'}} == 1){
+ $distro->{'file'} = $distro->{'files'}[0];
}
- elsif (scalar @distro_files > 1){
- # special case, to force manjaro/antergos which also have arch-release
+ elsif (scalar @{$distro->{'files'}} > 1){
+ # Special case, to force manjaro/antergos which also have arch-release
# manjaro should use lsb, which has the full info, arch uses os release
# antergos should use /etc/issue. We've already checked os-release above
- if ($distro_id eq 'antergos' || (grep {/antergos|chakra|manjaro/} @distro_files)){
- @distro_files = grep {!/arch-release/} @distro_files;
+ if ($distro->{'id'} eq 'antergos' || (grep {/antergos|chakra|manjaro/} @{$distro->{'files'}})){
+ @{$distro->{'files'}} = grep {!/arch-release/} @{$distro->{'files'}};
}
- my $distro_files_s = join('|', @distro_files);
- @working = (@derived,@primary);
- foreach my $file (@working){
- if ("/etc/$file" =~ /($distro_files_s)$/){
+ my $dist_files_str = join('|', @{$distro->{'files'}});
+ foreach my $file ((@derived,@primary)){
+ if ("/etc/$file" =~ /($dist_files_str)$/){
# These is for only those distro's with self named release/version files
# because Mint does not use such, it must be done as below
# Force use of os-release file in cases where there might be conflict
# between lsb-release rules and os-release priorities.
- if (@osr && $file =~ /($os_release_good_s)$/){
- $distro_file = $os_release;
+ if (@osr && $file =~ /($osr_good_str)$/){
+ $distro->{'file'} = $os_release;
}
# Now lets see if the distro file is in the known-good working-lsb-list
# if so, use lsb-release, if not, then just use the found file
- elsif ($b_lsb && $file =~ /$lsb_good_s/){
- $distro_file = $lsb_release;
+ elsif ($distro->{'lsb'} && $file =~ /$lsb_good_str/){
+ $distro->{'file'} = $lsb_release;
}
else {
- $distro_file = "/etc/$file";
+ $distro->{'file'} = "/etc/$file";
}
last;
}
}
}
}
- main::log_data('data',"distro_file-2: $distro_file") if $b_log;
+ $distro->{'file-for-1'} = $distro->{'file'};
# first test for the legacy antiX distro id file
if (-r '/etc/antiX'){
@working = main::reader('/etc/antiX');
- $distro = main::awk(\@working,'antix.*\.iso') if @working;
- $distro = main::clean_characters($distro) if $distro;
+ $distro->{'name'} = main::awk(\@working,'antix.*\.iso') if @working;
+ $distro->{'name'} = main::clean_characters($distro->{'name'}) if $distro->{'name'};
+ push(@{$distro->{'method'}},'file: /etc/antiX');
}
- # this handles case where only one release/version file was found, and it's lsb-release.
+ # This handles case where only one release/version file was found, and it's lsb-release.
# This would never apply for ubuntu or debian, which will filter down to the following
# conditions. In general if there's a specific distro release file available, that's to
# be preferred, but this is a good backup.
- elsif ($distro_file && $b_lsb && ($distro_file =~ /\/etc\/($lsb_good_s)$/ || $distro_file eq $lsb_release)){
- $distro = get_lsb_release();
- }
- elsif ($distro_file && $distro_file eq $os_release){
- $distro = get_os_release($b_osr_pretty);
- $b_skip_osr = 1;
- }
- # if distro id file was found and it's not in the exluded primary distro file list, read it
- elsif ($distro_file && -s $distro_file && $distro_file !~ /\/etc\/($exclude_s)$/){
- # new opensuse uses os-release, but older ones may have a similar syntax, so just use
+ elsif ($distro->{'file'} && $distro->{'lsb'} &&
+ ($distro->{'file'} =~ /\/etc\/($lsb_good_str)$/ || $distro->{'file'} eq $lsb_release)){
+ # print "df: $distro->{'file'} lf: $lsb_release\n";
+ $distro->{'name'} = get_lsb($lsb_release);
+ push(@{$distro->{'method'}},'get_lsb(): primary');
+ }
+ elsif ($distro->{'file'} && $distro->{'file'} eq $os_release){
+ $distro->{'name'} = get_osr();
+ $distro->{'osr-skip'} = 1;
+ push(@{$distro->{'method'}},'get_osr(): primary');
+ }
+ # If distro id file was found and it's not in the exluded primary distro file list, read it
+ elsif ($distro->{'file'} && -s $distro->{'file'} && $distro->{'file'} !~ /\/etc\/($exclude_str)$/){
+ # New opensuse uses os-release, but older ones may have a similar syntax, so just use
# the first line
- if ($distro_file eq '/etc/SuSE-release'){
- # leaving off extra data since all new suse have it, in os-release, this file has
+ if ($distro->{'file'} eq '/etc/SuSE-release'){
+ # Leaving off extra data since all new suse have it, in os-release, this file has
# line breaks, like os-release but in case we want it, it's:
# CODENAME = Mantis | VERSION = 12.2
- # for now, just take first occurrence, which should be the first line, which does
+ # For now, just take first occurrence, which should be the first line, which does
# not use a variable type format
- @working = main::reader($distro_file);
- $distro = main::awk(\@working,'suse');
+ @working = main::reader($distro->{'file'});
+ $distro->{'name'} = main::awk(\@working,'suse');
+ push(@{$distro->{'method'}}, 'custom: suse-release');
}
- elsif ($distro_file eq '/etc/bodhibuilder.conf'){
- @working = main::reader($distro_file);
- $distro = main::awk(\@working,'^LIVECDLABEL',2,'\s*=\s*');
- $distro =~ s/"//g if $distro;
+ elsif ($distro->{'file'} eq '/etc/bodhibuilder.conf'){
+ @working = main::reader($distro->{'file'});
+ $distro->{'name'} = main::awk(\@working,'^LIVECDLABEL',2,'\s*=\s*');
+ $distro->{'name'} =~ s/"//g if $distro->{'name'};
+ push(@{$distro->{'method'}},'custom: /etc/bodhibuilder');
}
else {
- $distro = main::reader($distro_file,'',0);
+ $distro->{'name'} = main::reader($distro->{'file'},'',0);
# only contains version number. Why? who knows.
- if ($distro_file eq '/etc/q4os_version' && $distro !~ /q4os/i){
- $distro = "Q4OS $distro" ;
+ if ($distro->{'file'} eq '/etc/q4os_version' && $distro->{'name'} !~ /q4os/i){
+ $distro->{'name'} = "Q4OS $distro->{'name'}" ;
}
+ push(@{$distro->{'method'}},'default: distro file');
+ }
+ if ($distro->{'name'}){
+ $distro->{'name'} = main::clean_characters($distro->{'name'});
}
- $distro = main::clean_characters($distro) if $distro;
}
- # otherwise try the default debian/ubuntu/distro /etc/issue file
- elsif ($b_issue){
- if (!$distro_id && $lc_issue && $lc_issue =~ /(mint|lmde)/){
- $distro_id = $1;
- $b_skip_issue = 1;
+ # Otherwise try the default debian/ubuntu/distro /etc/issue file
+ elsif ($distro->{'issue'}){
+ if (!$distro->{'id'} && $lc_issue && $lc_issue =~ /(mint|lmde)/){
+ $distro->{'id'} = $1;
+ $distro->{'issue-skip'} = 1;
}
# os-release/lsb gives more manageable and accurate output than issue,
# but mint should use issue for now. Antergos uses arch os-release, but issue shows them
- if (!$b_skip_issue && @osr){
- $distro = get_os_release($b_osr_pretty);
- $b_skip_osr = 1;
+ if (!$distro->{'issue-skip'} && @osr){
+ $distro->{'name'} = get_osr();
+ $distro->{'osr-skip'} = 1;
+ push(@{$distro->{'method'}},'get_osr(): w/issue');
}
- elsif (!$b_skip_issue && $b_lsb){
- $distro = get_lsb_release();
+ elsif (!$distro->{'issue-skip'} && $distro->{'lsb'}){
+ $distro->{'name'} = get_lsb();
+ push(@{$distro->{'method'}},'get_lsb(): w/issue');
}
elsif ($etc_issue){
if (-d '/etc/guix' && $lc_issue =~ /^this is the gnu system\./){
- $distro = 'Guix';
- # they didn't use any standard paths or files for os data, sigh, use pm version
- my $version = main::program_version('guix', '^guix', '4','--version',1);
- $distro .= " $version" if $version;
- $b_skip_issue = 1;
+ # No standard paths or files for os data, use pm version
+ ($distro->{'name'},my $version) = ProgramData::full('guix');
+ $distro->{'name'} .= " $version" if $version;
+ $distro->{'issue-skip'} = 1;
+ push(@{$distro->{'method'}},'issue-id; from program version');
}
else {
- $distro = $etc_issue;
- # this handles an arch bug where /etc/arch-release is empty and /etc/issue
+ $distro->{'name'} = $etc_issue;
+ push(@{$distro->{'method'}},'issue: source');
+ # This handles an arch bug where /etc/arch-release is empty and /etc/issue
# is corrupted only older arch installs that have not been updated should
# have this fallback required, new ones use os-release
- if ($distro =~ /arch linux/i){
- $distro = 'Arch Linux';
+ if ($distro->{'name'} =~ /arch linux/i){
+ $distro->{'name'} = 'Arch Linux';
}
}
}
}
- # a final check. If a long value, before assigning the debugger output, if os-release
+ # A final check. If a long value, before assigning the debugger output, if os-release
# exists then let's use that if it wasn't tried already. Maybe that will be better.
# not handling the corrupt data, maybe later if needed. 10 + distro: (8) + string
- if ($distro && length($distro) > 60){
- if (!$b_skip_osr && @osr){
- $distro = get_os_release($b_osr_pretty);
- $b_skip_osr = 1;
+ if ($distro->{'name'} && length($distro->{'name'}) > 60){
+ if (!$distro->{'osr-skip'} && @osr){
+ $distro->{'name'} = get_osr();
+ $distro->{'osr-skip'} = 1;
+ push(@{$distro->{'method'}},'get_osr(): bad name');
}
}
- # test for /etc/lsb-release as a backup in case of failure, in cases
+ # Test for /etc/lsb-release as a backup in case of failure, in cases
# where > one version/release file were found but the above resulted
# in null distro value.
- if (!$distro && $windows{'cygwin'}){
- $distro = $uname[0]; # like so: CYGWIN_NT-10.0-19043
- $b_skip_osr = 1;
+ if (!$distro->{'name'} && $windows{'cygwin'}){
+ $distro->{'name'} = $uname[0]; # like so: CYGWIN_NT-10.0-19043
+ $distro->{'osr-skip'} = 1;
+ push(@{$distro->{'method'}},'uname 0: cygwin');
}
- if (!$distro){
- if (!$b_skip_osr && @osr){
- $distro = get_os_release($b_osr_pretty);
- $b_skip_osr = 1;
+ if (!$distro->{'name'}){
+ if (!$distro->{'osr-skip'} && @osr){
+ $distro->{'name'} = get_osr();
+ $distro->{'osr-skip'} = 1;
+ push(@{$distro->{'method'}},'get_osr(): final');
}
- elsif ($b_lsb){
- $distro = get_lsb_release();
+ elsif ($distro->{'lsb'}){
+ $distro->{'name'} = get_lsb();
+ push(@{$distro->{'method'}},'get_lsb(): final');
}
}
- # now some final null tries
- if (!$distro){
- # if the file was null but present, which can happen in some cases, then use
+ # Now some final null tries
+ if (!$distro->{'name'}){
+ # If the file was null but present, which can happen in some cases, then use
# the file name itself to set the distro value. Why say unknown if we have
# a pretty good idea, after all?
- if ($distro_file){
- $distro_file =~ s/\/etc\/|[-_]|release|version//g;
- $distro = $distro_file;
+ if ($distro->{'file'}){
+ $distro->{'file'} =~ s/\/etc\/|[-_]|release|version//g;
+ $distro->{'name'} = $distro->{'file'};
+ push(@{$distro->{'method'}},'use: distro file name');
+ }
+ }
+ main::feature_debugger('name: $distro: pre-base [linux]',$distro) if $distro->{'dbg'};
+ system_base_linux() if $extra > 0;
+ # Some last customized changes, double check if possible to verify still valid
+ if ($distro->{'name'}){
+ if ($distro->{'id'} eq 'armbian'){
+ $distro->{'name'} =~ s/Debian/Armbian/;
+ push(@{$distro->{'method'}},'custom: armbian name adjust');
+ }
+ elsif ($distro->{'id'} eq 'raspios'){
+ $distro->{'base'} = $distro->{'name'};
+ push(@{$distro->{'base-method'}},'custom: pi base from name');
+ # No need to repeat the debian version info if base:
+ if ($extra == 0){
+ $distro->{'name'} =~ s/Debian\s*GNU\/Linux/Raspberry Pi OS/;
+ }
+ else {
+ $distro->{'name'} = 'Raspberry Pi OS';
+ }
+ push(@{$distro->{'method'}},'custom: pi name adjust');
}
- }
- system_base() if $extra > 0;
- # some last customized changes, double check if possible to verify still valid
- if ($distro){
- if ($distro_id eq 'armbian'){
- $distro =~ s/Debian/Armbian/;
+ # check for spins, relies on xdg directory name
+ elsif ($distro->{'name'} =~ /^(Ubuntu)/i){
+ my $base = $1;
+ my $temp = distro_spin($distro->{'name'});
+ if ($temp ne $distro->{'name'}){
+ if (!$distro->{'base'} && $extra > 0){
+ $distro->{'base'} = $base;
+ push(@{$distro->{'base-method'}},'use: name');
+ }
+ $distro->{'name'} = $temp;
+ push(@{$distro->{'method'}},'use: distro_spin()');
+ }
}
- elsif ($distro_id eq 'raspios'){
- $system_base = $distro;
- # no need to repeat the debian version info if base:
- if ($extra == 0){$distro =~ s/Debian\s*GNU\/Linux/Raspberry Pi OS/;}
- else {$distro = 'Raspberry Pi OS';}
+ elsif (-d '/etc/salixtools/' && $distro->{'name'} =~ /Slackware/i){
+ $distro->{'name'} =~ s/Slackware/Salix/;
+ push(@{$distro->{'method'}},'manual: name swap');
}
- elsif (-d '/etc/salixtools/' && $distro =~ /Slackware/i){
- $distro =~ s/Slackware/Salix/;
+ elsif ($distro->{'file'} =~ /($dist_file_no_name)/ && $distro->{'name'} =~ /^[\d\.]+$/){
+ $distro->{'file'} =~ s/\/etc\/|[-_]|release|version//g;
+ $distro->{'name'} = ucfirst($distro->{'file'}) . ' ' . $distro->{'name'};
+ push(@{$distro->{'method'}},'use: file name');
}
}
else {
# android fallback, sometimes requires root, sometimes doesn't
android_info() if $b_android;
}
- ## finally, if all else has failed, give up
- $distro ||= 'unknown';
+ ## Finally, if all else has failed, give up
+ $distro->{'name'} ||= 'unknown';
+ if ($extra > 0 && $distro->{'name'} && $distro->{'base'}){
+ check_base();
+ }
+ main::feature_debugger('name: $distro: final [linux]',$distro) if $distro->{'dbg'};
eval $end if $b_log;
}
sub android_info {
eval $start if $b_log;
main::set_build_prop() if !$loaded{'build-prop'};;
- $distro = 'Android';
- $distro .= ' ' . $build_prop{'build-version'} if $build_prop{'build-version'};
- $distro .= ' ' . $build_prop{'build-date'} if $build_prop{'build-date'};
+ $distro->{'name'} = 'Android';
+ $distro->{'name'} .= ' ' . $build_prop{'build-version'} if $build_prop{'build-version'};
+ $distro->{'name'} .= ' ' . $build_prop{'build-date'} if $build_prop{'build-date'};
if (!$show{'machine'}){
if ($build_prop{'product-manufacturer'} && $build_prop{'product-model'}){
- $distro .= ' (' . $build_prop{'product-manufacturer'} . ' ' . $build_prop{'product-model'} . ')';
+ $distro->{'name'} .= ' (' . $build_prop{'product-manufacturer'} . ' ' . $build_prop{'product-model'} . ')';
}
elsif ($build_prop{'product-device'}){
- $distro .= ' (' . $build_prop{'product-device'} . ')';
+ $distro->{'name'} .= ' (' . $build_prop{'product-device'} . ')';
}
elsif ($build_prop{'product-name'}){
- $distro .= ' (' . $build_prop{'product-name'} . ')';
+ $distro->{'name'} .= ' (' . $build_prop{'product-name'} . ')';
}
}
eval $end if $b_log;
}
-sub system_base_bsd {
- eval $start if $b_log;
- # ghostbsd is handled in main bsd section
- if (lc($uname[1]) eq 'nomadbsd' && $distro_id eq 'freebsd'){
- $system_base = $distro;
- $distro = $uname[1];
- }
- elsif (-f '/etc/pkg/HardenedBSD.conf' && $distro_id eq 'freebsd'){
- $system_base = $distro;
- $distro = 'HardenedBSD';
- }
- elsif ($distro_id =~ /^(truenas)$/){
- $system_base = "$uname[0] $uname[2]";
- }
- eval $end if $b_log;
-}
-
-sub system_base {
+sub system_base_linux {
eval $start if $b_log;
- my $base_distro_arch = 'anarchy|antergos|arch(bang|craft|labs|man|strike)|arco|artix';
+ $distro->{'osr-pretty'} = 0; # reset: if we want to use osr pretty, detect here.
+ # Need data on these Arch derived: CachyOS; can be ArchLab/Labs
+ my $base_distro_arch = 'anarchy|antergos|apricity';
+ $base_distro_arch .= '|arch(bang|craft|ex|lab|man|strike)|arco|artix';
+ $base_distro_arch .= '|blackarch|bluestar|bridge|cachyos|chakra|condres|ctlos';
# note: arch linux derived distro page claims kaos as arch derived but it is NOT
- $base_distro_arch .= '|blackarch|bluestar|chakra|ctios|endeavour|garuda|hyperbola|linhes';
- $base_distro_arch .= '|mabox|manjaro|mysys2|netrunner\s?rolling|ninja|obarun|parabola';
- $base_distro_arch .= '|puppyrus-?a|reborn|snal|steamos|talkingarch|ubos';
+ $base_distro_arch .= '|endeavour|feliz|garuda|hyperbola|linhes|liri';
+ $base_distro_arch .= '|mabox|magpie|manjaro|mysys2|namib|netrunner\s?rolling|ninja';
+ $base_distro_arch .= '|obarun|parabola|porteus|puppyrus-?a';
+ $base_distro_arch .= '|reborn|revenge|salient|snal|steamos';
+ $base_distro_arch .= '|talkingarch|theshell|ubos|velt|xero';
my $base_file_debian_version = 'sidux';
# detect debian steamos before arch steamos
- my $base_osr_debian_version = '\belive|lmde|neptune|parrot|pureos|rescatux|';
- $base_osr_debian_version .= 'septor|sparky|steamos|tails';
+ my $base_osr_debian_version = '\belive|lmde|neptune|nitrux|parrot|pureos|';
+ $base_osr_debian_version .= 'rescatux|septor|sparky|steamos|tails';
+ my $base_osr_devuan_version = 'crowz|dowse|etertics|\bexe\b|fluxuan|gnuinos|';
+ $base_osr_devuan_version .= 'gobmis|heads|miyo|refracta|\bstar\b|virage';
# osr has base ids
- my $base_default = 'antix-version|mx-version';
+ my $base_default = 'antix-version|bodhi|mx-version';
# base only found in issue
my $base_issue = 'bunsen';
# synthesize, no direct data available
my $base_manual = 'blankon|deepin|kali';
# osr base, distro id in list of distro files
- my $base_osr = 'aptosid|bodhi|grml|q4os|siduction|slax';
+ my $base_osr = 'aptosid|bodhi|grml|q4os|siduction|slax|zenwalk';
# osr base, distro id in issue
my $base_osr_issue = 'grml|linux lite|openmediavault';
+ # same as rhel re VERSION_ID but likely only ID_LIKE=fedora
+ my $base_osr_fedora = 'amahi|asahi|audinux|clearos|fx64|montana|nobara|qubes|';
+ $base_osr_fedora .= 'risios|ultramarine|vortexbox';
# osr has distro name but has fedora centos redhat ID_LIKE and VERSION_ID same
- my $base_osr_redhat = 'almalinux|centos|rocky';
- # osr has distro name but has ubuntu ID_LIKE/UBUNTU_CODENAME
- my $base_osr_ubuntu = 'mint|neon|nitrux|pop!_os|tuxedo|zinc|zorin';
+ # fedora not handled will fall to RHEL if contains centos string
+ my $base_osr_redhat = 'almalinux|centos|eurolinux|oracle|puias|rocky|';
+ $base_osr_redhat .= 'scientific|springdale';
+ # osr has distro name but has ubuntu (or debian) ID_LIKE/UBUNTU_CODENAME
+ my $base_osr_ubuntu = 'feren|mint|neon|nitrux|pop!?_os|tuxedo|zinc|zorin';
my $base_upstream_lsb = '/etc/upstream-release/lsb-release';
my $base_upstream_osr = '/etc/upstream-release/os-release';
- # these id as themselves, but system base is version file
+ # These id as themselves, but system base is version file. Slackware mostly.
my %base_version = (
- 'salix|slint' => '/etc/slackware-version',
+ 'porteux|salix|slackel|slint' => '/etc/slackware-version',
);
- # first: try, some distros have upstream-release, elementary, new mint
+ # First: try, some distros have upstream-release, elementary, new mint
# and anyone else who uses this method for fallback ID
if (-r $base_upstream_osr){
my @osr_working = main::reader($base_upstream_osr);
+ push(@{$distro->{'base-files'}},$base_upstream_osr) if $distro->{'dbg'};
if (@osr_working){
- my (@osr_temp);
- @osr_temp = @osr;
+ my @osr_temp = @osr;
@osr = @osr_working;
- $system_base = get_os_release();
- @osr = @osr_temp if !$system_base;
- (@osr_temp,@osr_working) = ();
+ $distro->{'base'} = get_osr();
+ @osr = @osr_temp if !$distro->{'base'};
+ push(@{$distro->{'base-method'}},'get_osr(): upstream osr');
}
}
+ # note: ultramarine trips this one but uses os-release field names, sigh, ignore
elsif (-r $base_upstream_lsb){
- $system_base = get_lsb_release($base_upstream_lsb);
+ $distro->{'base'} = get_lsb($base_upstream_lsb);
+ push(@{$distro->{'base-files'}},$base_upstream_lsb) if $distro->{'dbg'};
+ push(@{$distro->{'base-method'}},'get_lsb(): upstream lsb');
}
- # probably no need for these @osr greps, just grep $distro instead?
- if (!$system_base && @osr){
- my ($base_type) = ('');
+ dbg_distro_files('Linux base',$distro->{'base-files'}) if $distro->{'dbg'};
+ # probably no need for these @osr greps, just grep $distro->{'name'} instead?
+ if (!$distro->{'base'} && @osr){
if ($etc_issue && (grep {/($base_issue)/i} @osr)){
- $system_base = $etc_issue;
+ $distro->{'base'} = $etc_issue;
+ push(@{$distro->{'base-method'}},'file: /etc/issue');
}
# more tests added here for other ubuntu derived distros
- elsif (@distro_files && (grep {/($base_default)/} @distro_files)){
- $base_type = 'default';
+ elsif (@{$distro->{'files'}} && (grep {/($base_default)/} @{$distro->{'files'}})){
+ $distro->{'base-type'} = 'default';
}
# must go before base_osr_arch,ubuntu tests. For steamos, use fallback arch
elsif (grep {/($base_osr_debian_version)/i} @osr){
- $system_base = debian_id();
+ $distro->{'base'} = debian_id('debian');
+ push(@{$distro->{'base-method'}},'use: debian_id(debian)');
+ }
+ elsif (grep {/($base_osr_devuan_version)/i} @osr){
+ $distro->{'base'} = debian_id('devuan');
+ push(@{$distro->{'base-method'}},'use: debian_id(devuan)');
+ }
+ elsif (grep {/($base_osr_fedora)/i} @osr){
+ $distro->{'base-type'} = 'fedora';
}
elsif (grep {/($base_osr_redhat)/i} @osr){
- $base_type = 'rhel';
+ $distro->{'base-type'} = 'rhel';
}
elsif (grep {/($base_osr_ubuntu)/i} @osr){
- $base_type = 'ubuntu';
+ $distro->{'base-type'} = 'ubuntu';
}
- elsif ((($distro_id && $distro_id =~ /($base_osr_issue)/) ||
- (@distro_files && (grep {/($base_osr)/} @distro_files))) &&
+ elsif ((($distro->{'id'} && $distro->{'id'} =~ /($base_osr_issue)/) ||
+ (@{$distro->{'files'}} && (grep {/($base_osr)/} @{$distro->{'files'}}))) &&
!(grep {/($base_osr)/i} @osr)){
- $system_base = get_os_release();
+ $distro->{'base'} = get_osr();
+ push(@{$distro->{'base-method'}},'get_osr(): issue match');
}
- if (!$system_base && $base_type){
- $system_base = get_os_release('',$base_type);
+ if (!$distro->{'base'} && $distro->{'base-type'}){
+ $distro->{'base'} = get_osr($distro->{'base-type'});
+ push(@{$distro->{'base-method'}},'get_osr(): base-type');
}
}
- if (!$system_base && @distro_files &&
- (grep {/($base_file_debian_version)/i} @distro_files)){
- $system_base = debian_id();
+ if (!$distro->{'base'} && @{$distro->{'files'}} &&
+ (grep {/($base_file_debian_version)/i} @{$distro->{'files'}})){
+ $distro->{'base'} = debian_id('debian');
+ push(@{$distro->{'base-method'}},'debian_id(debian): base_file_debian_version');
}
- if (!$system_base && $lc_issue && $lc_issue =~ /($base_manual)/){
+ if (!$distro->{'base'} && $lc_issue && $lc_issue =~ /($base_manual)/){
my $id = $1;
my %manual = (
'blankon' => 'Debian unstable',
'deepin' => 'Debian unstable',
'kali' => 'Debian testing',
);
- $system_base = $manual{$id};
+ $distro->{'base'} = $manual{$id};
+ push(@{$distro->{'base-method'}},'manual: /etc/issue match');
}
- if (!$system_base && $distro && $distro =~ /^($base_distro_arch)/i){
- $system_base = 'Arch Linux';
+ if (!$distro->{'base'} && $distro->{'name'}){
+ if ($distro->{'name'} =~ /^($base_distro_arch)/i){
+ $distro->{'base'} = 'Arch Linux';
+ push(@{$distro->{'base-method'}},'name-match: assign arch');
+ }
+ elsif ($distro->{'name'} =~ /^peppermint/i){
+ my $type = (-f '/etc/devuan_version') ? 'devuan': 'debian';
+ $distro->{'base'} = debian_id($type);
+ push(@{$distro->{'base-method'}},'debian_id(): type');
+ }
}
- if (!$system_base && $distro){
+ if (!$distro->{'base'} && $distro->{'name'}){
foreach my $key (keys %base_version){
- if (-r $base_version{$key} && $distro =~ /($key)/i){
- $system_base = main::reader($base_version{$key},'strip',0);
- $system_base = main::clean_characters($system_base) if $system_base;
+ if (-r $base_version{$key} && $distro->{'name'} =~ /($key)/i){
+ $distro->{'base'} = main::reader($base_version{$key},'strip',0);
+ $distro->{'base'} = main::clean_characters($distro->{'base'}) if $distro->{'base'};
+ push(@{$distro->{'base-method'}},"base_version: file: $key");
last;
}
}
}
- if (!$system_base && $distro && -d '/etc/salixtools/' && $distro =~ /Slackware/i){
- $system_base = $distro;
+ if (!$distro->{'base'} && $distro->{'name'} && -d '/etc/salixtools/' &&
+ $distro->{'name'} =~ /Slackware/i){
+ $distro->{'base'} = $distro->{'name'};
+ push(@{$distro->{'base-method'}},'custom: salix');
}
+ main::feature_debugger('$distro: base [linux]',$distro) if $distro->{'dbg'};
eval $end if $b_log;
}
-sub get_lsb_release {
+## PROCESS OS/LSB RELEASE ##
+# Note: corner case when parsing the bodhi distro file
+# args: 0: file name
+sub get_lsb {
eval $start if $b_log;
my ($lsb_file) = @_;
$lsb_file ||= '/etc/lsb-release';
- my ($distro,$id,$release,$codename,$description) = ('','','','','');
+ my ($dist_lsb,$id,$release,$codename,$description) = ('','','','','');
+ my ($dist_id,$dist_release,$dist_code,$dist_desc) = ('DISTRIB_ID',
+ 'DISTRIB_RELEASE','DISTRIB_CODENAME','DISTRIB_DESCRIPTION');
+ if ($lsb_file eq '/etc/bodhi/info'){
+ $id = 'Bodhi Linux';
+ # note: No ID field, hard code
+ ($dist_id,$dist_release,$dist_code,$dist_desc) = ('ID','RELEASE',
+ 'CODENAME','DESCRIPTION');
+ }
my @content = main::reader($lsb_file);
main::log_data('dump','@content',\@content) if $b_log;
@content = map {s/,|\*|\\||\"|[:\47]|^\s+|\s+$|n\/a//ig; $_} @content if @content;
@@ -28781,53 +32044,53 @@ sub get_lsb_release {
next if /^\s*$/;
my @working = split(/\s*=\s*/, $_);
next if !$working[0];
- if ($working[0] eq 'DISTRIB_ID' && $working[1]){
+ if ($working[0] eq $dist_id && $working[1]){
if ($working[1] =~ /^Manjaro/i){
$id = 'Manjaro Linux';
}
# in the old days, arch used lsb_release
-# elsif ($working[1] =~ /^Arch$/i){
-# $id = 'Arch Linux';
-# }
+ # elsif ($working[1] =~ /^Arch$/i){
+ # $id = 'Arch Linux';
+ # }
else {
$id = $working[1];
}
}
- elsif ($working[0] eq 'DISTRIB_RELEASE' && $working[1]){
+ elsif ($working[0] eq $dist_release && $working[1]){
$release = $working[1];
}
- elsif ($working[0] eq 'DISTRIB_CODENAME' && $working[1]){
+ elsif ($working[0] eq $dist_code && $working[1]){
$codename = $working[1];
}
# sometimes some distros cannot do their lsb-release files correctly,
# so here is one last chance to get it right.
- elsif ($working[0] eq 'DISTRIB_DESCRIPTION' && $working[1]){
+ elsif ($working[0] eq $dist_desc && $working[1]){
$description = $working[1];
}
}
if (!$id && !$release && !$codename && $description){
- $distro = $description;
+ $dist_lsb = $description;
}
else {
# avoid duplicates
- $distro = $id;
- $distro .= " $release" if $release && $distro !~ /$release/;
+ $dist_lsb = $id;
+ $dist_lsb .= " $release" if $release && $dist_lsb !~ /$release/;
# eg: release: 9 codename: mga9
- if ($codename && $distro !~ /$codename/i &&
+ if ($codename && $dist_lsb !~ /$codename/i &&
(!$release || $codename !~ /$release/)){
- $distro .= " $codename";
+ $dist_lsb .= " $codename";
}
- $distro =~ s/^\s+|\s\s+|\s+$//g; # get rid of double and trailing spaces
+ $dist_lsb =~ s/^\s+|\s\s+|\s+$//g; # get rid of double and trailing spaces
}
eval $end if $b_log;
- return $distro;
+ return $dist_lsb;
}
-sub get_os_release {
+
+sub get_osr {
eval $start if $b_log;
- my ($b_osr_pretty,$base_type) = @_;
- my ($base_id,$base_name,$base_version,$distro,$distro_name,
- $name,$name_lc,$name_pretty,
- $version_codename,$version_name,$version_id) = ('','','','','','','','','','','');
+ my ($base_type) = @_;
+ my ($base_id,$base_name,$base_version,$dist_osr,$name,$name_lc,$name_pretty,
+ $version_codename,$version_name,$version_id) = ('','','','','','','','','','');
my @content = @osr;
main::log_data('dump','@content',\@content) if $b_log;
@content = map {s/\\||\"|[:\47]|^\s+|\s+$|n\/a//ig; $_} @content if @content;
@@ -28856,11 +32119,16 @@ sub get_os_release {
if ($base_type){
if ($working[0] eq 'ID_LIKE' && $working[1]){
if ($base_type eq 'ubuntu'){
- # popos shows debian
+ # feren,popos shows debian, feren ID ubuntu
$working[1] =~ s/^(debian|ubuntu\sdebian|debian\subuntu)/ubuntu/;
- $working[1] = 'ubuntu' if $working[1] eq 'debian';
+ $base_name = ucfirst($working[1]);
+ }
+ elsif ($base_type eq 'fedora' && $working[1] =~ /fedora/i){
+ $base_name = 'Fedora';
+ $base_version = $version_id if $version_id;
}
- if ($base_type eq 'rhel' && $working[1] =~ /$base_type/i){
+ # oracle ID_LIKE="fedora". Why? who knows.
+ elsif ($base_type eq 'rhel' && $working[1] =~ /rhel|fedora/i){
$base_name = 'RHEL';
$base_version = $version_id if $version_id;
}
@@ -28883,95 +32151,182 @@ sub get_os_release {
# arco shows only the release name, like kirk, in pretty name. Too many distros
# are doing pretty name wrong, and just putting in the NAME value there
if (!$base_type){
- if ((!$b_osr_pretty || !$name_pretty) && $name && $version_name){
- $distro = $name;
- $distro = 'Arco Linux' if $name_lc =~ /^arco/;
+ if ((!$distro->{'osr-pretty'} || !$name_pretty) && $name && $version_name){
+ $dist_osr = $name;
+ $dist_osr = 'Arco Linux' if $name_lc =~ /^arco/;
if ($version_id && $version_name !~ /$version_id/){
- $distro .= ' ' . $version_id;
+ $dist_osr .= ' ' . $version_id;
}
- $distro .= " $version_name";
+ $dist_osr .= " $version_name";
}
elsif ($name_pretty && ($name_pretty !~ /tumbleweed/i && $name_lc ne 'arcolinux')){
- $distro = $name_pretty;
+ $dist_osr = $name_pretty;
}
elsif ($name){
- $distro = $name;
+ $dist_osr = $name;
if ($version_id){
- $distro .= ' ' . $version_id;
+ $dist_osr .= ' ' . $version_id;
}
}
- if ($version_codename && $distro !~ /$version_codename/i){
- $distro .= " $version_codename";
+ if ($version_codename && $dist_osr !~ /$version_codename/i){
+ my @temp = split(/\s*[\/\s]\s*/, $version_codename);
+ foreach (@temp){
+ if ($dist_osr !~ /\b$_\b/i){
+ $dist_osr .= " $_";
+ }
+ }
}
}
# note: mint has varying formats here, some have ubuntu as name, 17 and earlier
else {
+ # incoherent feren use of version, id, etc
+ if ($base_type eq 'ubuntu' && !$base_version && $version_codename &&
+ $name =~ /feren/i){
+ $base_version = ucfirst($version_codename);
+ $distro->{'name'} =~ s/ $version_codename//;
+ }
# mint 17 used ubuntu os-release, so won't have $base_version, steamos holo
- if ($base_name && $base_type eq 'rhel'){
- $distro = $base_name;
- $distro .= ' ' . $version_id if $version_id;
+ if ($base_name && ($base_type eq 'fedora' || $base_type eq 'rhel')){
+ $dist_osr = $base_name;
+ $dist_osr .= ' ' . $version_id if $version_id;
}
elsif ($base_name && $base_type eq 'arch'){
- $distro = $base_name;
+ $dist_osr = $base_name;
}
elsif ($base_name && $base_version){
$base_id = ubuntu_id($base_version) if $base_type eq 'ubuntu' && $base_version;
$base_id = '' if $base_id && "$base_name$base_version" =~ /$base_id/;
$base_id .= ' ' if $base_id;
- $distro = "$base_name $base_id$base_version";
+ $dist_osr = "$base_name $base_id$base_version";
}
elsif ($base_type eq 'default' && ($name_pretty || ($name && $version_name))){
- $distro = ($name && $version_name) ? "$name $version_name" : $name_pretty;
+ $dist_osr = ($name && $version_name) ? "$name $version_name" : $name_pretty;
}
# LMDE 2 has only limited data in os-release, no _LIKE values. 3 has like and debian_codename
- elsif ($base_type eq 'ubuntu' && $name_lc =~ /^(debian|ubuntu)/ && ($name_pretty || ($name && $version_name))){
- $distro = ($name && $version_name) ? "$name $version_name": $name_pretty;
+ elsif ($base_type eq 'ubuntu' && $name_lc =~ /^(debian|ubuntu)/ &&
+ ($name_pretty || ($name && $version_name))){
+ $dist_osr = ($name && $version_name) ? "$name $version_name": $name_pretty;
}
elsif ($base_type eq 'debian' && $base_version){
- $distro = debian_id($base_version);
+ $dist_osr = debian_id('debian',$base_version);
+ }
+ # not used yet
+ elsif ($base_type eq 'devuan' && $base_version){
+ $dist_osr = debian_id('devuan',$base_version);
+ }
+ }
+ eval $end if $b_log;
+ return $dist_osr;
+}
+
+## ID MATCHING TABLES ##
+# args: 0: distro string
+# note: relies on /etc/xdg/xdg-[distro-id] which is an ubuntu thing but could
+# work if other distros use that for spins. Xebian does but not official spin.
+sub distro_spin {
+ my $name = $_[0];
+ eval $start if $b_log;
+ my @spins = (
+ # 0: distro name; 1: xdg search; 2: env search; 3: print name; 4: System Base
+ ['budgie','budgie','','Ubuntu Budgie','Ubuntu'],
+ ['cinnamon','cinnamon','','Ubuntu Cinnamon','Ubuntu'],
+ ['edubuntu','edubuntu','edubuntu','Edubuntu','Ubuntu'],
+ # ['icebox','icebox','icebox','Debian Icebox','Debian'],
+ ['kubuntu','kubuntu|plasma','kubuntu','Kubuntu','Ubuntu'],
+ ['kylin','kylin','kylin','Ubuntu Kylin','Ubuntu'],
+ ['lubuntu','lubuntu','lubuntu','Lubuntu','Ubuntu'],
+ ['mate','mate','','Ubuntu MATE','Ubuntu'],
+ ['studio','studio','studio','Ubuntu Studio','Ubuntu'],
+ ['unity','unity','','Ubuntu Unity','Ubuntu'],
+ # ['xebian','xebian','','Xebian','Debian'],
+ ['xubuntu','xubuntu','xubuntu','Xubuntu','Ubuntu'],
+ );
+ my $tests = 'budgie,cinna,edub,plasma,kubu,kylin,lubu,mate,studio,unity,xebi,xubu';
+ $tests = join(':',main::globber("/etc/xdg/xdg-*{$tests}*"));
+ # xdg is poor since only works in gui. Some of these also in DESKTOP_SESSION
+ foreach my $spin (@spins){
+ if ($name !~ /$spin->[0]/i && (
+ ($spin->[2] && $ENV{'DESKTOP_SESSION'} &&
+ $ENV{'DESKTOP_SESSION'} =~ /$spin->[2]/i) ||
+ ($ENV{'XDG_CONFIG_DIRS'} && $ENV{'XDG_CONFIG_DIRS'} =~ /$spin->[1]/i) ||
+ ($tests && $tests =~ /$spin->[1]/i))){
+ $name =~ s/\b$spin->[4]/$spin->[3]/i;
+ last;
}
}
eval $end if $b_log;
- return $distro;
+ return $name;
}
-# arg: 1 - optional: debian codename
+
+# args: 0: $type [debian|devuan]; 1: optional: debian codename
sub debian_id {
eval $start if $b_log;
- my ($codename) = @_;
- my ($debian_version,$id);
- $debian_version = main::reader('/etc/debian_version','strip',0) if -r '/etc/debian_version';
- $id = 'Debian';
- return if !$debian_version && !$codename;
- # note, 3.0, woody, 3.1, sarge, but after it's integer per version
- my %debians = (
- '4' => 'etch',
- '5' => 'lenny',
- '6' => 'squeeze',
- '7' => 'wheezy',
- '8' => 'jessie',
- '9' => 'stretch',
- '10' => 'buster',
- '11' => 'bullseye',
- '12' => 'bookworm',
- '13' => 'trixie',
- );
- if (main::is_numeric($debian_version)){
- $id .= " $debian_version " . $debians{int($debian_version)};
+ my ($type,$codename) = @_;
+ my ($id,$file_value,%releases,$version);
+ if (-r "/etc/${type}_version"){
+ $file_value = main::reader("/etc/${type}_version",'strip',0);
+ }
+ return if !$file_value && !$codename;
+ if ($type eq 'debian'){
+ $id = 'Debian';
+ # note, 3.0, woody, 3.1, sarge, but after it's integer per version
+ %releases = (
+ '4' => 'etch',
+ '5' => 'lenny',
+ '6' => 'squeeze',
+ '7' => 'wheezy',
+ '8' => 'jessie',
+ '9' => 'stretch',
+ '10' => 'buster',
+ '11' => 'bullseye',
+ '12' => 'bookworm',
+ '13' => 'trixie',
+ '14' => 'forky',
+ );
+ }
+ else {
+ $id = 'Devuan';
+ %releases = (
+ '1' => 'jesse', # jesse
+ '2' => 'ascii', # stretch
+ '3' => 'beowolf', # buster
+ '4' => 'chimaera', # bullseye
+ '5' => 'daedalus', # bookworm
+ '6' => 'excalibur',# trixie
+ '7' => 'freia', # forky
+ # '' => 'ceres/daedalus', # sid/unstable
+ );
+ }
+ # debian often numeric, devuan usually not
+ # like trixie/sid; daedalus; ceres/daedalus; 12.0
+ if (main::is_numeric($file_value)){
+ $version = $file_value . ' ' . $releases{int($file_value)};
}
- elsif ($codename){
- my %by_value = reverse %debians;
- my $version = (main::is_numeric($debian_version)) ? "$debian_version $codename": $debian_version;
- $id .= " $version";
+ else {
+ my %releases_r = reverse %releases;
+ if ($codename){
+ $version = ($releases_r{$codename}) ? "$releases_r{$codename} $codename": $codename;
+ }
+ elsif ($releases_r{$file_value}) {
+ $version = "$releases_r{$file_value} $file_value";
+ }
+ else {
+ $version = $file_value;
+ }
}
- # like buster/sid
- elsif ($debian_version){
- $id .= " $debian_version";
+ if ($version){
+ my @temp = split(/\s*[\/\s]\s*/, $version);
+ foreach (@temp){
+ if ($distro->{'name'} !~ /\b$_\b/i){
+ $id .= " $_";
+ }
+ }
}
eval $end if $b_log;
return $id;
}
-# note, these are only for matching distro/mint derived names.
+# Note, these are only for matching distro/mint derived names.
# Update list as new names become available. While first Mint was 2006-08,
# this method depends on /etc/os-release which was introduced 2012-02.
# Mint is using UBUNTU_CODENAME without ID data.
@@ -28982,17 +32337,35 @@ sub ubuntu_id {
my ($id) = ('');
# xx.04, xx.10
my %codenames = (
- 'jammy' => '22.04 LTS','kinetic' => '22.10',
- 'hirsute' => '21.04','impish' => '21.10',
- 'focal' => '20.04 LTS','groovy' => '20.10',
- 'disco' => '19.04','eoan' => '19.10',
- 'bionic' => '18.04 LTS','cosmic' => '18.10',
- 'zesty' => '17.04','artful' => '17.10',
- 'xenial' => '16.04 LTS','yakkety' => '16.10',
- 'vivid' => '15.04','wily' => '15.10',
- 'trusty' => '14.04 LTS ','utopic' => '14.10',
- 'raring' => '13.04','saucy' => '13.10',
- 'precise' => '12.04 LTS ','quantal' => '12.10',
+ # '??' => '26.04',
+ # '??' => '25.10',
+ # '??' => '25.04',
+ # '??' => '24.10',
+ 'noble' => '24.04 LTS',
+ 'mantic' => '23.10',
+ 'lunar' => '23.04',
+ 'kinetic' => '22.10',
+ 'jammy' => '22.04 LTS',
+ 'impish' => '21.10',
+ 'hirsute' => '21.04',
+ 'groovy' => '20.10',
+ 'focal' => '20.04 LTS',
+ 'eoan' => '19.10',
+ 'disco' => '19.04',
+ 'cosmic' => '18.10',
+ 'bionic' => '18.04 LTS',
+ 'artful' => '17.10',
+ 'zesty' => '17.04',
+ 'yakkety' => '16.10',
+ 'xenial' => '16.04 LTS',
+ 'wily' => '15.10',
+ 'vivid' => '15.04',
+ 'utopic' => '14.10',
+ 'trusty' => '14.04 LTS ',
+ 'saucy' => '13.10',
+ 'raring' => '13.04',
+ 'quantal' => '12.10',
+ 'precise' => '12.04 LTS ',
# 'natty' => '11.04','oneiric' => '11.10',
# 'lucid' => '10.04','maverick' => '10.10',
# 'jaunty' => '9.04','karmic' => '9.10',
@@ -29006,12 +32379,40 @@ sub ubuntu_id {
eval $end if $b_log;
return $id;
}
+
+## UTILITIES ##
+sub check_base {
+ if (lc($distro->{'name'}) eq lc($distro->{'base'})){
+ $distro->{'base'} = '';
+ }
+ else {
+ my @name = split(/\s+/,$distro->{'name'});
+ my @working;
+ foreach my $word (@name){
+ if ($distro->{'base'} !~ /\b\Q$word\E\b/i || $word =~ /^[\d\.]+$/){
+ push(@working,$word);
+ }
+ }
+ $distro->{'name'} = join(' ',@working) if @working;
+ }
+}
+
+# args: 0: info; 1: list of globbed distro files
+sub dbg_distro_files {
+ my ($info,$files) = @_;
+ my $contents = {};
+ foreach my $file (@$files){
+ $contents->{$file} = (-r $file ) ? main::reader($file,'','ref') : main::message('file-unreadable');
+ }
+ main::feature_debugger($info . ' raw distro files:',$contents);
+}
}
## DmidecodeData
{
package DmidecodeData;
-# note, all actual tests have already been run in check_tools so if we
+
+# Note, all actual tests have already been run in check_tools so if we
# got here, we're good.
sub set {
eval $start if $b_log;
@@ -29098,7 +32499,9 @@ sub generate_data {
}
}
-# return all device modules not including driver
+# args: 0: driver; 1: modules, comma separated, return only modules
+# which do not equal the driver string itself. Sometimes the module
+# name is different from the driver name, even though it's the same thing.
sub get_driver_modules {
eval $start if $b_log;
my ($driver,$modules) = @_;
@@ -29106,51 +32509,19 @@ sub get_driver_modules {
my @mods = split(/,\s+/, $modules);
if ($driver){
@mods = grep {!/^$driver$/} @mods;
- $modules = join(',', @mods);
+ my $join = (length(join(',', @mods)) > 40) ? ', ' : ',';
+ $modules = join($join, @mods);
}
log_data('data','$modules',$modules) if $b_log;
eval $end if $b_log;
return $modules;
}
-# 1: driver; 2: modules, comma separated, return only modules
-# which do not equal the driver string itself. Sometimes the module
-# name is different from the driver name, even though it's the same thing.
-sub get_gcc_data {
- eval $start if $b_log;
- my ($gcc,@data,@temp);
- my $gccs = [];
- # NOTE: We can't use program_version because we don't yet know where
- # the version number is
- if (my $program = check_program('gcc')){
- @data = grabber("$program --version 2>/dev/null");
- $gcc = awk(\@data,'^gcc');
- }
- if ($gcc){
- # strip out: gcc (Debian 6.3.0-18) 6.3.0 20170516
- # gcc (GCC) 4.2.2 20070831 prerelease [FreeBSD]
- $gcc =~ s/\([^\)]*\)//g;
- $gcc = get_piece($gcc,2);
- }
- if ($extra > 1){
- # glob /usr/bin for gccs, strip out all non numeric values
- @temp = globber('/usr/bin/gcc-*');
- foreach (@temp){
- if (/\/gcc-([0-9.]+)$/){
- push(@$gccs, $1);
- }
- }
- }
- unshift(@$gccs, $gcc);
- log_data('dump','@gccs',$gccs) if $b_log;
- eval $end if $b_log;
- return $gccs;
-}
-
-## GlabelData - set/get
-# used only to get RAID ZFS gptid path standard name, like ada0p1
+## GlabelData: public methods: set(), get()
+# Used only to get RAID ZFS gptid path standard name, like ada0p1
{
package GlabelData;
+
# gptid/c5e940f1-5ce2-11e6-9eeb-d05099ac4dc2 N/A ada0p1
sub get {
eval $start if $b_log;
@@ -29172,6 +32543,7 @@ sub get {
eval $end if $b_log;
return $dev_id;
}
+
sub set {
eval $start if $b_log;
$loaded{'glabel'} = 1;
@@ -29212,12 +32584,14 @@ sub get_hostname {
{
package InitData;
my ($init,$init_version,$program) = ('','','');
+
sub get {
eval $start if $b_log;
my $runlevel = get_runlevel();
my $default = ($extra > 1) ? get_runlevel_default() : '';
my ($rc,$rc_version) = ('','');
my $comm = (-r '/proc/1/comm') ? main::reader('/proc/1/comm','',0) : '';
+ my $link = readlink('/sbin/init');
# this test is pretty solid, if pid 1 is owned by systemd, it is systemd
# otherwise that is 'init', which covers the rest of the init systems.
# more data may be needed for other init systems.
@@ -29225,10 +32599,10 @@ sub get {
if (($comm && $comm =~ /systemd/) || -e '/run/systemd/units'){
$init = 'systemd';
if ($program = main::check_program('systemd')){
- $init_version = main::program_version($program,'^systemd','2','--version',1);
+ ($init,$init_version) = ProgramData::full('systemd',$program);
}
if (!$init_version && ($program = main::check_program('systemctl'))){
- $init_version = main::program_version($program,'^systemd','2','--version',1);
+ ($init,$init_version) = ProgramData::full('systemd',$program);
}
if ($runlevel && $runlevel =~ /^\d$/){
my $target = '';
@@ -29247,20 +32621,15 @@ sub get {
$init = '31init';
# no version, this is a 31 line C program
}
- # epoch version == Epoch Init System 1.0.1 "Sage"
elsif ($comm =~ /epoch/){
- $init = 'Epoch';
- $init_version = main::program_version('epoch', '^Epoch', '4','version');
+ ($init,$init_version) = ProgramData::full('epoch');
}
# if they fix dinit to show /proc/1/comm == dinit
elsif ($comm =~ /^dinit/){
- dinit_data();
+ ($init,$init_version) = ProgramData::full('dinit');
}
elsif ($comm =~ /finit/){
- $init = 'finit';
- if ($program = main::check_program('finit')){
- $init_version = main::program_version($program,'^Finit','2','-v',1);
- }
+ ($init,$init_version) = ProgramData::full('finit');
}
# not verified
elsif ($comm =~ /^hummingbird/){
@@ -29284,28 +32653,31 @@ sub get {
# no version data as of 2022-10-26
}
elsif ($comm =~ /shepherd/){
- $init = 'Shepherd';
- $init_version = main::program_version('shepherd', '^shepherd', '4','--version',1);
+ ($init,$init_version) = ProgramData::full('shepherd');
}
# fallback for some inits that link to /sbin/init
elsif ($comm eq 'init'){
# shows /sbin/dinit-init but may change
- if (-e '/sbin/dinit' && readlink('/sbin/init') =~ /dinit/){
- dinit_data();
+ if (-e '/sbin/dinit' && $link && $link =~ /dinit/){
+ ($init,$init_version) = ProgramData::full('dinit');
}
- elsif (-e '/sbin/openrc-init' && readlink('/sbin/init') =~ /openrc/){
+ elsif (-e '/sbin/openrc-init' && $link && $link =~ /openrc/){
($init,$init_version) = openrc_data();
}
}
}
if (!$init){
- # output: /sbin/init --version: init (upstart 1.1)
- # init (upstart 0.6.3)
- # openwrt /sbin/init hangs on --version command, I think
- if (!%risc &&
- ($init_version = main::program_version('init', 'upstart', '3','--version'))){
+ # openwrt/busybox /sbin/init hangs on --version command
+ if (-e '/sbin/init' && $link && $link =~ /busybox/){
+ ($init,$init_version) = ProgramData::full('busybox','/sbin/init');
+ }
+ # risky since we don't know which init it is. $comm == 'init'
+ # output: /sbin/init --version: init (upstart 1.1); init (upstart 0.6.3)
+ elsif (!%risc && !$link && main::globber('/{usr/lib,sbin,var/log}/upstart*') &&
+ ($init_version = ProgramData::version('init', 'upstart', '3','--version'))){
$init = 'Upstart';
}
+ # surely more positive way to detect active
elsif (main::check_program('launchctl')){
$init = 'launchd';
}
@@ -29313,7 +32685,7 @@ sub get {
elsif (-f '/etc/inittab'){
$init = 'SysVinit';
if (main::check_program('strings')){
- my @data = main::grabber('strings /sbin/init');
+ my @data = main::grabber('strings /sbin/init 2>/dev/null');
$init_version = main::awk(\@data,'^version\s+[0-9]',2);
}
}
@@ -29345,31 +32717,24 @@ sub get {
'default' => $default,
};
}
-sub dinit_data {
- eval $start if $b_log;
- $init = 'dinit';
- # Dinit version 0.15.1.
- if ($program = main::check_program('dinit')){
- $init_version = main::program_version($program,'^Dinit','3','--version',1);
- $init_version =~ s/\.$//;
- }
- eval $end if $b_log;
-}
+
sub openrc_data {
eval $start if $b_log;
- my $version;
- # /sbin/openrc --version == openrc (OpenRC) 0.13
+ my @result;
+ # /sbin/openrc --version: openrc (OpenRC) 0.13
if ($program = main::check_program('openrc')){
- $version = main::program_version($program, '^openrc', '3','--version');
+ @result = ProgramData::full('openrc',$program);
}
- # /sbin/rc --version == rc (OpenRC) 0.11.8 (Gentoo Linux)
+ # /sbin/rc --version: rc (OpenRC) 0.11.8 (Gentoo Linux)
elsif ($program = main::check_program('rc')){
- $version = main::program_version($program, '^rc', '3','--version');
+ @result = ProgramData::full('rc',$program);
}
+ $result[0] ||= 'OpenRC';
eval $end if $b_log;
- return ('OpenRC',$version);
+ return @result;
}
-# # check? /var/run/nologin for bsds?
+
+# Check? /var/run/nologin for bsds?
sub get_runlevel {
eval $start if $b_log;
my $runlevel = '';
@@ -29383,7 +32748,8 @@ sub get_runlevel {
eval $end if $b_log;
return $runlevel;
}
-# note: it appears that at least as of 2014-01-13, /etc/inittab is going
+
+# Note: it appears that at least as of 2014-01-13, /etc/inittab is going
# to be used for default runlevel in upstart/sysvinit. systemd default is
# not always set so check to see if it's linked.
sub get_runlevel_default {
@@ -29428,12 +32794,14 @@ sub get_runlevel_default {
## IpData
{
package IpData;
+
sub set {
eval $start if $b_log;
- if ($alerts{'ip'}->{'action'} eq 'use'){
+ if ($force{'ip'} ||
+ (!$force{'ifconfig'} && $alerts{'ip'}->{'action'} eq 'use')){
set_ip_addr();
}
- elsif ($alerts{'ifconfig'}->{'action'} eq 'use'){
+ elsif ($force{'ifconfig'} || $alerts{'ifconfig'}->{'action'} eq 'use'){
set_ifconfig();
}
eval $end if $b_log;
@@ -29442,17 +32810,21 @@ sub set {
sub set_ip_addr {
eval $start if $b_log;
my @data = main::grabber($alerts{'ip'}->{'path'} . " addr 2>/dev/null",'\n','strip');
- # my $file = "$fake_data_dir/if/scope-ipaddr-1.txt";
- # my $file = "$fake_data_dir/networking/ip-addr-blue-advance.txt";
- # my @data = reader($file,'strip') or die $!;
- my ($b_skip,$broadcast,$if,$ip,@ips,$scope,$if_id,$type,@temp,@temp2);
+ if ($fake{'ip-if'}){
+ # my $file = "$fake_data_dir/if/scope-ipaddr-1.txt";
+ # my $file = "$fake_data_dir/network/ip-addr-blue-advance.txt";
+ # my $file = "$fake_data_dir/network/ppoe/ppoe-ip-address-1.txt";
+ # my $file = "$fake_data_dir/network/ppoe/ppoe-ip-addr-2.txt";
+ # my $file = "$fake_data_dir/network/ppoe/ppoe-ip-addr-3.txt";
+ # @data = main::reader($file,'strip') or die $!;
+ }
+ my ($b_skip,$broadcast,$if,$if_id,$ip,@ips,$scope,$type,@temp,@temp2);
foreach (@data){
if (/^[0-9]/){
# print "$_\n";
if (@ips){
- # print "$if\n";
- @temp = ($if,[@ips]);
- push(@ifs,@temp);
+ # print "$if\n";
+ push(@ifs,($if,[@ips]));
@ips = ();
}
@temp = split(/:\s+/, $_);
@@ -29462,13 +32834,12 @@ sub set_ip_addr {
$if = '';
next;
}
- $b_skip = 0;
- @temp = ();
+ ($b_skip,@temp) = ();
}
elsif (!$b_skip && /^inet/){
# print "$_\n";
+ ($broadcast,$ip,$scope,$if_id,$type) = ();
@temp = split(/\s+/, $_);
- ($broadcast,$ip,$scope,$if_id,$type) = ('','','','','');
$ip = $temp[1];
$type = ($temp[0] eq 'inet') ? 4 : 6 ;
if ($temp[2] eq 'brd'){
@@ -29478,25 +32849,27 @@ sub set_ip_addr {
$scope = $1;
$if_id = $3;
}
- @temp = ($type,$ip,$broadcast,$scope,$if_id);
- push(@ips,[@temp]);
+ push(@ips,[$type,$ip,$broadcast,$scope,$if_id]);
# print Data::Dumper::Dumper \@ips;
}
}
- # print Data::Dumper::Dumper \@ips if $dbg[4];
if (@ips){
- @temp = ($if,[@ips]);
- push(@ifs,@temp);
+ push(@ifs,($if,[@ips]));
}
main::log_data('dump','@ifs',\@ifs) if $b_log;
- print Data::Dumper::Dumper \@ifs if $dbg[3];
+ print 'ip addr: ', Data::Dumper::Dumper \@ifs if $dbg[3];
eval $end if $b_log;
}
sub set_ifconfig {
eval $start if $b_log;
+ # whitespace matters!! Don't use strip
my @data = main::grabber($alerts{'ifconfig'}->{'path'} . " 2>/dev/null",'\n','');
- # my @data = reader("$fake_data_dir/if/vps-ifconfig-1.txt",'') or die $!;
+ if ($fake{'ip-if'}){
+ # my $file = "$fake_data_dir/network/ppoe/ppoe-ifconfig-all-1.txt";
+ # my $file = "$fake_data_dir/network/vps-ifconfig-1.txt";
+ # @data = main::reader($file) or die $!;
+ }
my ($b_skip,$broadcast,$if,@ips_bsd,$ip,@ips,$scope,$if_id,$type,@temp,@temp2);
my ($state,$speed,$duplex,$mac);
foreach (@data){
@@ -29504,13 +32877,11 @@ sub set_ifconfig {
# print "$_\n";
if (@ips){
# print "here\n";
- @temp = ($if,[@ips]);
- push(@ifs,@temp);
+ push(@ifs,($if,[@ips]));
@ips = ();
}
if ($mac){
- @temp = ($if,[($state,$speed,$duplex,$mac)]);
- push(@ifs_bsd,@temp);
+ push(@ifs_bsd,($if,[$state,$speed,$duplex,$mac]));
($state,$speed,$duplex,$mac,$if_id) = ('','','','','');
}
$if = (split(/\s+/, $_))[0];
@@ -29580,12 +32951,11 @@ sub set_ifconfig {
push(@ifs,($if,[@ips]));
}
if ($mac){
- @temp = ($if,[($state,$speed,$duplex,$mac)]);
- push(@ifs_bsd,@temp);
+ push(@ifs_bsd,($if,[$state,$speed,$duplex,$mac]));
($state,$speed,$duplex,$mac) = ('','','','');
}
- print Data::Dumper::Dumper \@ifs if $dbg[3];
- print Data::Dumper::Dumper \@ifs_bsd if $dbg[3];
+ print 'ifconfig: ', Data::Dumper::Dumper \@ifs if $dbg[3];
+ print 'ifconfig bsd: ', Data::Dumper::Dumper \@ifs_bsd if $dbg[3];
main::log_data('dump','@ifs',\@ifs) if $b_log;
main::log_data('dump','@ifs_bsd',\@ifs_bsd) if $b_log;
eval $end if $b_log;
@@ -29618,6 +32988,113 @@ sub get_kernel_bits {
return $bits;
}
+# arg: 0: $cs_curr, by ref; 1: $cs_avail, by ref.
+sub get_kernel_clocksource {
+ eval $start if $b_log;
+ if (-r '/sys/devices/system/clocksource/clocksource0/current_clocksource'){
+ ${$_[0]} = reader('/sys/devices/system/clocksource/clocksource0/current_clocksource','',0);
+ if ($b_admin &&
+ -r '/sys/devices/system/clocksource/clocksource0/available_clocksource'){
+ ${$_[1]} = reader('/sys/devices/system/clocksource/clocksource0/available_clocksource','',0);
+ if (${$_[0]} && ${$_[1]}){
+ my @temp = split(/\s+/,${$_[1]});
+ @temp = grep {$_ ne ${$_[0]}} @temp;
+ ${$_[1]} = join(',', @temp);
+ }
+ }
+ }
+ eval $end if $b_log;
+}
+
+## KernelCompiler
+{
+package KernelCompiler;
+
+sub get {
+ eval $start if $b_log;
+ my $compiler = []; # we want an array ref to return if not set
+ if (my $file = $system_files{'proc-version'}){
+ version_proc($compiler,$file);
+ }
+ elsif ($bsd_type){
+ version_bsd($compiler);
+ }
+ eval $end if $b_log;
+ return $compiler;
+}
+
+# args: 0: compiler by ref
+sub version_bsd {
+ eval $start if $b_log;
+ my $compiler = $_[0];
+ if ($alerts{'sysctl'}->{'action'} && $alerts{'sysctl'}->{'action'} eq 'use'){
+ if ($sysctl{'kernel'}){
+ my @working;
+ foreach (@{$sysctl{'kernel'}}){
+ # Not every line will have a : separator though the processor should make
+ # most have it. This appears to be 10.x late feature add, I don't see it
+ # on earlier BSDs
+ if (/^kern.compiler_version/){
+ @working = split(/:\s*/, $_);
+ $working[1] =~ /.*(clang|gcc|zigcc)\sversion\s([\S]+)\s.*/;
+ @$compiler = ($1,$2);
+ last;
+ }
+ }
+ }
+ # OpenBSD doesn't show compiler data in sysctl or dboot but it's going to
+ # be Clang until way into the future, and it will be the installed version.
+ if (ref $compiler ne 'ARRAY' || !@$compiler){
+ if (my $path = main::check_program('clang')){
+ ($compiler->[0],$compiler->[1]) = ProgramData::full('clang',$path);
+ }
+ }
+ }
+ main::log_data('dump','@$compiler',$compiler) if $b_log;
+ eval $end if $b_log;
+}
+
+# args: 0: compiler by ref; 1: proc file name
+sub version_proc {
+ eval $start if $b_log;
+ my ($compiler,$file) = @_;
+ if (my $result = main::reader($file,'',0)){
+ my $version;
+ if ($fake{'compiler'}){
+ # $result = $result =~ /\*(gcc|clang)\*eval\*/;
+ # $result='Linux version 5.4.0-rc1 (sourav@archlinux-pc) (clang version 9.0.0 (tags/RELEASE_900/final)) #1 SMP PREEMPT Sun Oct 6 18:02:41 IST 2019';
+ # $result='Linux version 5.8.3-fw1 (fst@x86_64.frugalware.org) ( OpenMandriva 11.0.0-0.20200819.1 clang version 11.0.0 (/builddir/build/BUILD/llvm-project-release-11.x/clang 2a0076812cf106fcc34376d9d967dc5f2847693a), LLD 11.0.0)';
+ # $result='Linux version 5.8.0-18-generic (buildd@lgw01-amd64-057) (gcc (Ubuntu 10.2.0-5ubuntu2) 10.2.0, GNU ld (GNU Binutils for Ubuntu) 2.35) #19-Ubuntu SMP Wed Aug 26 15:26:32 UTC 2020';
+ # $result='Linux version 5.8.9-fw1 (fst@x86_64.frugalware.org) (gcc (Frugalware Linux) 9.2.1 20200215, GNU ld (GNU Binutils) 2.35) #1 SMP PREEMPT Tue Sep 15 16:38:57 CEST 2020';
+ # $result='Linux version 5.8.0-2-amd64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.0-9) 10.2.0, GNU ld (GNU Binutils for Debian) 2.35) #1 SMP Debian 5.8.10-1 (2020-09-19)';
+ # $result='Linux version 5.9.0-5-amd64 (debian-kernel@lists.debian.org) (gcc-10 (Debian 10.2.1-1) 10.2.1 20201207, GNU ld (GNU Binutils for Debian) 2.35.1) #1 SMP Debian 5.9.15-1 (2020-12-17)';
+ # $result='Linux version 2.6.1 (GNU 0.9 GNU-Mach 1.8+git20201007-486/Hurd-0.9 i686-AT386)';
+ # $result='NetBSD version 9.1 (netbsd@localhost) (gcc version 7.5.0) NetBSD 9.1 (GENERIC) #0: Sun Oct 18 19:24:30 UTC 2020';
+ #$result='Linux version 6.0.8-0-generic (chimera@chimera) (clang version 15.0.4, LLD 15.0.4) #1 SMP PREEMPT_DYNAMIC Fri Nov 11 13:45:29 UTC 2022';
+ # 2023 ubuntu, sigh..
+ # $result='Linux version 6.5.8-1-liquorix-amd64 (steven@liquorix.net) (gcc (Debian 13.2.0-4) 13.2.0, GNU ld (GNU Binutils for Debian) 2.41) #1 ZEN SMP PREEMPT liquorix 6.5-9.1~trixie (2023-10-19)';
+ # $result='Linux version 6.5.0-9-generic (buildd@bos03-amd64-043) (x86_64-linux-gnu-gcc-13 (Ubuntu 13.2.0-4ubuntu3) 13.2.0, GNU ld (GNU Binutils for Ubuntu) 2.41) #9-Ubuntu SMP PREEMPT_DYNAMIC Sat Oct 7 01:35:40 UTC 2023';
+ # $result='Linux version 6.5.13-un-def-alt1 (builder@localhost.localdomain) (gcc-13 (GCC) 13.2.1 20230817 (ALT Sisyphus 13.2.1-alt2), GNU ld (GNU Binutils) 2.41.0.20230826) #1 SMP PREEMPT_DYNAMIC Wed Nov 29 15:54:38 UTC 2023';
+ }
+ # Note: zigcc is only theoretical, but someone is going to try it!
+ # cleanest, old style: 'clang version 9.0.0 (' | 'gcc version 7.5.0'
+ if ($result =~ /(gcc|clang|zigcc).*?version\s([^,\s\)]+)/){
+ @$compiler = ($1,$2);
+ }
+ # new styles: compiler + stuff + x.y.z. Ignores modifiers to number: -4, -ubuntu
+ elsif ($result =~ /(gcc|clang|zigcc).*?\s(\d+(\.\d+){2,4})[)\s,_-]/){
+ @$compiler = ($1,$2);
+ }
+ # failed, let's at least try for compiler type
+ elsif ($result =~ /(gcc|clang|zigcc)/){
+ @$compiler = ($1,'N/A');
+ }
+ }
+ main::log_data('dump','@$compiler',$compiler) if $b_log;
+ eval $end if $b_log;
+}
+}
+
sub get_kernel_data {
eval $start if $b_log;
my ($ksplice) = ('');
@@ -29645,6 +33122,7 @@ sub get_kernel_data {
## KernelParameters
{
package KernelParameters;
+
sub get {
eval $start if $b_log;
my ($parameters);
@@ -29657,6 +33135,7 @@ sub get {
eval $end if $b_log;
return $parameters;
}
+
sub parameters_linux {
eval $start if $b_log;
my ($file) = @_;
@@ -29666,6 +33145,7 @@ sub parameters_linux {
eval $end if $b_log;
return $line;
}
+
sub parameters_bsd {
eval $start if $b_log;
my ($parameters);
@@ -29674,10 +33154,11 @@ sub parameters_bsd {
}
}
-## LsblkData - set/get
+## LsblkData: public methods: set(), get()
{
package LsblkData;
-# 1 - partition name
+
+# args: 0: partition name
sub get {
eval $start if $b_log;
my $item = $_[0];
@@ -29692,6 +33173,7 @@ sub get {
eval $start if $b_log;
return ($result) ? $result : {};
}
+
sub set {
eval $start if $b_log;
$loaded{'lsblk'} = 1;
@@ -29771,13 +33253,12 @@ package MemoryData;
sub get {
eval $start if $b_log;
my ($type) = @_;
- my ($memory);
- # note: netbsd 8.0 has meminfo!
$loaded{'memory'} = 1;
- # netbsd uses meminfo, but it uses it in a weird way
+ my ($memory);
+ # netbsd 8.0 uses meminfo, but it uses it in a weird way
if (!$force{'vmstat'} && (!$bsd_type || ($force{'meminfo'} && $bsd_type)) &&
- (my $file = $system_files{'proc-meminfo'})){
- $memory = meminfo_data($type,$file);
+ (my $file = $system_files{'proc-meminfo'})){
+ $memory = linux_data($type,$file);
}
else {
$memory = bsd_data($type);
@@ -29785,41 +33266,70 @@ sub get {
eval $end if $b_log;
return $memory;
}
-sub full {
+
+# $memory:
+# 0: available (not reserved or iGPU)
+# 1: used (of available)
+# 2: used %
+# 3: gpu (raspberry pi only)
+# Linux only, but could be extended if anyone wants to do the work for BSDs
+# 4: array ref: sys_memory [total, blocks, block-size, count factor]
+# 5: array ref: proc/iomem [total, reserved, gpu]
+#
+# args: 0: source, the caller; 1: $row hash ref; 2: $num ref; 3: indent
+sub row {
eval $start if $b_log;
- my ($source) = @_;
- my $num = 0;
- my ($memory);
- my $row = {};
- my ($gpu_ram,$percent,$total,$used) = (0,'','','');
+ my ($source,$row,$num,$indent) = @_;
$loaded{'memory'} = 1;
- $memory = get('splits');
+ my ($available,$gpu_ram,$note,$total,$used);
+ my $memory = get('full');
if ($memory){
- my @temp = split(':', $memory);
- $gpu_ram = $temp[3] if $temp[3];
- $total = ($temp[0]) ? main::get_size($temp[0],'string') : 'N/A';
- $used = ($temp[1]) ? main::get_size($temp[1],'string') : 'N/A';
- $used .= " ($temp[2]%)" if $temp[2];
+ # print Data::Dumper::Dumper $memory;
+ if ($memory->[3]){
+ $gpu_ram = $memory->[3];
+ }
+ elsif ($memory->[5] && $memory->[5][2]){
+ $gpu_ram = $memory->[5][2];
+ }
+ # Great, we have the real RAM data.
+ if ($show{'ram'} && ($total = RamItem::ram_total())){
+ $total = main::get_size($total,'string');
+ }
+ elsif ($memory->[4] || $memory->[5]){
+ process_total($memory,\$total,\$note);
+ }
if ($gpu_ram){
$gpu_ram = main::get_size($gpu_ram,'string');
}
+ $available = main::get_size($memory->[0],'string') if $memory->[0];
+ $used = main::get_size($memory->[1],'string') if $memory->[1];
+ $used .= " ($memory->[2]%)" if $memory->[2];
}
- my $key = ($source eq 'process') ? 'System RAM': 'RAM';
- $row->{main::key($num++,1,1,$key)} = '';
- $row->{main::key($num++,0,2,'total')} = $total;
- $row->{main::key($num++,0,2,'used')} = $used;
- $row->{main::key($num++,0,2,'gpu')} = $gpu_ram if $gpu_ram;
+ my $field = ($source eq 'info') ? 'Memory' : 'System RAM';
+ $available ||= 'N/A';
+ $total ||= 'N/A';
+ $used ||= 'N/A';
+ $row->{main::key($$num++,1,$indent,$field)} = '';
+ $row->{main::key($$num++,1,$indent+1,'total')} = $total;
+ $row->{main::key($$num++,0,$indent+2,'note')} = $note if $note;
+ $row->{main::key($$num++,0,$indent+1,'available')} = $available;
+ $row->{main::key($$num++,0,$indent+1,'used')} = $used;
+ $row->{main::key($$num++,0,$indent+1,'igpu')} = $gpu_ram if $gpu_ram;
eval $end if $b_log;
- return $row;
}
-sub meminfo_data {
+
+## LINUX DATA ##
+sub linux_data {
eval $start if $b_log;
my ($type,$file) = @_;
- my ($available,$buffers,$cached,$free,$gpu,$memory,$not_used,$total) = (0,0,0,0,0,'',0,0);
+ my ($available,$buffers,$cached,$free,$gpu,$not_used,$total_avail) = (0,0,0,0,0,0,0);
+ my ($iomem,$memory,$sys_memory,$total);
my @data = main::reader($file);
+ # Note: units kB should mean 1000x8 bits, but actually means KiB! Confusing
foreach (@data){
+ # Not actual total, it's total physical minus reserved/kernel/system.
if ($_ =~ /^MemTotal:/){
- $total = main::get_piece($_,2);
+ $total_avail = main::get_piece($_,2);
}
elsif ($_ =~ /^MemFree:/){
$free = main::get_piece($_,2);
@@ -29835,37 +33345,380 @@ sub meminfo_data {
}
}
$gpu = gpu_ram_arm() if $risc{'arm'};
- #$gpu = main::translate_size('128M');
- $total += $gpu;
+ if ($type ne 'short' && ($fake{'sys-mem'} || -d '/sys/devices/system/memory')){
+ sys_memory(\$sys_memory);
+ }
+ if ($type ne 'short' && ($fake{'iomem'} || ($b_root && -r '/proc/iomem'))){
+ proc_iomem(\$iomem);
+ }
+ # $gpu = main::translate_size('128M');
+ # $total_avail += $gpu; # not using because this ram is not available to system
if ($available){
$not_used = $available;
}
- # seen fringe cases, where total - free+buff+cach < 0
- # the idea is that the OS must be using 10MiB of ram or more
- elsif (($total - ($free + $buffers + $cached)) > 10000){
+ # Seen fringe cases, where total - free+buff+cach < 0
+ # The idea is that the OS must be using 10MiB of ram or more
+ elsif (($total_avail - ($free + $buffers + $cached)) > 10000){
$not_used = ($free + $buffers + $cached);
}
- # netbsd goes < 0, but it's wrong, so dump the cache
- elsif (($total - ($free + $buffers)) > 10000){
+ # Netbsd goes < 0, but it's wrong, so dump the cache
+ elsif (($total_avail - ($free + $buffers)) > 10000){
$not_used = ($free + $buffers);
}
else {
$not_used = $free;
}
- my $used = ($total - $not_used);
- my $percent = ($used && $total) ? sprintf("%.1f", ($used/$total)*100) : '';
- if ($type eq 'string'){
- $percent = " ($percent%)" if $percent;
- $memory = sprintf("%.1f/%.1f MiB", $used/1024, $total/1024) . $percent;
+ my $used = ($total_avail - $not_used);
+ my $percent = ($used && $total_avail) ? sprintf("%.1f", ($used/$total_avail)*100) : '';
+ if ($type eq 'short'){
+ $memory = short_data($total_avail,$used,$percent);
}
else {
- $memory = "$total:$used:$percent:$gpu";
+ # raw return in KiB
+ $memory = [$total_avail,$used,$percent,$gpu,$sys_memory,$iomem];
}
- main::log_data('data',"memory: $memory") if $b_log;
+ # print "$total_avail, $used, $percent, $gpu\n";
+ # print Data::Dumper::Dumper $memory;
+ main::log_data('data',"memory ref: $memory") if $b_log;
eval $end if $b_log;
return $memory;
}
+# All values 0 if not root, but it is readable.
+# See inxi-perl/dev/code-snippets.pl for original attempt, with pci/reserved
+# args: 0: $iomem by ref
+sub proc_iomem {
+ eval $start if $b_log;
+ my $file = '/proc/iomem';
+ my ($buffer,$gpu,$pci,$reserved,$rom,$system) = (0,0,0,0,0,0);
+ my $b_reserved;
+ no warnings 'portable';
+ if ($fake{'iomem'}){
+ # $file = "$fake_data_dir/memory/proc-iomem-128gb-1.txt";
+ # $file = "$fake_data_dira/memory/proc-iomem-544mb-igpu.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-64mb-vram-stolen.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-rh-1-matrox.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-2-vram.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-512mb-1.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-518mb-reserved-1.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-512mb-2-onboardgpu-active.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-512mb-system-1.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-257.18gb-system-1.txt";
+ # $file = "$fake_data_dir/memory/proc-iomem-192gb-system-1.txt";
+ $file = "$fake_data_dir/memory/proc-iomem-1012mb-igpu.txt";
+ }
+ foreach ((main::reader($file),'EOF')){
+ if ($dbg[54]){
+ if (/^\s*([0-9a-f]+)-([^\s]+) : /){
+ print $_,"\n",' size: ';
+ print main::get_size(((hex($2) - hex($1) + 1)/1024),'string'), "\n";
+ }
+ }
+ # Get everythign solidly System RAM
+ if (/^([0-9a-f]+)-([^\s]+) : (System RAM)$/i){
+ $system += hex($2) - hex($1) + 1;
+ }
+ elsif (/^([0-9a-f]+)-([^\s]+) : (Ram buffer)$/i){
+ $buffer += hex($2) - hex($1) + 1;
+ }
+ # Sometimes primary Reserved block contains PCI and other non RAM devices,
+ # but also can contain non RAM addresses, maybe NVMe?
+ elsif (/^([0-9a-f]+)-([^\s]+) : (Reserved)$/i){
+ $reserved += hex($2) - hex($1) + 1;
+ }
+ # Legacy System ROM not in a Reserved block, primary item.
+ elsif (/^\s*([0-9a-f]+)-([^\s]+) : (System ROM)$/i){
+ $rom += hex($2) - hex($1) + 1;
+ }
+ elsif (/^([0-9a-f]+)-([^\s]+) : (ACPI Tables)$/i){
+ $rom += hex($2) - hex($1) + 1;
+ }
+ # Incomplete because sometimes Reserved blocks contain PCI etc devices
+ elsif (/^([0-9a-f]+)-([^\s]+) : (PCI .*)$/){
+ $pci += hex($2) - hex($1) + 1;
+ }
+ # Graphics stolen memory/Video RAM area, but legacy had inside PCI blocks,
+ # not reserved, or as primary. That behavior seems to have changed.
+ if (/^\s*([0-9a-f]+)-([^\s]+) : (?:(Video RAM|Graphics).*)$/i){
+ $gpu += hex($2) - hex($1) + 1;
+ }
+ }
+ if ($dbg[54] || $b_log){
+ my $d = ['iomem:','System: ' . main::get_size(($system/1024),'string'),
+ 'Reserved: ' . main::get_size(($reserved/1024),'string'),
+ 'Buffer: ' . main::get_size(($buffer/1024),'string'),
+ 'iGPU: ' . main::get_size(($gpu/1024),'string'),
+ 'ROM: ' . main::get_size(($rom/1024),'string'),
+ 'System+iGPU+buffer+rom: ' . main::get_size((($system+$gpu+$buffer+$rom)/1024),'string'),
+ ' Raw GiB: ' . ($system+$gpu+$buffer+$rom)/1024**3,
+ 'System+reserved: ' . main::get_size((($system+$reserved)/1024),'string'),
+ ' Raw GiB: ' . ($system+$reserved)/1024**3,
+ 'System+reserved+buffer: ' . main::get_size((($system+$reserved+$buffer)/1024),'string'),
+ ' Raw GiB: ' . ($system+$reserved+$buffer)/1024**3,
+ 'Reserved-iGPU: ' . main::get_size((($reserved-$gpu)/1024),'string'),
+ 'PCI Bus: ' . main::get_size(($pci/1024),'string')];
+ main::log_data('dump','$d iomem',$d) if $b_log;
+ print "\n",join("\n",@$d),"\n\n" if $dbg[54];
+ }
+ if ($gpu || $system || $reserved){
+ # This combination seems to provide the bwest overall result
+ $system += $gpu + $rom + $buffer;
+ ${$_[0]} = [$system/1024,$reserved/1024,$gpu/1024];
+ }
+ main::log_data('dump','$iomem',$_[0]) if $b_log;
+ print 'proc/iomem: ', Data::Dumper::Dumper $_[0] if $dbg[53];
+ eval $end if $b_log;
+}
+
+# Note: seen case where actual 128 GiB, result here 130, 65x2GiB. Also cases
+# where blocks under expected total, this may be related to active onboard gpu.
+sub sys_memory {
+ eval $start if $b_log;
+ return if !$fake{'sys-mem'} && ! -r '/sys/devices/system/memory/block_size_bytes';
+ my ($count,$factor,$size,$total) = (0,1,0,0);
+ # state = off,online; online = 1/0
+ foreach my $online (main::globber('/sys/devices/system/memory/memory*/online')){
+ $count++ if main::reader($online,'',0); # content 1/0, so will read as t/f
+ }
+ if ($count){
+ $size = main::reader('/sys/devices/system/memory/block_size_bytes','',0);
+ if ($size){
+ $size = hex($size)/1024; # back to integer KiB
+ $total = $count * $size;
+ }
+ }
+ if ($fake{'sys-mem'}){
+ # ($total,$count,$size) = (,,); #
+ # ($total,$count,$size) = (4194304,32,131072); # 4gb
+ # ($total,$count,$size) = (7864320,60,131072); # 7.5 gb, -4 blocks
+ # ($total,$count,$size) = (136314880,65,2097152); # 130 gb, +1 block
+ # ($total,$count,$size) = (8126464,62,131072); # 7.75 gb, -2 blocks, vram?
+ # ($total,$count,$size) = (33554432,256,131072); # 32 gb
+ # ($total,$count,$size) = (8388608,64,131072); # 8gb
+ # ($total,$count,$size) = (270532608,129,2097152); # 258 gb, +1 block
+ # ($total,$count,$size) = (17563648,134,131072); # 16.75 gb, +6 block
+ # ($total,$count,$size) = (3801088,29,131072); # 3.62 gb, -3 blocks
+ # ($total,$count,$size) = (67108864,32,2097152); # 64 gb
+ # ($total,$count,$size) = (524288,4,131072); # 512 mb, maybe -4 blocks, vm
+ }
+ # Max stick size assumed: 64 blocks: 8 GiB/128 GiB min module: 2 GiB/32 GiB
+ # 128 blocks: 16 GiB/256 GiB min module: 4 GiB/64 GiB but no way to know
+ # Note: 128 MiB blocks; > 32 GiB, 2 GiB blocks, I think.
+ # 64: 8 GiB/256 GiB, min module: 2 GiB/32 GiB
+ if ($count > 32){
+ $factor = 16;}
+ # 32: 4 GiB/64 GiB, min module: 1 GiB/16 GiB
+ elsif ($count > 16){
+ $factor = 8;}
+ # 16: 2 GiB, min module: 512 MiB
+ elsif ($count > 8){
+ $factor = 4;}
+ # 8: 1 GiB, min module: 256 MiB
+ elsif ($count > 4){
+ $factor = 2;}
+ # 4: 512 MiB, min module: 128 MiB
+ else {
+ $factor = 1;}
+ if ($total || $count || $size){
+ ${$_[0]} = [$total,$count,$size,$factor];
+ }
+ if ($dbg[54] || $b_log){
+ my $d = ['/sys:','Total: ' . main::get_size($total,'string'),
+ 'Blocks: ' . $count,
+ 'Block-size: ' . main::get_size($size,'string'),
+ "Count-factor: $count % $factor: " . $count % $factor];
+ main::log_data('dump','$d sys-mem',$d) if $b_log;
+ print "\n",join("\n",@$d),"\n\n" if $dbg[54];
+ }
+ main::log_data('dump','$sys_memory',$_[0]) if $b_log;
+ print 'sys memory: ', Data::Dumper::Dumper $_[0] if $dbg[53];
+ eval $end if $b_log;
+}
+
+# These are hacks since the phy ram real data is not available in clear form
+# args: 0: memory array ref; 1: $total ref; 2: $note ref.
+sub process_total {
+ eval $start if $b_log;
+ my ($memory,$total,$note) = @_;
+ my ($d,$b_vm,@info);
+ my $src = '';
+ $b_vm = MachineItem::is_vm() if $show{'machine'};
+ # Seen case where actual 128 GiB, result here 130, 65x2GiB. Maybe nvme?
+ # This can be over or under phys ram
+ if ($memory->[4] && $memory->[4][0]){
+ @info = main::get_size($memory->[4][0]);
+ # We want to show note for probably wrong results
+ if ((!$fake{'sys-mem'} && $memory->[0] && $memory->[4][0] < $memory->[0]) ||
+ (!$b_vm && $memory->[4][1] % $memory->[4][3] != 0)){
+ $$note = main::message('note-check');
+ }
+ $src = 'sys';
+ }
+ # Note: this is a touch under the real ram amount, varies, igpu/vram can eat it.
+ # This working total will only be under phys ram.
+ if ($memory->[5] && $memory->[5][0] &&
+ (!$memory->[4] || !$memory->[4][0] || ($memory->[4][0] != $memory->[5][0]))){
+ @info = main::get_size($memory->[5][0]);
+ $src = 'iomem';
+ }
+ if (@info){
+ $$note = '';
+ if (!$b_vm){
+ # $info[0] = 384;
+ # $info[1] = 'MiB';
+ my ($factor,$factor2) = (1,0.5);
+ # For M, assume smallest is 128, anything older won't even work probably.
+ # For T RAM, the system ram is going to be 99.9% of physical because the
+ # reserved stuff is going to be tiny, I believe. We will see.
+ # T array stick sizes: 128/256/512/1024 G
+ # Note: samsung ships 1T modules (2024?), 512G (2023).
+ if ($info[0] > 512){
+ $factor = ($info[1] eq 'MiB') ? 256 : 64;
+ }
+ elsif ($info[0] > 256){
+ $factor = ($info[1] eq 'MiB') ? 128 : 32;
+ }
+ elsif ($info[0] > 128){
+ $factor = ($info[1] eq 'MiB') ? 64 : 16;
+ }
+ elsif ($info[0] > 64){
+ $factor = 8;
+ }
+ elsif ($info[0] > 16){
+ $factor = 4;
+ }
+ elsif ($info[0] > 8){
+ $factor = 4;
+ }
+ elsif ($info[0] > 4){
+ $factor = 2;
+ }
+ elsif ($info[0] > 3){
+ $factor = 1;
+ }
+ elsif ($info[0] > 2){
+ $factor = ($info[1] eq 'TiB') ? 0.25 : 0.5;
+ }
+ # Note: get_size returns 1 as 1024, so we never actually see 1
+ elsif ($info[0] > 1){
+ $factor = ($info[1] eq 'TiB') ? 0.125 : 0.25;
+ }
+ my $result = $info[0] / $factor;
+ my $mod = ((100 * $result) % 100);
+ if ($b_log || $dbg[54]){
+ push(@$d,"src: $src result: $info[0] / $factor: $result math-modulus: $mod");
+ }
+ if ($mod > 0){
+ my ($check,$working) = (0,0);
+ # Sometimes Perl generates a tiny value over 0.1: 0.100000000000023
+ # but also we want to be a little loose here. Note that when high
+ # numbers, like 1012 M, we want the math much looser.
+ # Within ~ 5%
+ if ($info[1] eq 'MiB'){
+ if ($info[0] > 768){
+ $check = 64;
+ }
+ elsif ($info[0] > 512){
+ $check = 32;
+ }
+ elsif ($info[0] > 256){
+ $check = 16;
+ }
+ else {
+ $check = 4;
+ }
+ }
+ # Within ~ 1%
+ elsif ($info[1] eq 'GiB'){
+ if ($info[0] > 512){
+ $check = 4;
+ }
+ elsif ($info[0] > 256){
+ $check = 2;
+ }
+ elsif ($info[0] > 3){
+ $check = 0.25;
+ }
+ else {
+ $check = 0.1;
+ }
+ }
+ # Will need to verify this T assumption on real data one day, but keep
+ # in mind how much reserved ram this would be!
+ elsif ($info[1] eq 'TiB'){
+ if ($info[0] > 16){
+ $check = 0.25;
+ }
+ elsif ($info[0] > 8){
+ $check = 0.15;
+ }
+ elsif ($info[0] > 2){
+ $check = 0.1;
+ }
+ else {
+ $check = 0.05;
+ }
+ }
+ # iomem is always under, sys can be over or under. we want fractional
+ # corresponding value over or under result.
+ # sys has block sizes: 128M, 2G, 32G, so sizes will always be divisible
+ if ($src eq 'sys'){
+ if ($info[0] > 64){
+ $factor2 = 0.25;
+ }
+ }
+ if ($src eq 'sys' && int($result + $factor2) == int($result)){
+ $working = int($result) * $factor;
+ }
+ else {
+ $working = POSIX::ceil($result) * $factor;
+ }
+ if ($b_log || $dbg[54]){
+ push(@$d, "factor2: $factor2 floor_res+fact2: " . int($result + $factor2),
+ "ceil_result * factor: " . (POSIX::ceil($result) * $factor),
+ "floor_result * factor: " . (int($result) * $factor));
+ }
+ if (abs(($working - $info[0])) < $check){
+ if ($src eq 'sys' && $info[0] != $working){
+ $$note = main::message('note-est');
+ }
+ if ($b_log || $dbg[54]){
+ push(@$d,"check less: ($working - $info[0]) < $check: ",
+ "result: inside ceil < $check, clean");
+ }
+ }
+ else {
+ if ($b_log || $dbg[54]){
+ push(@$d,"check not less: ($working - $info[0]) < $check: ",
+ "set: $info[0] = $working");
+ }
+ $$note = main::message('note-est');
+ }
+ $info[0] = $working;
+ }
+ else {
+ if ($b_log || $dbg[54]){
+ push(@$d,"result: clean match, no change: $info[0] $info[1]");
+ }
+ }
+ }
+ else {
+ my $dec = ($info[1] eq 'MiB') ? 1: 2;
+ $info[0] = sprintf("%0.${dec}f",$info[0]) + 0;
+ if ($b_log || $dbg[54]){
+ push(@$d,"result: vm, using size: $info[0] $info[1]");
+ }
+ }
+ $$total = $info[0] . ' ' . $info[1];
+ }
+ if ($b_log || $dbg[54]){
+ main::log_data('dump','debugger',$d) if $b_log;
+ print Data::Dumper::Dumper $d if $dbg[54];
+ }
+ eval $end if $b_log;
+}
+
+## BSD DATA ##
## openbsd/linux
# procs memory page disks traps cpu
# r b w avm fre flt re pi po fr sr wd0 wd1 int sys cs us sy id
@@ -29886,12 +33739,11 @@ sub meminfo_data {
sub bsd_data {
eval $start if $b_log;
my ($type) = @_;
- my $memory = '';
my ($avm,$av_pages,$cnt,$fre,$free_mem,$mult,$real_mem,$total) = (0,0,0,0,0,0,0,0);
- my (@data,$message);
+ my (@data,$memory,$message);
# my $arg = ($bsd_type ne 'openbsd' && $bsd_type ne 'dragonfly') ? '-H' : '';
if (my $program = main::check_program('vmstat')){
- # see above, it's the last line. -H makes it hopefully all in kB so no need
+ # See above, it's the last line. -H makes it hopefully all in kB so no need
# for K/M/G tests, note that -H not consistently supported, so don't use.
my @vmstat = main::grabber("vmstat 2>/dev/null",'\n','strip');
main::log_data('dump','@vmstat',\@vmstat) if $b_log;
@@ -29905,14 +33757,14 @@ sub bsd_data {
my $row = $vmstat[-1];
if ($row){
@data = split(/\s+/, $row);
- # openbsd 6.3, dragonfly 5.x introduced an M / G character, sigh.
+ # Openbsd 6.3, dragonfly 5.x introduced an M / G character, sigh.
if ($avm > 0 && $data[$avm] && $data[$avm] =~ /^([0-9\.]+[KGMT])(iB|B)?$/){
$data[$avm] = main::translate_size($1);
}
if ($fre > 0 && $data[$fre] && $data[$fre] =~ /^([0-9\.]+[KGMT])(iB|B)?$/){
$data[$fre] = main::translate_size($1);
}
- # dragonfly can have 0 avg, or no avm, sigh, but they may fix that so make test dynamic
+ # Dragonfly can have 0 avg, or no avm, sigh, but they may fix that so make test dynamic
if ($avm > 0 && $data[$avm] != 0){
$av_pages = ($bsd_type !~ /^(net|open)bsd$/) ? sprintf('%.1f',$data[$avm]/1024) : $data[$avm];
}
@@ -29921,13 +33773,13 @@ sub bsd_data {
}
}
}
- ## code to get total goes here:
+ # Code to get total goes here:
if ($alerts{'sysctl'}->{'action'} eq 'use'){
- # for dragonfly, we will use free mem, not used because free is 0
+ # For dragonfly, we will use free mem, not used because free is 0
my @working;
if ($sysctl{'memory'}){
foreach (@{$sysctl{'memory'}}){
- # freebsd seems to use bytes here
+ # Freebsd seems to use bytes here
if (!$real_mem && /^hw.physmem:/){
@working = split(/:\s*/, $_);
# if ($working[1]){
@@ -29937,7 +33789,7 @@ sub bsd_data {
last if $free_mem;
}
# But, it uses K here. Openbsd/Dragonfly do not seem to have this item
- # this can be either: Free Memory OR Free Memory Pages
+ # This can be either: Free Memory OR Free Memory Pages
elsif (/^Free Memory:/){
@working = split(/:\s*/, $_);
$working[1] =~ s/[^0-9]+//g;
@@ -29950,36 +33802,57 @@ sub bsd_data {
else {
$message = "sysctl $alerts{'sysctl'}->{'action'}"
}
- # not using, but leave in place for a bit in case we want it
+ # Not using, but leave in place for a bit in case we want it
# my $type = ($free_mem) ? ' free':'' ;
- # hack: temp fix for openbsd/darwin: in case no free mem was detected but we have physmem
+ # Hack: temp fix for openbsd/darwin: in case no free mem was detected but we have physmem
if (($av_pages || $free_mem) && !$real_mem){
my $error = ($message) ? $message: 'total N/A';
my $used = (!$free_mem) ? $av_pages : $real_mem - $free_mem;
- if ($type eq 'string'){
- $used = sprintf("%.1f",$used/1024);
- $memory = "$used/($error) MiB";
+ if ($type eq 'short'){
+ $memory = short_data($error,$used);
}
else {
- $memory = "$error:$used:";
+ $memory = [$error,$used,undef];
}
}
- # use openbsd/dragonfly avail mem data if available
+ # Use openbsd/dragonfly avail mem data if available
elsif (($av_pages || $free_mem) && $real_mem){
my $used = (!$free_mem) ? $av_pages : $real_mem - $free_mem;
my $percent = ($used && $real_mem) ? sprintf("%.1f", ($used/$real_mem)*100) : '';
- if ($type eq 'string'){
- $percent = " ($percent)" if $percent;
- $memory = sprintf("%.1f/%.1f MiB", $used/1024, $real_mem/1024) . $percent;
+ if ($type eq 'short'){
+ $memory = short_data($real_mem,$used,$percent);
}
else {
- $memory = "$real_mem:$used:$percent:0";
+ $memory = [$real_mem,$used,$percent,0];
}
}
eval $end if $b_log;
return $memory;
}
-# raspberry pi only
+
+## TOOLS ##
+# args: 0: avail memory; 1: used memory; 2: percent used
+sub short_data {
+ # some BSDs, no available
+ my @avail = (main::is_numeric($_[0])) ? main::get_size($_[0]) : ($_[0]);
+ my @used = main::get_size($_[1]);
+ my $string = '';
+ if ($avail[1] && $used[1]){
+ if ( $avail[1] eq $used[1]){
+ $string = "$used[0]/$avail[0] $used[1]";
+ }
+ else {
+ $string = "$used[0] $used[1]/$avail[0] $avail[1]";
+ }
+ }
+ elsif ($used[1]){
+ $string = "$used[0]/[$avail[0]] $used[1]";
+ }
+ $string .= " ($_[2]%)" if $_[2];
+ return $string;
+}
+
+# Raspberry pi only
sub gpu_ram_arm {
eval $start if $b_log;
my ($gpu_ram) = (0);
@@ -29994,15 +33867,9 @@ sub gpu_ram_arm {
eval $end if $b_log;
return $gpu_ram;
}
-# standard systems, not used currently, but maybe one day?
-sub get_gpu_ram {
- eval $start if $b_log;
- my ($gpu_ram) = (0);
- eval $end if $b_log;
- return $gpu_ram;
-}
}
+# args: 0: module to get version of
sub get_module_version {
eval $start if $b_log;
my ($module) = @_;
@@ -30034,6 +33901,7 @@ sub get_module_version {
package PackageData;
my ($count,$num,%pms,$type);
$pms{'total'} = 0;
+
sub get {
eval $start if $b_log;
# $num passed by reference to maintain incrementing where requested
@@ -30046,6 +33914,7 @@ sub get {
eval $end if $b_log;
return $output;
}
+
sub create_output {
eval $start if $b_log;
my $output = $_[0];
@@ -30054,7 +33923,7 @@ sub create_output {
$total = $pms{'total'};
}
else {
- if ($type eq 'inner' || $pms{'note'}){
+ if ($type eq 'inner' || $pms{'disabled'}){
$total = 'N/A' if $extra < 2;
}
else {
@@ -30065,7 +33934,7 @@ sub create_output {
delete $pms{'total'};
my $b_mismatch;
foreach (keys %pms){
- next if $_ eq 'note';
+ next if $_ eq 'disabled';
if ($pms{$_}->{'pkgs'} && $pms{$_}->{'pkgs'} != $total){
$b_mismatch = 1;
last;
@@ -30075,23 +33944,23 @@ sub create_output {
}
$output->{main::key($$num++,1,1,'Packages')} = $total;
# if blocked pm secondary, only show if no total or improbable total
- if ($pms{'note'} && $extra < 2 && (!$pms{'total'} || $total < 100)){
- $output->{main::key($$num++,0,2,'note')} = $pms{'note'};
+ if ($pms{'disabled'} && $extra < 2 && (!$pms{'total'} || $total < 100)){
+ $output->{main::key($$num++,0,2,'note')} = $pms{'disabled'};
}
if ($extra > 1 && %pms){
foreach my $pm (sort keys %pms){
my ($cont,$ind) = (1,2);
# if package mgr command returns error, this will not be a hash
next if ref $pms{$pm} ne 'HASH';
- if ($pms{$pm}->{'pkgs'} || $b_admin || ($extra > 1 && $pms{$pm}->{'note'})){
+ if ($pms{$pm}->{'pkgs'} || $b_admin || ($extra > 1 && $pms{$pm}->{'disabled'})){
my $type = $pm;
$type =~ s/^zzz-//; # get rid of the special sorters for items to show last
$output->{main::key($$num++,$cont,$ind,'pm')} = $type;
($cont,$ind) = (0,3);
- $pms{$pm}->{'pkgs'} = 'N/A' if $pms{$pm}->{'note'};
+ $pms{$pm}->{'pkgs'} = 'N/A' if $pms{$pm}->{'disabled'};
$output->{main::key($$num++,($cont+1),$ind,'pkgs')} = $pms{$pm}->{'pkgs'};
- if ($pms{$pm}->{'note'}){
- $output->{main::key($$num++,$cont,$ind,'note')} = $pms{$pm}->{'note'};
+ if ($pms{$pm}->{'disabled'}){
+ $output->{main::key($$num++,$cont,$ind,'note')} = $pms{$pm}->{'disabled'};
}
if ($b_admin ){
if ($pms{$pm}->{'libs'}){
@@ -30107,6 +33976,7 @@ sub create_output {
# print Data::Dumper::Dumper \%output;
eval $end if $b_log;
}
+
sub package_counts {
eval $start if $b_log;
my ($type) = @_;
@@ -30114,8 +33984,8 @@ sub package_counts {
# apt systems: plasma-discover, non apt, discover, but can't use due to conflict
# my $disc = 'plasma-discover';
my $gs = 'gnome-software';
- # 0: key; 1: program; 2: p/d; 3: arg/path; 4: 0/1 use lib;
- # 5: lib slice; 6: lib splitter; 7 - optional eval test;
+ # 0: key; 1: program; 2: p/d [no-list]; 3: arg/path/no-list; 4: 0/1 use lib;
+ # 5: lib slice; 6: lib splitter; 7: optional eval test;
# 8: optional installed tool tests for -ra
# needed: cards [nutyx], urpmq [mageia]
my @pkg_managers = (
@@ -30125,14 +33995,18 @@ sub package_counts {
# mutyx. do cards test because there is a very slow pkginfo python pkg mgr
['cards','pkginfo','p','-i',1,1,'','main::check_program(\'cards\')'],
# older dpkg-query do not support -f values consistently: eg ${binary:Package}
- ['dpkg','dpkg-query','p','-W -f=\'${Package}\n\'',1,0,'','',
- ['apt','apt-get','aptitude','deb-get','nala','synaptic']],
+ ['dpkg','dpkg-query','p','-W --showformat=\'${Package}\n\'',1,0,'','',
+ ['apt','apt-get','aptitude','deb-get','muon','nala','synaptic']],
['emerge','emerge','d','/var/db/pkg/*/*/',1,5,'\\/'],
['eopkg','eopkg','d','/var/lib/eopkg/package/*',1,5,'\\/'],
['guix-sys','guix','p','package -p "/run/current-system/profile" -I',1,0,''],
['guix-usr','guix','p','package -I',1,0,''],
['kiss','kiss','p','list',1,0,''],
['mport','mport','p','list',1,0,''],
+ # netpkg puts packages in same place as slackpkg, only way to tell apart
+ ['netpkg','netpkg','d','/var/lib/pkgtools/packages/*',1,5,'\\/',
+ '-d \'/var/netpkg\' && -d \'/var/lib/pkgtools/packages\'',
+ ['netpkg','sbopkg','sboui','slackpkg','slapt-get','slpkg','swaret']],
['nix-sys','nix-store','p','-qR /run/current-system/sw',1,1,'-'],
['nix-usr','nix-store','p','-qR ~/.nix-profile',1,1,'-'],
['nix-default','nix-store','p','-qR /nix/var/nix/profiles/default',1,2,'-'],
@@ -30140,26 +34014,31 @@ sub package_counts {
['pacman','pacman','p','-Qq --color never',1,0,'',
'!main::check_program(\'pacman-g2\')', # pacman-g2 has sym link to pacman
# these may need to be trimmed down depending on how useful/less some are
- ['argon','aura','aurutils','cylon','octopi','pacaur','pakku','pamac','paru',
- 'pikaur','trizen','yaourt','yay','yup']],
+ ['argon','aura','aurutils','baph','cylon','octopi','pacaur','pacseek',
+ 'pakku','pamac','paru','pikaur','trizen','yaourt','yay','yup']],
['pacman-g2','pacman-g2','p','-Q',1,0,'','',],
['pkg','pkg','d','/var/db/pkg/*',1,0,''], # 'pkg list' returns non programs
- ['pkg_info','pkg_info','p','',1,0,''],
+ ['pkg_add','pkg_info','p','',1,0,''], # OpenBSD has set of tools, not 1 pm
# like cards, avoid pkginfo directly due to python pm being so slow
# but pkgadd is also found in scratch
['pkgutils','pkginfo','p','-i',1,0,'','main::check_program(\'pkgadd\')'],
# slack 15 moves packages to /var/lib/pkgtools/packages but links to /var/log/packages
['pkgtool','installpkg','d','/var/lib/pkgtools/packages/*',1,5,'\\/',
- '-d \'/var/lib/pkgtools/packages\'',
- ['slackpkg','slapt-get','slpkg','swaret']],
+ '!-d \'/var/netpkg\' && -d \'/var/lib/pkgtools/packages\'',
+ ['sbopkg','sboui','slackpkg','slapt-get','slpkg','swaret']],
['pkgtool','installpkg','d','/var/log/packages/*',1,4,'\\/',
'! -d \'/var/lib/pkgtools/packages\' && -d \'/var/log/packages/\'',
- ['slackpkg','slapt-get','slpkg','swaret']],
+ ['sbopkg','sboui','slackpkg','slapt-get','slpkg','swaret']],
# rpm way too slow without nodigest/sig!! confirms packages exist
# but even with, MASSIVELY slow in some cases, > 20, 30 seconds!!!!
# find another way to get rpm package counts or don't show this feature for rpm!!
- ['rpm','rpm','force','-qa --nodigest --nosignature',1,0,'','',
+ ['rpm','rpm','force','-qa --nodigest --nosignature',1,0,'',
+ 'main::check_program(\'apt-get\') && main::check_program(\'dpkg\')',
['dnf','packagekit','up2date','urpmi','yast','yum','zypper']],
+ # uncommon case where apt-get frontend for rpm, w/o dpkg, like AltLinux did
+ ['rpm-apt','rpm','p','-qa',1,0,'',
+ 'main::check_program(\'apt-get\') && !main::check_program(\'dpkg\')',
+ ['apt-get','rpm']],
# scratch is a programming language too, with software called scratch
['scratch','pkgbuild','d','/var/lib/scratchpkg/index/*/.pkginfo',1,5,'\\/',
'-d \'/var/lib/scratchpkg\''],
@@ -30167,6 +34046,7 @@ sub package_counts {
# ['slackpkg','pkgtool','slapt-get','slpkg','swaret']],
# ['slapt-get','slapt-get','p','--installed',1,0,''],
# ['spkg','spkg','p','--installed',1,0,''],
+ ['tazpkg','tazpkg','p','list',1,0,'','',['tazpkgbox','tazpanel']],
['tce','tce-status','p','-i',1,0,'','',['apps','tce-load']],
# note: I believe mageia uses rpm internally but confirm
# ['urpmi','urpmq','p','??',1,0,''],
@@ -30179,26 +34059,26 @@ sub package_counts {
foreach my $pm (@pkg_managers){
if ($program = main::check_program($pm->[1])){
next if $pm->[7] && !eval $pm->[7];
- my ($error,$libs,@list,$pmts);
+ my ($disabled,$libs,@list,$pmts);
if ($pm->[2] eq 'p' || ($pm->[2] eq 'force' && check_run($pm))){
- chomp(@list = qx($program $pm->[3] 2>/dev/null));
+ chomp(@list = qx($program $pm->[3] 2>/dev/null)) if $pm->[3];
}
elsif ($pm->[2] eq 'd'){
@list = main::globber($pm->[3]);
}
else {
# update message() if pm other than rpm disabled by default
- $error = main::message('pm-' . $pm->[1] . '-disabled');
+ $disabled = main::message('pm-disabled',$pm->[1]);
}
- $count = scalar @list if !$error;
+ $count = scalar @list if !$disabled;
# print Data::Dumper::Dumper \@list;
- if (!$error){
+ if (!$disabled){
if ($b_admin && $count && $pm->[4]){
$libs = count_libs(\@list,$pm->[5],$pm->[6]);
}
}
else {
- $pms{'note'} = $error;
+ $pms{'disabled'} = $disabled;
}
# if there is ambiguity about actual program installed, use this loop
if ($b_admin && $pm->[8]){
@@ -30215,22 +34095,25 @@ sub package_counts {
$gs = '';
}
}
- $pmts = join(',',sort @tools) if @tools;
+ if (@tools){
+ main::make_list_value(\@tools,\$pmts,',','sort');
+ }
}
$pms{$pm->[0]} = {
+ 'disabled' => $disabled,
'pkgs' => $count,
'libs' => $libs,
- 'note' => $error,
'tools' => $pmts,
};
$pms{'total'} += $count if defined $count;
# print Data::Dumper::Dumper \%pms;
}
}
- # print Data::Dumper::Dumper \%pms;
+ print 'package_counts %pms: ', Data::Dumper::Dumper \%pms if $dbg[65];
main::log_data('dump','Package managers: %pms',\%pms) if $b_log;
eval $end if $b_log;
}
+
sub appimage_counts {
if (@ps_cmd && (grep {/\bappimage(d|launcher)\b/} @ps_cmd)){
my @list = main::globber($ENV{'HOME'} . '/.{appimage/,local/bin/}*.[aA]pp[iI]mage');
@@ -30242,6 +34125,7 @@ sub appimage_counts {
$pms{'total'} += $count;
}
}
+
sub check_run {
if ($force{'pkg'}){
return 1;
@@ -30259,6 +34143,7 @@ sub check_run {
}
}
}
+
sub count_libs {
my ($items,$pos,$split) = @_;
my (@data);
@@ -30279,10 +34164,11 @@ sub count_libs {
package ParseEDID;
# CVT_ratios:
my @known_ratios = qw(5/4 4/3 3/2 16/10 15/9 16/9);
+
+# Set values
my @edid_info = (
['a8', '_header'],
['a2', 'manufacturer_name'],
-
['v', 'product_code'],
['V', 'serial_number'],
['C', 'week'],
@@ -30290,7 +34176,6 @@ my @edid_info = (
['C', 'edid_version'],
['C', 'edid_revision'],
['a', 'video_input_definition'],
-
['C', 'max_size_horizontal'], # in cm, 0 on projectors
['C', 'max_size_vertical'], # in cm, 0 on projectors
['C', 'gamma'],
@@ -30299,7 +34184,6 @@ my @edid_info = (
['a3' , 'established_timings'],
['a16', 'standard_timings'],
['a72', 'monitor_details'],
-
['C', 'extension_flag'],
['C', 'checksum'],
);
@@ -30323,7 +34207,6 @@ my %subfields = (
[1, 'DPMS_suspend'],
[1, 'DPMS_active_off'],
[1, 'rgb'],
-
[1, ''],
[1, 'sRGB_compliance'],
[1, 'has_preferred_timing'],
@@ -30376,7 +34259,6 @@ my %subfields = (
[4, 'vertical_image_size_hi'],
[8, 'horizontal_border'],
[8, 'vertical_border'],
-
[1, 'interlaced'],
[2, 'stereo'],
[2, 'digital_composite'],
@@ -30572,6 +34454,7 @@ my %vendors = (
'VIT' => 'Visitech', 'VLV' => 'Valve', 'VSC' => 'ViewSonic', 'VTK' => 'Viewteck', 'VTS' => 'VTech',
'WTC' => 'Wen Technology', 'XLX' => 'Xilinx', 'YMH' => 'Yamaha', 'ZCM' => 'Zenith',
);
+
sub _within_limit {
my ($value, $type, $limit) = @_;
$type eq 'min' ? $value >= $limit : $value <= $limit;
@@ -30594,6 +34477,7 @@ sub _get_many_bits {
}
\%h;
}
+
sub _build_detailed_timing {
my ($pixel_clock, $vv) = @_;
my $h = _get_many_bits($vv, 'detailed_timing');
@@ -30606,6 +34490,7 @@ sub _build_detailed_timing {
}
$h;
}
+
sub _add_standard_timing_modes {
my ($edid, $v) = @_;
my @aspect2ratio = (
@@ -30615,17 +34500,19 @@ sub _add_standard_timing_modes {
$v = [ map {
my $h = _get_many_bits($_, 'standard_timing');
$h->{X} = ($h->{X} + 31) * 8;
- if ($_ ne "\x20\x20" && $h->{X} > 256) { # cf VALID_TIMING in Xorg edid.h
+ if ($_ ne "\x20\x20" && $h->{X} > 256){ # cf VALID_TIMING in Xorg edid.h
$h->{vfreq} += 60;
- if ($h->{ratio} = $aspect2ratio[$h->{aspect}]) {
+ if ($h->{ratio} = $aspect2ratio[$h->{aspect}]){
delete $h->{aspect};
$h->{Y} = $h->{X} / eval($h->{ratio});
}
$h;
- } else { () }
+ }
+ else { () }
} unpack('a2' x (length($v) / 2), $v) ];
$v;
}
+
sub parse_edid {
eval $start if $b_log;
my ($raw_edid, $verbose) = @_;
@@ -30635,52 +34522,62 @@ sub parse_edid {
my $i = 0;
foreach (@edid_info) {
my ($field, $v) = ($_->[1], $vals[$i++]);
- if ($field eq 'year') {
+ if ($field eq 'year'){
$v += 1990;
- } elsif ($field eq 'manufacturer_name') {
+ }
+ elsif ($field eq 'manufacturer_name'){
my $h = _get_many_bits($v, 'manufacturer_name');
$v = join('', map { chr(ord('A') + $h->{$_} - 1) } 1 .. 3);
$v = "" if $v eq "@@@";
$edid{'manufacturer_name_nice'} = ($v && $vendors{$v}) ? $vendors{$v} : '';
- } elsif ($field eq 'video_input_definition') {
+ }
+ elsif ($field eq 'video_input_definition'){
$v = _get_many_bits($v, 'video_input_definition');
- } elsif ($field eq 'feature_support') {
+ }
+ elsif ($field eq 'feature_support'){
$v = _get_many_bits($v, 'feature_support');
- } elsif ($field eq 'color_characteristics') {
+ }
+ elsif ($field eq 'color_characteristics'){
$v = _get_many_bits($v, 'color_characteristics');
- } elsif ($field eq 'established_timings') {
+ }
+ elsif ($field eq 'established_timings'){
my $h = _get_many_bits($v, 'established_timings');
$v = [
sort { $a->{X} <=> $b->{X} || $a->{vfreq} <=> $b->{vfreq} }
map { /(\d+)x(\d+)_(\d+)(i?)/ ? { X => $1, Y => $2, vfreq => $3, $4 ? (interlace => 1) : () } : () }
grep { $h->{$_} } keys %$h ];
- } elsif ($field eq 'standard_timings') {
+ }
+ elsif ($field eq 'standard_timings'){
$v = _add_standard_timing_modes(\%edid, $v);
- } elsif ($field eq 'monitor_details') {
- while ($v) {
+ }
+ elsif ($field eq 'monitor_details'){
+ while ($v){
(my $pixel_clock, my $vv, $v) = unpack("v a16 a*", $v);
- if ($pixel_clock) {
+ if ($pixel_clock){
# detailed timing
my $h = _build_detailed_timing($pixel_clock, $vv);
push @{$edid{detailed_timings}}, $h
if $h->{horizontal_active} > 1 && $h->{vertical_active} > 1;
- } else {
+ }
+ else {
(my $flag, $vv) = unpack("n x a*", $vv);
- if ($flag == 0xfd) {
+ if ($flag == 0xfd){
# range
$edid{monitor_range} = _get_many_bits($vv, 'monitor_range');
- if ($edid{monitor_range}{pixel_clock_max} == 0xff) {
+ if ($edid{monitor_range}{pixel_clock_max} == 0xff){
delete $edid{monitor_range}{pixel_clock_max};
- } else {
+ }
+ else {
$edid{monitor_range}{pixel_clock_max} *= 10; #- to have it in MHz
}
- } elsif ($flag == 0xf) {
+ }
+ elsif ($flag == 0xf){
my $range = _get_many_bits($vv, 'manufacturer_specified_range_timing');
my $e = $edid{detailed_timings}[0];
my $valid = 1;
foreach my $m ('min', 'max') {
my %total;
- foreach my $dir ('horizontal', 'vertical') {
+ foreach my $dir ('horizontal', 'vertical'){
$range->{$dir . '_sync_pulse_width_' . $m} *= 2;
$range->{$dir . '_back_porch_' . $m} *= 2;
$range->{$dir . '_blanking_' . $m} *= 2;
@@ -30688,30 +34585,36 @@ sub parse_edid {
&& _within_limit($e->{$dir . '_blanking'}, $m, $range->{$dir . '_blanking_' . $m})
&& _within_limit($e->{$dir . '_sync_pulse_width'}, $m, $range->{$dir . '_sync_pulse_width_' . $m})
&& _within_limit($e->{$dir . '_blanking'} - $e->{$dir . '_sync_offset'} - $e->{$dir . '_sync_pulse_width'},
- $m, $range->{$dir . '_back_porch_' . $m})) {
+ $m, $range->{$dir . '_back_porch_' . $m})){
$total{$dir} = $e->{$dir . '_active'} + $range->{$dir . '_blanking_' . $m};
}
}
- if ($total{horizontal} && $total{vertical}) {
+ if ($total{horizontal} && $total{vertical}){
my $hfreq = $e->{pixel_clock} * 1000 / $total{horizontal};
my $vfreq = $hfreq * 1000 / $total{vertical};
$range->{'horizontal_' . ($m eq 'min' ? 'max' : 'min')} = _round($hfreq);
$range->{'vertical_' . ($m eq 'min' ? 'max' : 'min')} = _round($vfreq);
- } else {
+ }
+ else {
$valid = 0;
}
}
$edid{$valid ? 'monitor_range' : 'manufacturer_specified_range_timing'} = $range;
- } elsif ($flag == 0xfa) {
+ }
+ elsif ($flag == 0xfa){
push @{$edid{standard_timings}}, _add_standard_timing_modes(\%edid, unpack('a12', $vv));
- } elsif ($flag == 0xfc) {
+ }
+ elsif ($flag == 0xfc){
my $prev = $edid{monitor_name};
$edid{monitor_name} = ($prev ? "$prev " : '') . unpack('A13', $vv);
- } elsif ($flag == 0xfe) {
+ }
+ elsif ($flag == 0xfe){
push @{$edid{monitor_text}}, unpack('A13', $vv);
- } elsif ($flag == 0xff) {
+ }
+ elsif ($flag == 0xff){
push @{$edid{serial_number2}}, unpack('A13', $vv);
- } elsif ($vv ne "\0" x 13 && $vv ne " " x 13) {
+ }
+ elsif ($vv ne "\0" x 13 && $vv ne " " x 13){
push(@warnings, "parse_edid: unknown flag $flag");
warn "$warnings[-1]\n" if $verbose;
}
@@ -30720,15 +34623,15 @@ sub parse_edid {
}
$edid{$field} = $v if $field && $field !~ /^_/;
}
- foreach (@eedid_blocks) {
+ foreach (@eedid_blocks){
my ($tag, $v) = unpack("C a*", $_);
- if ($tag == 0x02) { # CEA EDID
+ if ($tag == 0x02){ # CEA EDID
my $dtd_offset;
($dtd_offset, $v) = unpack("x C x a*", $v);
next if $dtd_offset < 4;
$dtd_offset -= 4;
- while ($dtd_offset > 0) {
- if (!$v) {
+ while ($dtd_offset > 0){
+ if (!$v){
push(@warnings, "parse_edid: DTD offset outside of available data");
warn "$warnings[-1]\n" if $verbose;
last;
@@ -30737,12 +34640,12 @@ sub parse_edid {
$dtd_offset -= $h->{size} + 1;
my $vv;
($vv, $v) = unpack("x a$h->{size} a*", $v);
- if ($h->{type} == 0x02) { # Video Data Block
+ if ($h->{type} == 0x02){ # Video Data Block
my @vmodes = unpack("a" x $h->{size}, $vv);
- foreach my $vmode (@vmodes) {
+ foreach my $vmode (@vmodes){
$h = _get_many_bits($vmode, 'cea_video_data_block');
my $cea_mode = $cea_video_modes[$h->{mode} - 1];
- if (!$cea_mode) {
+ if (!$cea_mode){
push(@warnings, "parse_edid: unhandled CEA mode $h->{mode}");
warn "$warnings[-1]\n" if $verbose;
next;
@@ -30753,14 +34656,15 @@ sub parse_edid {
}
}
}
- while (length($v) >= 18) {
+ while (length($v) >= 18){
(my $pixel_clock, my $vv, $v) = unpack("v a16 a*", $v);
last if !$pixel_clock;
my $h = _build_detailed_timing($pixel_clock, $vv);
push @{$edid{detailed_timings}}, $h
if $h->{horizontal_active} > 1 && $h->{vertical_active} > 1;
}
- } else {
+ }
+ else {
push(@warnings, "parse_edid: unknown tag $tag");
warn "$warnings[-1]\n" if $verbose;
}
@@ -30773,24 +34677,24 @@ sub parse_edid {
}
$edid{product_code_h} = '0x'. $edid{product_code_h};
}
- if ($edid{monitor_range}) {
+ if ($edid{monitor_range}){
$edid{HorizSync} = $edid{monitor_range}{horizontal_min} . '-' . $edid{monitor_range}{horizontal_max};
$edid{VertRefresh} = $edid{monitor_range}{vertical_min} . '-' . $edid{monitor_range}{vertical_max};
}
- if ($edid{max_size_vertical}) {
+ if ($edid{max_size_vertical}){
$edid{ratio} = $edid{max_size_horizontal} / $edid{max_size_vertical};
$edid{ratio_name} = _ratio_name($edid{max_size_horizontal}, $edid{max_size_vertical}, 'cm');
$edid{ratio_precision} = 'cm';
}
- if ($edid{feature_support}{has_preferred_timing} && $edid{detailed_timings}[0]) {
+ if ($edid{feature_support}{has_preferred_timing} && $edid{detailed_timings}[0]){
$edid{detailed_timings}[0]{preferred} = 1;
}
- foreach my $h (@{$edid{detailed_timings}}) {
+ foreach my $h (@{$edid{detailed_timings}}){
# EDID standard is ambiguous on how interlaced modes should be
# specified; workaround clearly broken modes:
- if ($h->{interlaced}) {
- foreach ("720x480", "1440x480", "2880x480", "720x576", "1440x576", "2880x576", "1920x1080") {
- if ($_ eq $h->{horizontal_active} . 'x' . $h->{vertical_active} * 2) {
+ if ($h->{interlaced}){
+ foreach ("720x480", "1440x480", "2880x480", "720x576", "1440x576", "2880x576", "1920x1080"){
+ if ($_ eq $h->{horizontal_active} . 'x' . $h->{vertical_active} * 2){
$h->{vertical_active} *= 2;
$h->{vertical_blanking} *= 2;
$h->{vertical_sync_offset} *= 2;
@@ -30806,39 +34710,39 @@ sub parse_edid {
vertical => _define($h->{vertical_image_size}) / 10,
);
my ($error) = sort { $b <=> $a } map { abs($edid{'max_size_' . $_} - $in_cm{$_}) } keys %in_cm;
- if ($error <= 0.5) {
+ if ($error <= 0.5){
$edid{'max_size_' . $_} = $in_cm{$_} foreach keys %in_cm;
$edid{max_size_precision} = 'mm';
}
- if ($error < 1 && $in_cm{vertical}) {
+ if ($error < 1 && $in_cm{vertical}){
# using it for the ratio
$edid{ratio} = $in_cm{horizontal} / $in_cm{vertical};
$edid{ratio_name} = _ratio_name($in_cm{horizontal}, $in_cm{vertical}, 'mm');
$edid{ratio_precision} = 'mm';
}
if ($edid{ratio_precision} &&
- abs($edid{ratio} - $h->{horizontal_active} / $h->{vertical_active}) > ($edid{ratio_precision} eq 'mm' ? 0.02 : 0.2)) {
+ abs($edid{ratio} - $h->{horizontal_active} / $h->{vertical_active}) > ($edid{ratio_precision} eq 'mm' ? 0.02 : 0.2)){
$h->{bad_ratio} = 1;
}
- if ($edid{ratio_name}) {
+ if ($edid{ratio_name}){
$edid{ratios} = $edid{ratio_name};
$edid{ratios} =~ s|/|:|g;
$edid{ratios} = [split(/ or /, $edid{ratios})]; # "3/2 or 16/10"
}
- if ($edid{max_size_vertical}) {
+ if ($edid{max_size_vertical}){
$h->{vertical_dpi} = $h->{vertical_active} / $edid{max_size_vertical} * 2.54;
}
- if ($edid{max_size_horizontal}) {
+ if ($edid{max_size_horizontal}){
$h->{horizontal_dpi} = $h->{horizontal_active} / $edid{max_size_horizontal} * 2.54;
}
- if ($h->{horizontal_image_size}) {
+ if ($h->{horizontal_image_size}){
$h->{horizontal_image_size_i} = sprintf('%.2f',($h->{horizontal_image_size}/25.4)) + 0;
}
- if ($h->{vertical_image_size}) {
+ if ($h->{vertical_image_size}){
$h->{vertical_image_size_i} = sprintf('%.2f',($h->{vertical_image_size}/25.4)) + 0;
}
my $dpi_string = '';
- if ($h->{vertical_dpi} && $h->{horizontal_dpi}) {
+ if ($h->{vertical_dpi} && $h->{horizontal_dpi}){
$dpi_string =
abs($h->{vertical_dpi} / $h->{horizontal_dpi} - 1) < 0.05 ?
sprintf("%d dpi", $h->{horizontal_dpi}) :
@@ -30858,17 +34762,14 @@ sub parse_edid {
$h->{ModeLine} = sprintf(qq("%dx%d" $h->{pixel_clock} %d %d %d %d %d %d %d %d %shsync %svsync%s),
$h->{horizontal_active}, $h->{vertical_active},
-
$h->{horizontal_active},
$h->{horizontal_active} + $h->{horizontal_sync_offset},
$h->{horizontal_active} + $h->{horizontal_sync_offset} + $h->{horizontal_sync_pulse_width},
$horizontal_total,
-
$h->{vertical_active},
$h->{vertical_active} + $h->{vertical_sync_offset},
$h->{vertical_active} + $h->{vertical_sync_offset} + $h->{vertical_sync_pulse_width},
$vertical_total,
-
$h->{horizontal_sync_positive} ? '+' : '-',
$h->{vertical_sync_positive} ? '+' : '-',
$h->{interlaced} ? ' Interlace' : '');
@@ -30883,6 +34784,7 @@ sub parse_edid {
eval $end if $b_log;
\%edid;
}
+
sub _edid_errors {
my $edid = shift @_;
if (!defined $edid->{edid_version}){
@@ -30914,11 +34816,13 @@ sub _edid_errors {
}
}
}
+
sub _edid_error {
my ($edid,$error,$data) = @_;
$edid->{edid_errors} = [] if !$edid->{edid_errors};
push(@{$edid->{edid_errors}},main::message($error,$data));
}
+
sub _nearest_ratio {
my ($ratio, $max_error) = @_;
my @sorted =
@@ -30929,32 +34833,45 @@ sub _nearest_ratio {
} @known_ratios;
$sorted[0][0];
}
+
sub _ratio_name {
my ($horizontal, $vertical, $precision) = @_;
- if ($precision eq 'mm') {
+ if ($precision eq 'mm'){
_nearest_ratio($horizontal / $vertical, 0.1);
- } else {
+ }
+ else {
my $error = 0.5;
my $ratio1 = _nearest_ratio(($horizontal + $error) / ($vertical - $error), 0.2);
my $ratio2 = _nearest_ratio(($horizontal - $error) / ($vertical + $error), 0.2);
$ratio1 && $ratio2 or return;
- if ($ratio1 eq $ratio2) {
+ if ($ratio1 eq $ratio2){
$ratio1;
- } else {
+ }
+ else {
my $ratio = _nearest_ratio($horizontal / $vertical, 0.2);
join(' or ', $ratio, $ratio eq $ratio1 ? $ratio2 : $ratio1);
}
}
}
-sub _define { defined $_[0] ? $_[0] : 0 }
-sub _sqr { $_[0] * $_[0] }
-sub _round { int($_[0] + 0.5) }
+
+sub _define {
+ defined $_[0] ? $_[0] : 0;
+}
+
+sub _sqr {
+ $_[0] * $_[0];
+}
+
+sub _round {
+ int($_[0] + 0.5);
+}
}
-## PartitionData - set/get
+## PartitionData: public methods: set(), get()
# for /proc/partitions only, see DiskDataBSD for BSD partition data.
{
package PartitionData;
+
sub set {
my ($type) = @_;
$loaded{'partition-data'} = 1;
@@ -30962,7 +34879,8 @@ sub set {
proc_data($file);
}
}
-# 1 - partition name, without /dev, like sda1, sde
+
+# args: 0: partition name, without /dev, like sda1, sde
sub get {
eval $start if $b_log;
my $item = $_[0];
@@ -30982,7 +34900,7 @@ sub proc_data {
eval $start if $b_log;
my $file = $_[0];
if ($fake{'partitions'}){
- # $file = "$fake_data_dir/proc-partitions-1.txt";
+ # $file = "$fake_data_dir/block-devices/proc-partitions/proc-partitions-1.txt";
}
my @parts = main::reader($file,'strip');
# print Data::Dumper::Dumper \@parts;
@@ -30996,7 +34914,7 @@ sub proc_data {
}
}
-# args: 1 - pci device string; 2 - pci cleaned subsystem string
+# args: 0: pci device string; 1: pci cleaned subsystem string
sub get_pci_vendor {
eval $start if $b_log;
my ($device, $subsystem) = @_;
@@ -31096,132 +35014,869 @@ sub get_pcie_data {
eval $end if $b_log;
}
-sub set_ps_aux {
+## PowerData: public method: get()
+# No BSD support currently. Test by !$bsd_type. Should any BSD data source
+# appear, make bsd_data() and add $bsd_type switch here, remove from caller.
+{
+package PowerData;
+my $power = {};
+
+# args: 0: $power by ref
+sub get {
+ eval $start if $b_log;
+ sys_data();
+ eval $end if $b_log;
+ return $power;
+}
+
+sub sys_data {
eval $start if $b_log;
- my ($header,$ps,@temp);
- # note: some ps cut off output based on terminal width
- # ww sets width unlimited
- $loaded{'ps-aux'} = 1;
- $ps = grabber("ps wwaux 2>/dev/null",'','strip','ref');
+ # Some systems also report > 1 wakeup events per wakeup with
+ # /sys/power/wakeup_count, thus, we are using /sys/power/suspend_stats/success
+ # which does not appear to have that issue. There is more info in suspend_stats
+ # which we might think of using, particularly fail events, which can be useful.
+ # this increments on suspend, but you can't see it until wake, numbers work.
+ # note: seen android instance where reading file wakeup_count hangs endlessly.
+ my %files = ('suspend-resumes' => '/sys/power/suspend_stats/success');
+ if ($extra > 2){
+ $files{'hibernate'} = '/sys/power/disk';
+ $files{'hibernate-image-size'} = '/sys/power/image_size';
+ $files{'suspend'} = '/sys/power/mem_sleep';
+ $files{'suspend-fails'} = '/sys/power/suspend_stats/fail';
+ $files{'states-avail'} = '/sys/power/state';
+ }
+ foreach (sort keys %files){
+ if (-r $files{$_}){
+ $power->{$_} = main::reader($files{$_}, 'strip', 0);
+ if ($_ eq 'states-avail'){
+ $power->{$_} =~ s/\s+/,/g if $power->{$_};
+ }
+ # seen: s2idle [deep] OR [s2idle] deep OR s2idle shallow [deep]
+ elsif ($_ eq 'hibernate' || $_ eq 'suspend'){
+ # [item] is currently selected/active option
+ if ($power->{$_}){
+ if ($power->{$_} =~ /\[([^\]]+)\]/){
+ $power->{$_ . '-active'} = $1;
+ $power->{$_} =~ s/\[$1\]//;
+ $power->{$_} =~ s/^\s+|\s+$//g;
+ }
+ # some of these can get pretty long, so handle with make_list_value
+ if ($power->{$_}){
+ main::make_list_value([split(/\s+/,$power->{$_})],\$power->{$_},',');
+ $power->{$_ . '-avail'} = $power->{$_};
+ }
+ }
+ }
+ # size is in bytes
+ elsif ($_ eq 'hibernate-image-size'){
+ $power->{$_} = main::get_size(($power->{$_}/1024),'string') if defined $power->{$_};
+ }
+ }
+ }
+ print 'power: ', Data::Dumper::Dumper $power if $dbg[58];
+ main::log_data('dump','$power',$power) if $b_log;
+ eval $end if $b_log;
+}
+}
+
+# ProgramData
+# public methods:
+# full(): returns (print name, version nu, [full version data output]).
+# values(): returns program values array
+# version(): returns program version number
+{
+package ProgramData;
+my $output;
+
+# returns array of: 0: program print name 1: program version
+# args: 0: program values ID [usually program name];
+# 1: program alternate name, or path [allows for running different command];
+# 2: $extra level. Note that StartClient runs BEFORE -x levels are set!;
+# 3: [array ref/undef] return full version output block
+# Only use this function when you only need the name/version data returned
+sub full {
+ eval $start if $b_log;
+ my ($values_id,$version_id,$level,$b_return_full) = @_;
+ my @full;
+ $level = 0 if !$level;
+ # print "val_id: $values_id ver_id:$version_id lev:$level ex:$extra\n";
+ ProgramData::set_values() if !$loaded{'program-values'};
+ $version_id = $values_id if !$version_id;
+ if (my $values = $program_values{$values_id}){
+ $full[0] = $values->[3];
+ # programs that have no version method return 0 0 for index 1 and 2
+ if ($extra >= $level && $values->[1] && $values->[2]){
+ $full[1] = version($version_id,$values->[0],$values->[1],$values->[2],
+ $values->[5],$values->[6],$values->[7],$values->[8]);
+ }
+ }
+ # should never trip since program should be whitelist, but mistakes happen!
+ $full[0] ||= $values_id;
+ $full[1] ||= '';
+ $full[2] = $output if $b_return_full;
+ eval $end if $b_log;
+ return @full;
+}
+
+# It's almost 1000 times slower to load these each time values() is called!!
+# %program_values: key: desktop/app command for --version => [0: search string;
+# 1: space print number; 2: [optional] version arg: -v, version, etc;
+# 3: print name; 4: console 0/1;
+# 5: [optional] exit first line 0/1 [alt: if version=file replace value with \s];
+# 6: [optional] 0/1 stderr output; 7: replace regex; 8: extra data]
+sub set_values {
+ $loaded{'program-values'} = 1;
+ %program_values = (
+ ## Clients (IRC,chat) ##
+ 'bitchx' => ['bitchx',2,'','BitchX',1,0,0,'',''],# special
+ 'finch' => ['finch',2,'-v','Finch',1,1,0,'',''],
+ 'gaim' => ['[0-9.]+',2,'-v','Gaim',0,1,0,'',''],
+ 'ircii' => ['[0-9.]+',3,'-v','ircII',1,1,0,'',''],
+ 'irssi' => ['irssi',2,'-v','Irssi',1,1,0,'',''],
+ 'irssi-text' => ['irssi',2,'-v','Irssi',1,1,0,'',''],
+ 'konversation' => ['konversation',2,'-v','Konversation',0,0,0,'',''],
+ 'kopete' => ['Kopete',2,'-v','Kopete',0,0,0,'',''],
+ 'ksirc' => ['KSirc',2,'-v','KSirc',0,0,0,'',''],
+ 'kvirc' => ['[0-9.]+',2,'-v','KVIrc',0,0,1,'',''], # special
+ 'pidgin' => ['[0-9.]+',2,'-v','Pidgin',0,1,0,'',''],
+ 'quassel' => ['',1,'-v','Quassel [M]',0,0,0,'',''], # special
+ 'quasselclient' => ['',1,'-v','Quassel',0,0,0,'',''],# special
+ 'quasselcore' => ['',1,'-v','Quassel (core)',0,0,0,'',''],# special
+ 'gribble' => ['^Supybot',2,'--version','Gribble',1,0,0,'',''],# special
+ 'limnoria' => ['^Supybot',2,'--version','Limnoria',1,0,0,'',''],# special
+ 'supybot' => ['^Supybot',2,'--version','Supybot',1,0,0,'',''],# special
+ 'weechat' => ['[0-9.]+',1,'-v','WeeChat',1,0,0,'',''],
+ 'weechat-curses' => ['[0-9.]+',1,'-v','WeeChat',1,0,0,'',''],
+ 'xchat-gnome' => ['[0-9.]+',2,'-v','X-Chat-Gnome',1,1,0,'',''],
+ 'xchat' => ['[0-9.]+',2,'-v','X-Chat',1,1,0,'',''],
+ ## Desktops / wm / compositors ##
+ '2bwm' => ['^2bwm',0,'0','2bWM',0,1,0,'',''], # unverified/based on mcwm
+ '3dwm' => ['^3dwm',0,'0','3Dwm',0,1,0,'',''], # unverified
+ '5dwm' => ['^5dwm',0,'0','5Dwm',0,1,0,'',''], # unverified
+ '9wm' => ['^9wm',3,'-version','9wm',0,1,0,'',''],
+ 'aewm' => ['^aewm',3,'--version','aewm',0,1,0,'',''],
+ 'aewm++' => ['^Version:',2,'-version','aewm++',0,1,0,'',''],
+ 'afterstep' => ['^afterstep',3,'--version','AfterStep',0,1,0,'',''],
+ 'amiwm' => ['^amiwm',0,'0','AmiWM',0,1,0,'',''], # no version
+ 'antiwm' => ['^antiwm',0,'0','AntiWM',0,1,0,'',''], # no version known
+ 'asc' => ['^asc',0,'0','asc',0,1,0,'',''],
+ 'awc' => ['^awc',0,'0','awc',0,1,0,'',''], # unverified
+ 'awesome' => ['^awesome',2,'--version','awesome',0,1,0,'',''],
+ 'beryl' => ['^beryl',0,'0','Beryl',0,1,0,'',''], # unverified; legacy
+ 'bismuth' => ['^bismuth',0,'0','Bismuth',0,1,0,'',''], # unverified
+ 'blackbox' => ['^Blackbox',2,'--version','Blackbox',0,1,0,'',''],
+ 'bspwm' => ['^\S',1,'-v','bspwm',0,1,0,'',''],
+ 'budgie-desktop' => ['^budgie-desktop',2,'--version','Budgie',0,1,0,'',''],
+ 'budgie-wm' => ['^budgie',0,'0','budgie-wm',0,1,0,'',''],
+ 'cage' => ['^cage',3,'-v','Cage',0,1,0,'',''],
+ 'cagebreak' => ['^Cagebreak',3,'-v','Cagebreak',0,1,0,'',''],
+ 'calmwm' => ['^calmwm',0,'0','CalmWM',0,1,0,'',''], # unverified
+ 'cardboard' => ['^cardboard',0,'0','Cardboard',0,1,0,'',''], # unverified
+ 'catwm' => ['^catwm',0,'0','catwm',0,1,0,'',''], # unverified
+ 'cde' => ['^cde',0,'0','CDE',0,1,0,'',''], # unverified
+ 'chameleonwm' => ['^chameleon',0,'0','ChameleonWM',0,1,0,'',''], # unverified
+ 'cinnamon' => ['^cinnamon',2,'--version','Cinnamon',0,1,0,'',''],
+ 'clfswm' => ['^clsfwm',0,'0','clfswm',0,1,0,'',''], # no version
+ 'comfc' => ['^comfc',0,'0','comfc',0,1,0,'',''], # unverified
+ 'compiz' => ['^compiz',2,'--version','Compiz',0,1,0,'',''],
+ 'compton' => ['^\d',1,'--version','Compton',0,1,0,'',''],
+ 'cosmic-comp' => ['^cosmic-comp',0,'0','cosmic-comp',0,1,0,'',''], # unverified
+ 'ctwm' => ['^\S',1,'-version','ctwm',0,1,0,'',''],
+ 'cwm' => ['^cwm',0,'0','CWM',0,1,0,'',''], # no version
+ 'dawn' => ['^dawn',1,'-v','dawn',0,1,1,'^dawn-',''], # to stderr, not verified
+ 'dcompmgr' => ['^dcompmgr',0,'0','dcompmgr',0,1,0,'',''], # unverified
+ 'deepin' => ['^Version',2,'file','Deepin',0,100,'=','','/etc/deepin-version'], # special
+ 'deepin-metacity' => ['^metacity',2,'--version','Deepin-Metacity',0,1,0,'',''],
+ 'deepin-mutter' => ['^mutter',2,'--version','Deepin-Mutter',0,1,0,'',''],
+ 'deepin-wm' => ['^gala',0,'0','DeepinWM',0,1,0,'',''], # no version
+ 'draco' => ['^draco',0,'0','Draco',0,1,0,'',''], # no version
+ 'dusk' => ['^dusk',1,'-v','dusk',0,1,1,'^dusk-',''], # to stderr, not verified
+ 'dtwm' => ['^dtwm',0,'0','dtwm',0,1,0,'',''],# no version
+ 'dwc' => ['^dwc',0,'0','dwc',0,1,0,'',''], # unverified
+ 'dwl' => ['^dwl',0,'0','dwl',0,1,0,'',''], # unverified
+ 'dwm' => ['^dwm',1,'-v','dwm',0,1,1,'^dwm-',''],
+ 'echinus' => ['^echinus',1,'-v','echinus',0,1,1,'',''], # echinus-0.4.9 (c)...
+ # only listed here for compositor values, version data comes from xprop
+ 'enlightenment' => ['^enlightenment',0,'0','Enlightenment',0,1,0,'',''], # no version. Starts new
+ 'epd-wm' => ['^epd-wm',0,'0','epd-wm',0,1,0,'',''], # unverified
+ 'evilwm' => ['evilwm',3,'-V','evilwm',0,1,0,'',''],# might use full path in match
+ 'feathers' => ['^feathers',0,'0','feathers',0,1,0,'',''], # unverified
+ 'fenestra' => ['^fenestra',0,'0','fenestra',0,1,0,'',''], # unverified
+ 'fireplace' => ['^fireplace',0,'0','fireplace',0,1,0,'',''], # unverified
+ 'fluxbox' => ['^fluxbox',2,'-v','Fluxbox',0,1,0,'',''],
+ 'flwm' => ['^flwm',0,'0','FLWM',0,0,1,'',''], # no version
+ # openbsd changed: version string: [FVWM[[main] Fvwm.. sigh, and outputs to stderr. Why?
+ 'fvwm' => ['^fvwm',2,'-version','FVWM',0,1,0,'',''],
+ 'fvwm1' => ['^Fvwm',3,'-version','FVWM1',0,1,1,'',''],
+ 'fvwm2' => ['^fvwm',2,'--version','FVWM2',0,1,0,'',''],
+ 'fvwm3' => ['^fvwm',2,'--version','FVWM3',0,1,0,'',''],
+ 'fvwm95' => ['^fvwm',2,'--version','FVWM95',0,1,1,'',''],
+ # Note: first line can be: FVWM-Cystal starting... so always use fvwm --version
+ 'fvwm-crystal' => ['^fvwm',2,'--version','FVWM-Crystal',0,0,0,'',''], # for print name fvwm
+ 'gala' => ['^gala',2,'--version','gala',0,1,0,'',''], # pantheon wm: can be slow result
+ 'gamescope' => ['^gamescope',0,'0','Gamescope',0,1,0,'',''], # unverified
+ 'glass' => ['^glass',3,'-v','Glass',0,1,0,'',''],
+ 'gnome' => ['^gnome',3,'--version','GNOME',0,1,0,'',''], # no version, print name
+ 'gnome-about' => ['^gnome',3,'--version','GNOME',0,1,0,'',''],
+ 'gnome-shell' => ['^gnome',3,'--version','gnome-shell',0,1,0,'',''],
+ 'greenfield' => ['^greenfield',0,'0','Greenfield',0,1,0,'',''], # unverified
+ 'grefson' => ['^grefson',0,'0','Grefson',0,1,0,'',''], # unverified
+ 'hackedbox' => ['^hackedbox',2,'-version','HackedBox',0,1,0,'',''], # unverified, assume blackbox
+ # note, herbstluftwm when launched with full path returns full path in version string
+ 'herbstluftwm' => ['herbstluftwm',2,'--version','herbstluftwm',0,1,0,'',''],
+ 'hikari' => ['^hikari',0,'0','hikari',0,1,0,'',''], # unverified
+ 'hopalong' => ['^hopalong',0,'0','Hopalong',0,1,0,'',''], # unverified
+ 'hyprctl' => ['^Tag:',2,'version','Hyprland',0,0,0,'',''], # method to get hyprland version
+ 'hyprland' => ['^hyprland',0,'0','Hyprland',0,0,0,'',''], # uses hyprctl for version
+ 'i3' => ['^i3',3,'--version','i3',0,1,0,'',''],
+ 'icewm' => ['^icewm',2,'--version','IceWM',0,1,0,'',''],
+ 'inaban' => ['^inaban',0,'0','inaban',0,1,0,'',''], # unverified
+ 'instantwm' => ['^instantwm',1,'-v','instantWM',0,1,1,'^instantwm-?(instantos-?)?',''],
+ 'ion3' => ['^ion3',0,'--version','Ion3',0,1,0,'',''], # unverified; also shell called ion
+ 'japokwm' => ['^japokwm',0,'0','japokwm',0,1,0,'',''], # unverified
+ 'jbwm' => ['jbwm',3,'-v','JBWM',0,1,0,'',''], # might use full path in match
+ 'jwm' => ['^jwm',2,'-v','JWM',0,1,0,'',''],
+ 'kded' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,0,0,'\sDevelopment Platform',''],
+ 'kded1' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,0,0,'\sDevelopment Platform',''],
+ 'kded2' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,0,0,'\sDevelopment Platform',''],
+ 'kded3' => ['^KDE( Development Platform)?:',2,'--version','KDE',0,0,0,'\sDevelopment Platform',''],
+ 'kded4' => ['^KDE( Development Platform)?:',2,'--version','KDE Plasma',0,0,0,'\sDevelopment Platform',''],
+ 'kdesktop-trinity' => ['^TDE:',2,'--version','TDE (Trinity)',0,0,0],
+ 'kiwmi' => ['^kwimi',0,'0','kiwmi',0,1,0,'',''], # unverified
+ 'ksmcon' => ['^ksmcon',0,'0','ksmcon',0,1,0,'',''],# no version
+ 'kwin' => ['^kwin',0,'0','kwin',0,1,0,'',''],# no version, same as kde
+ 'kwin-kde' => ['^kwin',2,'--version','KDE Plasma',0,1,0,'',''],# only for 5+, same as KDE version
+ 'kwin_wayland' => ['^kwin_wayland',0,'0','kwin_wayland',0,1,0,'',''],# no version, same as kde
+ 'kwin_x11' => ['^kwin_x11',0,'0','kwin_x11',0,1,0,'',''],# no version, same as kde
+ 'kwinft' => ['^kwinft',0,'0','KWinFT',0,1,0,'',''], # unverified
+ 'labwc' => ['^labwc',0,'0','LabWC',0,1,0,'',''], # unverified
+ 'laikawm' => ['^laikawm',0,'0','LaikaWM',0,1,0,'',''], # unverified
+ 'larswm' => ['^larswm',2,'-v','larswm',0,1,1,'',''],
+ 'leftwm' => ['^leftwm',0,'0','LeftWM',0,1,0,'',''],# no version, in CHANGELOG
+ 'liri' => ['^liri',0,'0','liri',0,1,0,'',''],
+ 'lipstick' => ['^lipstick',0,'0','Lipstick',0,1,0,'',''], # unverified
+ 'liri' => ['^liri',0,'0','liri',0,1,0,'',''], # unverified
+ 'lumina-desktop' => ['^\S',1,'--version','Lumina',0,1,1,'',''],
+ 'lwm' => ['^lwm',0,'0','lwm',0,1,0,'',''], # no version
+ 'lxpanel' => ['^lxpanel',2,'--version','LXDE',0,1,0,'',''],
+ # command: lxqt-panel
+ 'lxqt-panel' => ['^lxqt-panel',2,'--version','LXQt',0,1,0,'',''],
+ 'lxqt-session' => ['^lxqt-session',2,'--version','LXQt',0,1,0,'',''],
+ 'lxqt-variant' => ['^lxqt-panel',0,'0','LXQt-Variant',0,1,0,'',''],
+ 'lxsession' => ['^lxsession',0,'0','lxsession',0,1,0,'',''],
+ 'mahogany' => ['^mahogany',0,'0','Mahogany',0,1,0,'',''], # unverified
+ 'manokwari' => ['^manokwari',0,'0','Manokwari',0,1,0,'',''],
+ 'marina' => ['^marina',0,'0','Marina',0,1,0,'',''], # unverified
+ 'marco' => ['^marco',2,'--version','marco',0,1,0,'',''],
+ 'matchbox' => ['^matchbox',0,'0','Matchbox',0,1,0,'',''],
+ 'matchbox-window-manager' => ['^matchbox',2,'--help','Matchbox',0,0,0,'',''],
+ 'mate-about' => ['^MATE[[:space:]]DESKTOP',-1,'--version','MATE',0,1,0,'',''],
+ # note, mate-session when launched with full path returns full path in version string
+ 'mate-session' => ['mate-session',-1,'--version','MATE',0,1,0,'',''],
+ 'maynard' => ['^maynard',0,'0','maynard',0,1,0,'',''], # unverified
+ 'maze' => ['^maze',0,'0','Maze',0,1,0,'',''], # unverified
+ 'mcompositor' => ['^mcompositor',0,'0','MCompositor',0,1,0,'',''], # unverified
+ 'mcwm' => ['^mcwm',0,'0','mcwm',0,1,0,'',''], # unverified/see 2bwm
+ 'metacity' => ['^metacity',2,'--version','Metacity',0,1,0,'',''],
+ 'metisse' => ['^metisse',0,'0','metisse',0,1,0,'',''],
+ 'mini' => ['^Mini',5,'--version','Mini',0,1,0,'',''],
+ 'mir' => ['^mir',0,'0','mir',0,1,0,'',''],# unverified
+ 'miwm' => ['^miwm',0,'0','MIWM',0,1,0,'',''], # no version
+ 'mlvwm' => ['^mlvwm',3,'--version','MLVWM',0,1,1,'',''],
+ 'moblin' => ['^moblin',0,'0','moblin',0,1,0,'',''],# unverified
+ 'moksha' => ['^\S',1,'-version','Moksha',0,1,0,'',''], # v: x.y.z
+ 'monsterwm' => ['^monsterwm',0,'0','monsterwm',0,1,0,'',''],# unverified
+ 'motorcar' => ['^motorcar',0,'0','motorcar',0,1,0,'',''],# unverified
+ 'muffin' => ['^mu(ffin|tter)',2,'--version','Muffin',0,1,0,'',''],
+ 'musca' => ['^musca',0,'-v','Musca',0,1,0,'',''], # unverified
+ 'mutter' => ['^mutter',2,'--version','Mutter',0,1,0,'',''],
+ 'mvwm' => ['^mvwm',0,'0','mvwm',0,1,0,'',''], # unverified
+ 'mwm' => ['^mwm',0,'0','MWM',0,1,0,'',''],# no version
+ 'nawm' => ['^nawm',0,'0','nawm',0,1,0,'',''],# unverified
+ 'newm' => ['^newm',0,'0','newm',0,1,0,'',''], # unverified
+ 'notion' => ['^.',1,'--version','Notion',0,1,0,'',''],
+ 'nscde' => ['^(fvwm|nscde)',2,'--version','NsCDE',0,1,0,'',''],
+ 'nucleus' => ['^nucleus',0,'0','Nucleus',0,1,0,'',''], # unverified
+ 'openbox' => ['^openbox',2,'--version','Openbox',0,1,0,'',''],
+ 'orbital' => ['^orbital',0,'0','Orbital',0,1,0,'',''],# unverified
+ 'orbment' => ['^orbment',0,'0','orbment',0,1,0,'',''], # unverified
+ 'pantheon' => ['^pantheon',0,'0','Pantheon',0,1,0,'',''],# no version
+ 'papyros' => ['^papyros',0,'0','papyros',0,1,0,'',''],# no version
+ 'pekwm' => ['^pekwm',3,'--version','PekWM',0,1,0,'',''],
+ 'penrose' => ['^penrose',0,'0','Penrose',0,1,0,'',''],# no version?
+ 'perceptia' => ['^perceptia',0,'0','perceptia',0,1,0,'',''],
+ 'phoc' => ['^phoc',0,'0','phoc',0,1,0,'',''], # unverified
+ 'picom' => ['^\S',1,'--version','Picom',0,1,0,'^v',''],
+ 'plasmashell' => ['^plasmashell',2,'--version','KDE Plasma',0,1,0,'',''],
+ 'polonium' => ['^polonium',0,'0','polonium',0,1,0,'',''], # unverified
+ 'pywm' => ['^pywm',0,'0','pywm',0,1,0,'',''], # unverified
+ 'qtile' => ['^',1,'--version','Qtile',0,1,0,'',''],
+ 'qvwm' => ['^qvwm',0,'0','qvwm',0,1,0,'',''], # unverified
+ 'razor-session' => ['^razor',0,'0','Razor-Qt',0,1,0,'',''],
+ 'ratpoison' => ['^ratpoison',2,'--version','Ratpoison',0,1,0,'',''],
+ 'river' => ['^river',0,'0','River',0,1,0,'',''], # unverified
+ 'rootston' => ['^rootston',0,'0','rootston',0,1,0,'',''], # unverified, wlroot ref
+ 'rustland' => ['^rustland',0,'0','rustland',0,1,0,'',''], # unverified
+ 'sapphire' => ['^version sapphire',3,'-version','sapphire',0,1,0,'',''],
+ 'sawfish' => ['^sawfish',3,'--version','Sawfish',0,1,0,'',''],
+ 'scrotwm' => ['^scrotwm',2,'-v','scrotwm',0,1,1,'welcome to scrotwm',''],
+ 'simulavr' => ['simulavr^',0,'0','SimulaVR',0,1,0,'',''], # unverified
+ 'skylight' => ['^skylight',0,'0','Skylight',0,1,0,'',''], # unverified
+ 'smithay' => ['^smithay',0,'0','Smithay',0,1,0,'',''], # unverified
+ 'sommelier' => ['^sommelier',0,'0','sommelier',0,1,0,'',''], # unverified
+ 'snapwm' => ['^snapwm',0,'0','snapwm',0,1,0,'',''], # unverified
+ 'spectrwm' => ['^spectrwm',2,'-v','spectrwm',0,1,1,'welcome to spectrwm',''],
+ # out of stump, 2 --version, but in tries to start new wm instance endless hang
+ 'stumpwm' => ['^SBCL',0,'--version','StumpWM',0,1,0,'',''], # hangs when run in wm
+ 'subtle' => ['^subtle',2,'--version','subtle',0,1,0,'',''],
+ 'surfaceflinger' => ['surfaceflinger^',0,'0','SurfaceFlinger',0,1,0,'',''], # Android, unverified
+ 'sway' => ['^sway',3,'-v','Sway',0,1,0,'',''],
+ 'swayfx' => ['^swayfx',0,'0','SwayFX',0,1,0,'',''], # probably same as sway, unverified
+ 'swayfx' => ['^sway',3,'-v','SwayFX',0,1,0,'',''], # not sure if safe
+ 'swc' => ['^swc',0,'0','swc',0,1,0,'',''], # unverified
+ 'swvkc' => ['^swvkc',0,'0','swvkc',0,1,0,'',''], # unverified
+ 'tabby' => ['^tabby',0,'0','Tabby',0,1,0,'',''], # unverified
+ 'taiwins' => ['^taiwins',0,'0','taiwins',0,1,0,'',''], # unverified
+ 'tinybox' => ['^tinybox',0,'0','tinybox',0,1,0,'',''], # unverified
+ 'tinywl' => ['^tinywl',0,'0','TinyWL',0,1,0,'',''], # unverified
+ 'tinywm' => ['^tinywm',0,'0','TinyWM',0,1,0,'',''], # no version
+ 'trinkster' => ['^trinkster',0,'0','Trinkster',0,1,0,'',''], # unverified
+ 'tvtwm' => ['^tvtwm',0,'0','tvtwm',0,1,0,'',''], # unverified
+ 'twin' => ['^Twin:',2,'--version','Twin',0,0,0,'',''],
+ 'twm' => ['^twm',0,'0','TWM',0,1,0,'',''], # no version
+ 'ukui' => ['^ukui-session',2,'--version','UKUI',0,1,0,'',''],
+ 'ukwm' => ['^ukwm',2,'--version','ukwm',0,1,0,'',''],
+ 'unagi' => ['^\S',1,'--version','unagi',0,1,0,'',''],
+ 'unity' => ['^unity',2,'--version','Unity',0,1,0,'',''],
+ 'unity-system-compositor' => ['^unity-system-compositor',2,'--version',
+ 'unity-system-compositor (mir)',0,0,0,'',''],
+ 'uwm' => ['^uwm',0,'0','UWM',0,1,0,'',''], # unverified
+ 'velox' => ['^velox',0,'0','Velox',0,1,0,'',''], # unverified
+ 'vimway' => ['^vimway',0,'0','vimway',0,1,0,'',''], # unverified
+ 'vivarium' => ['^vivarium',0,'0','Vivarium',0,1,0,'',''], # unverified
+ 'vtwm' => ['^vtwm',0,'0','vtwm',0,1,0,'',''], # no version
+ 'w9wm' => ['^w9wm',3,'-version','w9wm',0,1,0,'',''], # fork of 9wm, unverified
+ 'wavy' => ['^wavy',0,'0','wavy',0,1,0,'',''], # unverified
+ 'waybox' => ['^way',0,'0','waybox',0,1,0,'',''], # unverified
+ 'waycooler' => ['^way',3,'--version','way-cooler',0,1,0,'',''],
+ 'way-cooler' => ['^way',3,'--version','way-cooler',0,1,0,'',''],
+ 'wayfire' => ['^\d',1,'--version','wayfire',0,1,0,'',''], # -version/--version
+ 'wayhouse' => ['^wayhouse',0,'0','wayhouse',0,1,0,'',''], # unverified
+ 'waymonad' => ['^waymonad',0,'0','waymonad',0,1,0,'',''], # unverified
+ 'westeros' => ['^westeros',0,'0','westeros',0,1,0,'',''], # unverified
+ 'westford' => ['^westford',0,'0','westford',0,1,0,'',''], # unverified
+ 'weston' => ['^weston',2,'--version','Weston',0,1,0,'',''],
+ 'windowlab' => ['^windowlab',2,'-about','WindowLab',0,1,0,'',''],
+ 'windowmaker' => ['^Window\s*Maker',-1,'--version','WindowMaker',0,1,0,'',''], # uses wmaker
+ 'wingo' => ['^wingo',0,'0','Wingo',0,1,0,'',''], # unverified
+ 'wio' => ['^wio',0,'0','Wio',0,1,0,'',''], # unverified
+ 'wio' => ['^wio\+',0,'0','wio+',0,1,0,'',''], # unverified
+ 'wm2' => ['^wm2',0,'0','wm2',0,1,0,'',''], # no version
+ 'wmaker' => ['^Window\s*Maker',-1,'--version','WindowMaker',0,1,0,'',''],
+ 'wmfs' => ['^wmfs',0,'0','WMFS',0,1,0,'',''], # unverified
+ 'wmfs2' => ['^wmfs',0,'0','WMFS',0,1,0,'',''], # unverified
+ 'wmii' => ['^wmii',1,'-v','wmii',0,1,0,'^wmii[234]?-',''], # wmii is wmii3
+ 'wmii2' => ['^wmii2',1,'--version','wmii2',0,1,0,'^wmii[234]?-',''],
+ 'wmx' => ['^wmx',0,'0','wmx',0,1,0,'',''], # no version
+ 'wxrc' => ['^wx',0,'0','',0,1,0,'WXRC',''], # unverified
+ 'wxrd' => ['^wx',0,'0','',0,1,0,'WXRD',''], # unverified
+ 'x9wm' => ['^x9wm',3,'-version','x9wm',0,1,0,'',''], # fork of 9wm, unverified
+ 'xcompmgr' => ['^xcompmgr',0,'0','xcompmgr',0,1,0,'',''], # no version
+ 'xfce-panel' => ['^xfce-panel',2,'--version','Xfce',0,1,0,'',''],
+ 'xfce4-panel' => ['^xfce4-panel',2,'--version','Xfce',0,1,0,'',''],
+ 'xfce5-panel' => ['^xfce5-panel',2,'--version','Xfce',0,1,0,'',''],
+ 'xfdesktop' => ['xfdesktop\sversion',5,'--version','Xfce',0,1,0,'',''],
+ # ' This is xfwm4 version 4.16.1 (revision 5f61a84ad) for Xfce 4.16'
+ 'xfwm' => ['xfwm[3-8]? version',5,'--version','xfwm',0,1,0,'^^\s+',''],# unverified
+ 'xfwm3' => ['xfwm3? version',5,'--version','xfwm3',0,1,0,'^^\s+',''], # unverified
+ 'xfwm4' => ['xfwm4? version',5,'--version','xfwm4',0,1,0,'^^\s+',''],
+ 'xfwm5' => ['xfwm5? version',5,'--version','xfwm5',0,1,0,'^^\s+',''], # unverified
+ 'xmonad' => ['^xmonad',2,'--version','XMonad',0,1,0,'',''],
+ 'xuake' => ['^xuake',0,'0','xuake',0,1,0,'',''], # unverified
+ 'yeahwm' => ['^yeahwm',0,'--version','YeahWM',0,1,0,'',''], # unverified
+ ## Desktop Toolkits/Frameworks ##
+ 'efl-version' => ['^\S',1,'--version','EFL',0,1,0,'',''], # any arg returns v
+ 'gtk-launch' => ['^\S',1,'--version','GTK',0,1,0,'',''],
+ 'kded-qt' => ['^Qt',2,'--version','Qt',0,0,0,'',''],
+ # --version: kded5 5.110.0 (frameworks v, not kde)
+ 'kded5-frameworks' => ['^kded5',2,'--version','frameworks',0,1,0],
+ 'kded6-frameworks' => ['^kded6',2,'--version','frameworks',0,1,0],
+ 'kf-config-qt' => ['^^Qt',2,'--version','Qt',0,0,0,'',''],
+ 'qmake-qt' => ['^Using Qt version',4,'--version','Qt',0,0,0,'',''],
+ 'qtdiag-qt' => ['^qt',2,'--version','Qt',0,0,0,'',''],
+ # command: xfdesktop
+ 'xfdesktop-gtk' => ['Built\swith\sGTK',4,'--version','Gtk',0,0,0,'',''],
+ ## Display/Login Managers (dm,lm) ##
+ 'brzdm' => ['^brzdm version',3,'-v','brzdm',0,1,0,'',''], # unverified, slim fork
+ 'cdm' => ['^cdm',0,'0','CDM',0,1,0,'',''],
+ # might be xlogin, unknown output for -V
+ 'clogin' => ['^clogin',0,'-V','clogin',0,1,0,'',''], # unverified, cysco router
+ 'elogind' => ['^elogind',0,'0','elogind',0,1,0,'',''], # no version
+ 'emptty' => ['^emptty',0,'0','EMPTTY',0,1,0,'',''], # unverified
+ 'entranced' => ['^entrance',0,'0','Entrance',0,1,0,'',''],
+ 'gdm' => ['^gdm',2,'--version','GDM',0,1,0,'',''],
+ 'gdm3' => ['^gdm',2,'--version','GDM3',0,1,0,'',''],
+ 'greetd' => ['^greetd',0,'0','greetd',0,1,0,'',''], # no version
+ 'kdm' => ['^kdm',0,'0','KDM',0,1,0,'',''],
+ 'kdm3' => ['^kdm',0,'0','KDM',0,1,0,'',''],
+ 'kdmctl' => ['^kdm',0,'0','KDM',0,1,0,'',''],
+ 'ldm' => ['^ldm',0,'0','LDM',0,1,0,'',''],
+ 'lemurs' => ['^lemurs',0,'0','lemurs',0,1,0,'',''], # unverified
+ 'lightdm' => ['^lightdm',2,'--version','LightDM',0,1,1,'',''],
+ 'loginx' => ['^loginx',0,'0','loginx',0,1,0,'',''], # unverified
+ 'lxdm' => ['^lxdm',0,'0','LXDM',0,1,0,'',''],
+ 'ly' => ['^ly',3,'--version','Ly',0,1,0,'',''],
+ 'mdm' => ['^mdm',0,'0','MDM',0,1,0,'',''],
+ 'mlogind' => ['^mlogind',3,'-v','mlogind',0,1,0,'',''], # guess, unverified, BSD SLiM fork
+ 'nodm' => ['^nodm',0,'0','nodm',0,1,0,'',''],
+ 'pcdm' => ['^pcdm',0,'0','PCDM',0,1,0,'',''],
+ 'qingy' => ['^qingy',0,'0','qingy',0,1,0,'',''], # unverified
+ 'seatd' => ['^seatd',3,'-v','seatd',0,1,0,'',''],
+ 'sddm' => ['^sddm',0,'0','SDDM',0,1,0,'',''],
+ 'slim' => ['slim version',3,'-v','SLiM',0,1,0,'',''],
+ 'slimski' => ['slimski version',3,'-v','slimski',0,1,0,'',''], # slim fork
+ 'tbsm' => ['^tbsm',0,'0','tbsm',0,1,0,'',''], # unverified
+ 'tdm' => ['^tdm',0,'0','TDM',0,1,0,'',''], # could be consold-tdm or tizen dm
+ 'udm' => ['^udm',0,'0','udm',0,1,0,'',''],
+ 'wdm' => ['^wdm',0,'0','WINGs DM',0,1,0,'',''],
+ 'x3dm' => ['^x3dm',0,'0','X3DM',0,1,0,'',''], # unverified
+ 'xdm' => ['^xdm',0,'0','XDM',0,1,0,'',''],
+ 'xdmctl' => ['^xdm',0,'0','XDM',0,1,0,'',''],# opensuse/redhat may use this to start real dm
+ 'xenodm' => ['^xenodm',0,'0','xenodm',0,1,0,'',''],
+ 'xlogin' => ['^xlogin',0,'-V','xlogin',0,1,0,'',''], # unverified, cysco router
+ ## Shells - not checked: ion, eshell ##
+ ## See ShellData::shell_test() for unhandled but known shells
+ 'ash' => ['',3,'pkg','ash',1,0,0,'',''], # special; dash precursor
+ 'bash' => ['^GNU[[:space:]]bash',4,'--version','Bash',1,1,0,'',''],
+ 'busybox' => ['^busybox',0,'0','BusyBox',1,0,0,'',''], # unverified, hush/ash likely
+ 'cicada' => ['^\s*version',2,'cmd','cicada',1,1,0,'',''], # special
+ 'csh' => ['^tcsh',2,'--version','csh',1,1,0,'',''], # mapped to tcsh often
+ 'dash' => ['',3,'pkg','DASH',1,0,0,'',''], # no version, pkg query
+ 'elvish' => ['^\S',1,'--version','Elvish',1,0,0,'',''],
+ 'fish' => ['^fish',3,'--version','fish',1,0,0,'',''],
+ 'fizsh' => ['^fizsh',3,'--version','FIZSH',1,0,0,'',''],
+ # ksh/lksh/loksh/mksh/posh//pdksh need to print their own $VERSION info
+ 'ksh' => ['^\S',1,'cmd','ksh',1,0,0,'^(Version|.*KSH)\s*',''], # special
+ 'ksh93' => ['^\S',1,'cmd','ksh93',1,0,0,'^(Version|.*KSH)\s*',''], # special
+ 'lksh' => ['^\S',1,'cmd','lksh',1,0,0,'^.*KSH\s*',''], # special
+ 'loksh' => ['^\S',1,'cmd','loksh',1,0,0,'^.*KSH\s*',''], # special
+ 'mksh' => ['^\S',1,'cmd','mksh',1,0,0,'^.*KSH\s*',''], # special
+ 'nash' => ['^nash',0,'0','Nash',1,0,0,'',''], # unverified; rc based [no version]
+ 'oh' => ['^oh',0,'0','Oh',1,0,0,'',''], # no version yet
+ 'oil' => ['^Oil',3,'--version','Oil',1,1,0,'',''], # could use cmd $OIL_SHELL
+ 'osh' => ['^osh',3,'--version','OSH',1,1,0,'',''], # precursor of oil
+ 'pdksh' => ['^\S',1,'cmd','pdksh',1,0,0,'^.*KSH\s*',''], # special, in ksh family
+ 'posh' => ['^\S',1,'cmd','posh',1,0,0,'',''], # special, in ksh family
+ 'tcsh' => ['^tcsh',2,'--version','tcsh',1,1,0,'',''], # enhanced csh
+ 'xonsh' => ['^xonsh',1,'--version','xonsh',1,0,0,'^xonsh[\/-]',''],
+ 'yash' => ['^Y',5,'--version','yash',1,0,0,'',''],
+ 'zsh' => ['^zsh',2,'--version','Zsh',1,0,0,'',''],
+ ## Sound Servers ##
+ 'arts' => ['^artsd',2,'-v','aRts',0,1,0,'',''],
+ 'esound' => ['^Esound',3,'--version','EsounD',0,1,1,'',''],
+ 'jack' => ['^jackd',3,'--version','JACK',0,1,0,'',''],
+ 'nas' => ['^Network Audio',5,'-V','NAS',0,1,0,'',''],
+ 'pipewire' => ['^Compiled with libpipe',4,'--version','PipeWire',0,0,0,'',''],
+ 'pulseaudio' => ['^pulseaudio',2,'--version','PulseAudio',0,1,0,'',''],
+ 'roaraudio' => ['^roaraudio',0,'0','RoarAudio',0,1,0,'',''], # no version/unknown?
+ ## Tools: Compilers ##
+ 'clang' => ['clang',3,'--version','clang',1,1,0,'',''],
+ # gcc (Debian 6.3.0-18) 6.3.0 20170516
+ # gcc (GCC) 4.2.2 20070831 prerelease [FreeBSD]
+ 'gcc' => ['^gcc',2,'--version','GCC',1,0,0,'\([^\)]*\)',''],
+ 'gcc-apple' => ['Apple[[:space:]]LLVM',2,'--version','LLVM',1,0,0,'',''], # not used
+ 'zigcc' => ['zigcc',0,'0','zigcc',1,1,0,'',''], # unverified
+ ## Tools: Init ##
+ 'busybox' => ['busybox',2,'--help','BusyBox',0,1,1,'',''],
+ # Dinit version 0.15.1. [ends .]
+ 'dinit' => ['^Dinit',3,'--version','Dinit',0,1,0,'',''],
+ # version: Epoch Init System 1.0.1 "Sage"
+ 'epoch' => ['^Epoch',4,'version','Epoch',0,1,0,'',''],
+ 'finit' => ['^Finit',2,'-v','finit',0,1,0,'',''],
+ # /sbin/openrc --version: openrc (OpenRC) 0.13
+ 'openrc' => ['^openrc',3,'--version','OpenRC',0,1,0,'',''],
+ # /sbin/rc --version: rc (OpenRC) 0.11.8 (Gentoo Linux)
+ 'rc' => ['^rc',3,'--version','OpenRC',0,1,0,'',''],
+ 'shepherd' => ['^shepherd',4,'--version','Shepherd',0,1,0,'',''],
+ 'systemd' => ['^systemd',2,'--version','systemd',0,1,0,'',''],
+ 'upstart' => ['upstart',3,'--version','Upstart',0,1,0,'',''],
+ ## Tools: Miscellaneous ##
+ 'sudo' => ['^Sudo',3,'-V','Sudo',1,1,0,'',''], # sudo pre 1.7 does not have --version
+ 'udevadm' => ['^\d{3}',1,'--version','udevadm',0,1,0,'',''],
+ ## Tools: Package Managers ##
+ 'guix' => ['^guix',4,'--version','Guix',0,1,0,'',''], # used for distro ID
+ );
+}
+
+# returns array of:
+# 0: match string; 1: search word number; 2: version string [alt: file];
+# 3: Print name; 4: console 0/1;
+# 5: 0/1 exit version loop at 1 [alt: if version=file replace value with \s];
+# 6: 0/1 write to stderr [alt: if version=file, path for file];
+# 7: replace regex for further cleanup; 8: extra data
+# note: setting index 1 or 2 to 0 will trip flags to not do version
+# args: 0: program lower case name
+sub values {
+ my @values;
+ ProgramData::set_values() if !$loaded{'program-values'};
+ if (defined $program_values{$_[0]}){
+ @values = @{$program_values{$_[0]}};
+ }
+ # my $debug = Dumper \@values;
+ main::log_data('dump','@values',\@values) if $b_log;
+ return @values;
+}
+
+# args: 0: desktop/app command for --version; 1: search string;
+# 2: space print number; 3: [optional] version arg: -v, version, etc;
+# 4: [optional] exit 1st line 0/1; 5: [optional] 0/1 stderr output;
+# 6: replace regex; 7: extra data
+sub version {
+ eval $start if $b_log;
+ my ($app,$search,$num,$version,$exit,$stderr,$replace,$extra) = @_;
+ my ($b_no_space,$cmd,$line);
+ my $version_nu = '';
+ my $count = 0;
+ my $app_name = $app;
+ $output = ();
+ $app_name =~ s%^.*/%%;
+ # print "app: $app :: appname: $app_name\n";
+ $exit ||= 100; # basically don't exit ever
+ $version ||= '--version';
+ # adjust to array index, not human readable
+ $num-- if (defined $num && $num > 0);
+ # konvi in particular doesn't like using $ENV{'PATH'} as set, so we need
+ # to always assign the full path if it hasn't already been done
+ if ($version ne 'file' && $app !~ /^\//){
+ if (my $program = main::check_program($app)){
+ $app = $program;
+ }
+ else {
+ main::log_data('data',"$app not found in path.") if $b_log;
+ return 0;
+ }
+ }
+ if ($version eq 'file'){
+ return 0 unless $extra && -r $extra;
+ $output = main::reader($extra,'strip','ref');
+ @$output = map {s/$stderr/ /;$_} @$output if $stderr; # $stderr is the splitter
+ $cmd = '';
+ }
+ # These will mostly be shells that require running the shell command -c to get info data
+ elsif ($version eq 'cmd'){
+ ($cmd,$b_no_space) = version_cmd($app,$app_name,$extra);
+ return 0 if !$cmd;
+ }
+ # slow: use pkg manager to get version, avoid unless you really want version
+ elsif ($version eq 'pkg'){
+ ($cmd,$search) = version_pkg($app_name);
+ return 0 if !$cmd;
+ }
+ # note, some wm/apps send version info to stderr instead of stdout
+ elsif ($stderr){
+ $cmd = "$app $version 2>&1";
+ }
+ else {
+ $cmd = "$app $version 2>/dev/null";
+ }
+ # special case, in rare instances version comes from file
+ if ($version ne 'file'){
+ $output = main::grabber($cmd,'','strip','ref');
+ }
+ if ($b_log){
+ main::log_data('data',"version: $version num: $num search: $search command: $cmd");
+ main::log_data('dump','output',$output);
+ }
+ if ($dbg[64]){
+ print "::::::::::\nPD::version() cmd: $cmd\noutput:",Data::Dumper::Dumper $output;
+ }
+ # sample: dwm-5.8.2, ©.. etc, why no space? who knows. Also get rid of v in number string
+ # xfce, and other, output has , in it, so dump all commas and parentheses
+ if ($output && @$output){
+ foreach (@$output){
+ last if $count == $exit;
+ if ($_ =~ /$search/i){
+ # print "loop: $_ :: num: $num\n";
+ $_ =~ s/$replace//i if $replace;
+ $_ =~ s/\s/_/g if $b_no_space; # needed for some items with version > 1 word
+ my @data = split(/\s+/, $_);
+ $version_nu = $data[$num];
+ last if !defined $version_nu;
+ # some distros add their distro name before the version data, which
+ # breaks version detection. A quick fix attempt is to just add 1 to $num
+ # to get the next value.
+ $version_nu = $data[$num+1] if $data[$num+1] && $version_nu =~ /version/i;
+ $version_nu =~ s/(\([^)]+\)|,|"|\||\(|\)|\.$)//g if $version_nu;
+ # trim off leading v but only when followed by a number
+ $version_nu =~ s/^v([0-9])/$1/i if $version_nu;
+ # print "$version_nu\n";
+ last;
+ }
+ $count++;
+ }
+ }
+ main::log_data('data',"Program version: $version_nu") if $b_log;
+ eval $end if $b_log;
+ return $version_nu;
+}
+# print version('bash', 'bash', 4) . "\n";
+
+# returns ($cmdd, $b_no_space)
+# ksh: Version JM 93t+ 2010-03-05 [OR] Version A 2020.0.0
+# mksh: @(#)MIRBSD KSH R56 2018/03/09; lksh/pdksh: @(#)LEGACY KSH R56 2018/03/09
+# loksh: @(#)PD KSH v5.2.14 99/07/13.2; posh: 0.13.2
+sub version_cmd {
+ eval $start if $b_log;
+ my ($app,$app_name,$extra) = @_;
+ my @data = ('',0);
+ if ($app_name eq 'cicada'){
+ $data[0] = $app . ' -c "' . $extra . '" 2>/dev/null';}
+ elsif ($app_name =~ /^(|l|lo|m|pd)ksh(93)?$/){
+ $data[0] = $app . ' -c \'printf %s "$KSH_VERSION"\' 2>/dev/null';
+ $data[1] = 1;}
+ elsif ($app_name eq 'posh'){
+ $data[0] = $app . ' -c \'printf %s "$POSH_VERSION"\' 2>/dev/null'}
+ # print "$data[0] :: $data[1]\n";
+ eval $end if $b_log;
+ return @data;
+}
+
+# returns $cmd, $search
+sub version_pkg {
+ eval $start if $b_log;
+ my ($app) = @_;
+ my ($program,@data);
+ # note: version $num is 3 in dpkg-query/pacman/rpm, which is convenient
+ if ($program = main::check_program('dpkg-query')){
+ $data[0] = "$program -W -f='\${Package}\tversion\t\${Version}\n' $app 2>/dev/null";
+ $data[1] = "^$app\\b";
+ }
+ elsif ($program = main::check_program('pacman')){
+ $data[0] = "$program -Q --info $app 2>/dev/null";
+ $data[1] = '^Version';
+ }
+ elsif ($program = main::check_program('rpm')){
+ $data[0] = "$program -qi --nodigest --nosignature $app 2>/dev/null";
+ $data[1] = '^Version';
+ }
+ # print "$data[0] :: $data[1]\n";
+ eval $end if $b_log;
+ return @data;
+}
+}
+
+## PsData
+# public methods:
+# set_cmd(): sets @ps_aux, @ps_cmd
+# set_dm(): sets $ps_data{'dm-active'}
+# set_de_wm(): sets -S/-G de/wm/comp/tools items
+# set_power(): sets -I $ps_data{'power-services'}
+{
+package PsData;
+
+sub set_cmd {
+ eval $start if $b_log;
+ my ($b_busybox,$header,$ps,@temp);
+ $loaded{'ps-cmd'} = 1;
+ my $args = 'wwaux';
+ my $path = main::check_program('ps');
+ my $link = readlink($path);
+ if ($link && $link =~ /busybox/i){
+ $b_busybox = 1;
+ $args = '';
+ }
+ # note: some ps cut output based on terminal width, ww sets width unlimited
+ # old busybox returns error with args, new busybox ignores auxww
+ $ps = main::grabber("$path $args 2>/dev/null",'','strip','ref');
if (@$ps){
$header = shift @$ps; # get rid of header row
# handle busy box, which has 3 columns, regular ps aux has 11
# avoid deprecated implicit split error in older Perls
@temp = split(/\s+/, $header);
}
- $ps_cols = $#temp; # the indexes, not the scalar count
- if ($ps_cols < 10){
- my $version = qx(ps --version 2>&1);
- $b_busybox_ps = 1 if $version =~ /busybox/i;
+ else {
+ return;
}
- return if !@$ps; # note: mips/openwrt ps has no 'a'
+ $ps_data{'header'}->[0] = $#temp; # the indexes, not the scalar count
+ for (my $i = 0; $i <= $#temp; $i++){
+ if ($temp[$i] eq 'PID'){$ps_data{'header'}->[1] = $i;}
+ elsif ($temp[$i] eq '%CPU'){$ps_data{'header'}->[2] = $i;}
+ # note: %mem is percent used
+ elsif ($temp[$i] eq '%MEM'){$ps_data{'header'}->[3] = $i;}
+ elsif ($temp[$i] eq 'RSS'){$ps_data{'header'}->[4] = $i;}
+ }
+ # we want more data from ps busybox, to get TinyX screen res
+ my $cols_use = ($b_busybox) ? 7 : 2;
+ my $pattern = 'brave|chrom(e|ium)|falkon|(fire|water)fox|gvfs|';
+ $pattern .= 'konqueror|mariadb|midori|mysql|openvpn|opera|';
+ $pattern .= 'pale|postgre|php|qtwebengine|smtp|vivald';
for (@$ps){
next if !$_;
next if $self_name eq 'inxi' && /\/$self_name\b/;
- $_ = lc;
+ # $_ = lc;
push (@ps_aux,$_);
my @split = split(/\s+/, $_);
- # slice out 10th to last elements of ps aux rows
+ # slice out COMMAND to last elements of psrows
my $final = $#split;
# some stuff has a lot of data, chrome for example
- $final = ($final > ($ps_cols + 2)) ? $ps_cols + 2 : $final;
+ $final = ($final > ($ps_data{'header'}->[0] + $cols_use)) ?
+ $ps_data{'header'}->[0] + $cols_use : $final;
# handle case of ps wrapping lines despite ww unlimited width, which
- # should NOT be happening, but is.
- next if !defined $split[$ps_cols];
- if ($split[$ps_cols] !~ /^\[/){
- push(@ps_cmd,join(' ', @split[$ps_cols .. $final]));
+ # should NOT be happening, except on busybox ps, which has no ww.
+ next if !defined $split[$ps_data{'header'}->[0]];
+ # we don't want zombie/system/kernel processes, or servers, browsers.
+ if ($split[$ps_data{'header'}->[0]] !~ /^([\[\(]|(\S+\/|)($pattern))/i){
+ push(@ps_cmd,join(' ', @split[$ps_data{'header'}->[0] .. $final]));
}
}
- # never, because ps loaded before option handler
- # print Dumper \@ps_cmd; # if $dbg[5];
+ # dump multiple instances, just need to see if process running
+ main::uniq(\@ps_cmd) if @ps_cmd;
+ # Use $dbg[61] to see @ps_cmd result
+ eval $end if $b_log;
+}
+
+# only runs when no /run type dm found
+sub set_dm {
+ eval $start if $b_log;
+ # startx: /bin/sh /usr/bin/startx
+ process_items(\@{$ps_data{'dm-active'}},join('|',qw(ly startx xinit))); # possible dm values
+ print '$ps_data{dm-active}: ', Data::Dumper::Dumper $ps_data{'dm-active'} if $dbg[5];
+ main::log_data('dump','$ps_data{dm-active}',$ps_data{'dm-active'}) if $b_log;
eval $end if $b_log;
}
-sub set_ps_gui {
+sub set_de_wm {
eval $start if $b_log;
$loaded{'ps-gui'} = 1;
- my ($b_wl,$working,@match,@temp);
+ my ($b_de_wm_comp,$b_wm_comp);
# desktops / wm (some wm also compositors)
if ($show{'system'}){
- @temp=qw(razor-desktop razor-session lxsession lxqt-session
- tdelauncher tdeinit_phase1);
- push(@match,@temp);
- @temp=qw(2bwm 3dwm 9wm afterstep aewm aewm\+\+ amiwm antiwm awesome
- blackbox bspwm calmwm catwm cde (sh|c?lisp).*clfswm ctwm (openbsd-)?cwm
- dwm evilwm
- fluxbox flwm flwm_topside fvwm.*-crystal fvwm1 fvwm2 fvwm3 fvwm95 fvwm
- herbstluftwm i3 icewm instantwm ion3 jbwm jwm larswm leftwm lwm
- matchbox-window-manager mcwm mini monsterwm musca mwm nawm notion
- openbox nscde pekwm penrose python.*qtile qvwm ratpoison
- sawfish scrotwm snapwm spectrwm (sh|c?lisp).*stumpwm
- tinywm tvtwm twm uwm windowlab WindowMaker wingo wm2 wmfs wmfs2 wmii2 wmii
- wmx xfdesktop xmonad yeahwm);
- push(@match,@temp);
- $b_wl = 1;
- }
- # wm: note that for all but the listed wm, the wm and desktop would be the
- # same, particularly with all smaller wayland wm/compositors.
- if ($show{'system'} && $extra > 1){
- @temp=qw(budgie-wm compiz deepin-wm gala gnome-shell
- twin kwin_wayland kwin_x11 kwinft kwin marco
- deepin-metacity metacity metisse mir muffin deepin-mutter mutter
- ukwm xfwm[45]?);
- push(@match,@temp);
- # startx: /bin/sh /usr/bin/startx
- @temp=qw(ly .*startx xinit); # possible dm values
- push(@match,@temp);
- }
- # info: NOTE: glx-dock is cairo-dock
- if ($show{'system'} && $extra > 2){
- @temp=qw(alltray awn bar bmpanel bmpanel2 budgie-panel
- cairo-dock dde-dock dmenu dockbarx docker docky dzen dzen2
- fbpanel fspanel glx-dock gnome-panel hpanel i3bar i3-status(-rs)? icewmtray
- kdocker kicker latte latte-dock lemonbar ltpanel luastatus lxpanel lxqt-panel
- matchbox-panel mate-panel nwg-bar nwg-dock nwg-panel ourico
- perlpanel plank plasma-desktop plasma-netbook polybar pypanel
- razor-panel razorqt-panel rootbar
- sfwbar stalonetray swaybar taskbar tint2 trayer
- ukui-panel vala-panel wapanel waybar wbar wharf wingpanel witray
- xfce[45]?-panel xmobar yambar yabar);
- push(@match,@temp);
- }
- # compositors (for wayland these are also the server, note.
+ # some desktops detect via ps as fallback
+ process_items(\@{$ps_data{'de-ps-detect'}},join('|', qw(
+ razor-desktop razor-session lxsession lxqt-session nscde
+ tdelauncher tdeinit_phase1)));
+ # order matters!
+ process_items(\@{$ps_data{'wm-parent'}},join('|', qw(xfdesktop icewm fluxbox
+ blackbox)));
+ # regular wm
+ # unverfied: 2bwm catwm mcwm penrose snapwm uwm wmfs wmfs2 wingo wmii2
+ process_items(\@{$ps_data{'wm-main'}},join('|', qw(2bwm 9wm
+ afterstep aewm aewm\+\+ amiwm antiwm awesome
+ bspwm calmwm catwm cde clfswm ctwm (openbsd-)?cwm
+ dawn dtwm dusk dwm echinus evilwm flwm flwm_topside
+ fvwm.*-crystal\S* fvwm1 fvwm2 fvwm3 fvwm95 fvwm
+ hackedbox herbstluftwm i3 instantwm ion3 jbwm jwm larswm leftwm lwm
+ matchbox-window-manager mcwm mini miwm mlvwm monsterwm musca mvwm mwm
+ nawm notion openbox nscde pekwm penrose qvwm ratpoison
+ sapphire sawfish scrotwm snapwm spectrwm stumpwm subtle tinywm tvtwm twm
+ uwm vtwm windowlab [wW]indo[mM]aker w9wm wingo wm2 wmfs wmfs2 wmii2 wmii
+ wmx x9wm xmonad yeahwm)));
+ $b_wm_comp = 1;
+ # wm: note that for all but the listed wm, the wm and desktop would be the
+ # same, particularly with all smaller wayland wm/compositors.
+ $b_de_wm_comp = 1 if $extra > 1;
+ }
+ # compositors (for wayland these are also the server, note).
# for wayland always show, so always load these
if ($show{'graphic'}){
- @temp=qw(3dwm budgie-wm cairo compiz compton deepin-wm dcompmgr enlightenment
- gala gnome-shell kmscon kwin_wayland kwin_x11 kwinft kwin
- marco metisse mir moblin muffin mutter picom steamcompmgr
- ukwm unagi unity-system-compositor wayland xcompmgr xfwm[45]?);
- push(@match,@temp);
- $b_wl = 1;
- }
- uniq(\@match);
- my $matches = join('|', @match);
- if ($b_wl){
+ $b_de_wm_comp = 1;
+ $b_wm_comp = 1;
+ process_items(\@{$ps_data{'compositors-pure'}},join('|',qw(cairo compton dcompmgr
+ mcompositor picom steamcompmgr surfaceflinger xcompmgr unagi)));
+ }
+ if ($b_de_wm_comp){
+ process_items(\@{$ps_data{'de-wm-compositors'}},join('|',qw(budgie-wm compiz
+ deepin-wm enlightenment gala gnome-shell twin kwin_wayland kwin_x11 kwinft kwin
+ marco deepin-metacity metacity metisse mir moksha muffin deepin-mutter mutter
+ ukwm xfwm[345]?)));
+ }
+ if ($b_wm_comp){
+ # x11: 3dwm, qtile [originally], rest wayland
# wayland compositors generally are compositors and wm.
# These will be used globally to avoid having to redo it over and over.
- $wl_compositors = '|' . join('|',qw(asc awc
+ process_items(\@{$ps_data{'wm-compositors'}},join('|',qw(3dwm asc awc bismuth
cage cagebreak cardboard chameleonwm clayland comfc
- dwc dwl epd-wm fireplace feathers fenestra glass gamescope greenfield grefson
- hikari hopalong hyprland inaban japokwm kiwmi labwc laikawm lipstick liri
- mahogany marina maze motorcar newm nucleus orbital perceptia phoc pywm qtile
- river rootston rustland simulavr skylight sommelier sway swc swvkc
+ dwl dwc epd-wm fireplace feathers fenestra glass gamescope greenfield grefson
+ hikari hopalong [Hh]yprland inaban japokwm kiwmi labwc laikawm lipstick liri
+ mahogany marina maze maynard motorcar newm nucleus
+ orbital orbment perceptia phoc polonium pywm qtile river rootston rustland
+ simulavr skylight smithay sommelier sway swayfx swc swvkc
tabby taiwins tinybox tinywl trinkster velox vimway vivarium
wavy waybox way-?cooler wayfire wayhouse waymonad westeros westford
- weston wio\+? wxr[cd] xuake));
- $matches .= $wl_compositors;
+ weston wio\+? wxr[cd] xuake)));
}
- $matches = qr/$matches/;
+ # info:/tools:
+ if ($show{'system'} && $extra > 2){
+ process_items(\@{$ps_data{'components-active'}},join('|', qw(
+ albert alltray awesomebar awn
+ bar barpanel bbdock bbpager bemenu bipolarbar bmpanel bmpanel2 budgie-panel
+ cairo-dock dde-dock deskmenu dmenu(-wayland)? dockbarx docker docky dzen dzen2
+ fbpanel fspanel fuzzel glx-dock gnome-panel hpanel
+ i3bar i3-status(-rs|-rust)? icewmtray jgmenu kdocker kicker krunner ksmoothdock
+ latte lavalauncher latte-dock lemonbar ltpanel luastatus lxpanel lxqt-panel
+ matchbox-panel mate-panel mauncher mopag nwg-(bar|dock|launchers|panel)
+ openbox-menu ourico perlpanel plank polybar pypanel razor(qt)?-panel rofi rootbar
+ sfwbar simplepanel sirula some_sorta_bar stalonetray swaybar
+ taffybar taskbar tint2 tofi trayer ukui-panel vala-panel
+ wapanel waybar wbar wharf wingpanel witray wldash wmdocker wmsystemtray wofi
+ xfce[45]?-panel xmobar yambar yabar yofi)));
+ # Generate tools: power manager daemons, then screensavers/lockers.
+ # Note that many lockers may not be services
+ @{$ps_data{'tools-test'}}=qw(away boinc-screensaver budgie-screensaver
+ cinnamon-screensaver gnome-screensaver gsd-screensaver-proxy gtklock i3lock
+ kscreenlocker light-locker lockscreen lxlock mate-screensaver nwg-lock
+ physlock rss-glx slock swayidle swaylock ukui-screensaver unicode-screensaver
+ xautolock xfce4-screensaver xlock xlockmore xscreensaver
+ xscreensaver-systemd xsecurelock xss-lock xtrlock);
+ process_items(\@{$ps_data{'tools-active'}},join('|',@{$ps_data{'tools-test'}}));
+ }
+ if ($dbg[63]){
+ main::feature_debugger('ps de-wm',
+ ['compositors-pure:',$ps_data{'compositors-pure'},
+ 'de-ps-detect:',$ps_data{'de-ps-detect'},
+ 'de-wm-compositors:',$ps_data{'de-wm-compositors'},
+ 'wm-main:',$ps_data{'wm-main'},
+ 'wm-parent:',$ps_data{'wm-parent'},
+ 'wm-compositors:',$ps_data{'wm-compositors'}],$dbg[63]);
+ }
+ print '%ps_data: ', Data::Dumper::Dumper \%ps_data if $dbg[5];
+ main::log_data('dump','%ps_data',\%ps_data) if $b_log;
+ eval $end if $b_log;
+}
+
+sub set_network {
+ eval $start if $b_log;
+ process_items(\@{$ps_data{'network-services'}},join('|', qw(apache\d?
+ cC]onn[mM]and? dhcpd dhcpleased fingerd ftpd gated httpd inetd ircd iwd
+ [mM]odem[mM]nager named networkd-dispatcher [nN]etwork[mM]anager nfsd nginx
+ ntpd proftpd routed smbd sshd systemd-networkd systemd-timesyncd tftpd
+ wicd wpa_supplicant xinetd xntpd)));
+ print '$ps_data{network-daemons}: ', Data::Dumper::Dumper $ps_data{'network-services'} if $dbg[5];
+ main::log_data('dump','$ps_data{network-daemons}',$ps_data{'network-services'}) if $b_log;
+ eval $end if $b_log;
+}
+
+sub set_power {
+ eval $start if $b_log;
+ process_items(\@{$ps_data{'power-services'}},join('|', qw(apmd csd-power
+ gnome-power-manager gsd-power kpowersave org\.dracolinux\.power
+ org_kde_powerdevil mate-power-manager power-profiles-daemon powersaved
+ tdepowersave thermald tlp upowerd ukui-power-manager xfce4-power-manager)));
+ print '$ps_data{power-daemons}: ', Data::Dumper::Dumper $ps_data{'power-services'} if $dbg[5];
+ main::log_data('dump','$ps_data{power-daemons}',$ps_data{'power-services'}) if $b_log;
+ eval $end if $b_log;
+}
+
+# args: 0: array ref or scalar to become ref; 1: 1: matches pattern
+sub process_items {
foreach (@ps_cmd){
- if (/^(|[\S]*\/)($matches)(\/|\s|$)/){
- $working = $2;
- push(@ps_gui, $working); # deal with duplicates with uniq
+ # strip out python/lisp/*sh starters
+ if (/^(\/\S+?\/(c?lisp|perl|python|[a-z]{0,3}sh)\s+)?(|\S*?\/)($_[1])(:|\s|$)/i){
+ push(@{$_[0]},$4) ; # deal with duplicates with uniq
}
}
- uniq(\@ps_gui) if @ps_gui;
- print Dumper \@ps_gui if $dbg[5];
- log_data('dump','@ps_gui',\@ps_gui) if $b_log;
- eval $end if $b_log;
+ main::uniq($_[0]) if @{$_[0]} && scalar @{$_[0]} > 1;
+}
}
sub get_self_version {
@@ -31240,6 +35895,7 @@ sub get_self_version {
{
package ServiceData;
my ($key,$service,$type);
+
sub get {
eval $start if $b_log;
($type,$service) = @_;
@@ -31257,6 +35913,7 @@ sub get {
eval $end if $b_log;
return $value;
}
+
sub process_status {
eval $start if $b_log;
my ($cmd,$status,@data);
@@ -31391,6 +36048,7 @@ sub process_status {
eval $end if $b_log;
return $result;
}
+
sub set {
eval $start if $b_log;
$loaded{'service-tool'} = 1;
@@ -31444,15 +36102,15 @@ sub set {
package ShellData;
my $b_debug = 0; # disable all debugger output in case forget to comment out!
-# public. This does not depend on using ps -jfp, open/netbsd do not
-# at this point support it, so we only want to use -jp to get parent
-# $ppid set in initialize(). shell_launcher will use -f so it only
-# runs in case we got $pppid. $client{'pppid'} will be used to trigger
-# launcher tests. If started with sshd via ssh user@address 'pinxi -Ia'
-# will show sshd as shell, which is fine, that's what it is.
+# Public. This does not depend on using ps -jfp, open/netbsd do not at this
+# point support it, so we only want to use -jp to get parent $ppid set in
+# initialize(). shell_launcher will use -f so it only runs in case we got
+# $pppid. $client{'pppid'} will be used to trigger launcher tests. If started
+# with sshd via ssh user@address 'pinxi -Ia' will show sshd as shell, which is
+# fine, that's what it is.
sub set {
eval $start if $b_log;
- my ($cmd,$parent,$pppid,$shell);
+ my (@app,$cmd,$parent,$pppid,$shell);
$loaded{'shell-data'} = 1;
$cmd = "ps -wwp $ppid -o comm= 2>/dev/null";
$shell = qx($cmd);
@@ -31504,7 +36162,7 @@ sub set {
# do nothing, just leave $shell as is
}
# note: not all programs return version data. This may miss unhandled shells!
- elsif ((@app = main::program_data(lc($shell),lc($shell),1)) && $app[0]){
+ elsif ((@app = ProgramData::full(lc($shell),lc($shell),1)) && $app[0]){
$shell = $app[0];
$client{'version'} = $app[1] if $app[1];
print "3: app test $shell v: $client{'version'}\n" if $b_debug;
@@ -31523,7 +36181,7 @@ sub set {
if (shell_test($parent)){
$shell = $parent;
}
- elsif ((@app = main::program_data(lc($parent),lc($parent),0)) && $app[0]){
+ elsif ((@app = ProgramData::full(lc($parent),lc($parent),0)) && $app[0]){
$shell = $app[0];
$client{'version'} = $app[1] if $app[1];
}
@@ -31542,7 +36200,7 @@ sub set {
$client{'name-print'} = $shell;
print "7: shell: $client{'name-print'} version: $client{'version'}\n" if $b_debug;
if ($extra > 2 && $working && lc($shell) ne lc($working)){
- if (@app = main::program_data(lc($working))){
+ if (@app = ProgramData::full(lc($working))){
$client{'default-shell'} = $app[0];
$client{'default-shell-v'} = $app[1];
$client{'default-shell-v'} =~ s/(\s*\(.*|-release|-version)// if $client{'default-shell-v'};
@@ -31576,7 +36234,8 @@ sub set {
}
eval $end if $b_log;
}
-# public, returns shell launcher, terminal, program, whatever
+
+# Public: returns shell launcher, terminal, program, whatever
# depends on $pppid so only runs if that is set.
sub shell_launcher {
eval $start if $b_log;
@@ -31625,7 +36284,8 @@ sub shell_launcher {
eval $end if $b_log;
return $shell_parent;
}
-# arg: 1 - parent id
+
+# args: 0: parent id
# returns SID/start ID
sub get_pppid {
eval $start if $b_log;
@@ -31640,13 +36300,15 @@ sub get_pppid {
eval $end if $b_log;
return $pppid;
}
-# arg: 1 - parent id
+
+# args: 0: parent id
# returns parent command name
sub parent_name {
eval $start if $b_log;
my ($ppid) = @_;
return '' if !$ppid;
my ($parent_name);
+ # known issue, ps truncates long command names, like io.elementary.t[erminal]
my $cmd = "ps -wwjp $ppid 2>/dev/null";
main::log_data('cmd',$cmd) if $b_log;
my @data = main::grabber($cmd,'','strip');
@@ -31667,9 +36329,10 @@ sub parent_name {
eval $end if $b_log;
return $parent_name;
}
-# list of program_values non-handled shells, or known to have no version
+
+# List of program_values non-handled shells, or known to have no version
# Move shell to set_program_values for print name, or version if available
-# $1 - return|[shell name to test
+# args: 0: return|[shell name to test
# returns test list OR shell name/''
sub shell_test {
my ($test) = @_;
@@ -31682,7 +36345,8 @@ sub shell_test {
return '|' . $shells if $test eq 'return';
return ($test =~ /^($shells)$/) ? $test : '';
}
-# this will test against default IP like: (:0) vs full IP to determine
+
+# This will test against default IP like: (:0) vs full IP to determine
# ssh status. Surprisingly easy test? Cross platform
sub ssh_status {
eval $start if $b_log;
@@ -31691,7 +36355,7 @@ sub ssh_status {
# fred-remote pts/1 2018-03-27 17:13 (43.43.43.43)
if (my $program = main::check_program('who')){
$ssh = (main::grabber("$program am i 2>/dev/null"))[0];
- # crude IP validation
+ # crude IP validation, v6 ::::::::, v4 x.x.x.x
if ($ssh && $ssh =~ /\(([:0-9a-f]{8,}|[1-9][\.0-9]{6,})\)$/){
$b_ssh = 1;
}
@@ -31699,6 +36363,7 @@ sub ssh_status {
eval $end if $b_log;
return $b_ssh;
}
+
# If IRC: called if root for -S, -G, or if not in display for user.
sub console_irc_tty {
eval $start if $b_log;
@@ -31717,6 +36382,7 @@ sub console_irc_tty {
main::log_data('data',"console-irc-tty:$client{'con-irc-tty'}") if $b_log;
eval $end if $b_log;
}
+
sub tty_number {
eval $start if $b_log;
$loaded{'tty-number'} = 1;
@@ -31770,14 +36436,14 @@ sub set_sysctl_data {
}
else {
my $file;
- # $file = "$fake_data_dir/sysctl/obsd_6.1_sysctl_soekris6501_root.txt";
- # $file = "$fake_data_dir/sysctl/obsd_6.1sysctl_lenovot500_user.txt";
+ # $file = "$fake_data_dir/bsd/sysctl/obsd_6.1_sysctl_soekris6501_root.txt";
+ # $file = "$fake_data_dir/bsd/sysctl/obsd_6.1sysctl_lenovot500_user.txt";
## matches: compaq: openbsd-dmesg.boot-1.txt
- # $file = "$fake_data_dir/sysctl/openbsd-5.6-sysctl-1.txt";
+ # $file = "$fake_data_dir/bsd/sysctl/openbsd-5.6-sysctl-1.txt";
## matches: toshiba: openbsd-5.6-dmesg.boot-1.txt
- # $file = "$fake_data_dir/sysctl/openbsd-5.6-sysctl-2.txt";
- $file = "$fake_data_dir/sysctl/obsd-6.8-sysctl-a-battery-sensor-1.txt";
- @temp = reader($file);
+ # $file = "$fake_data_dir/bsd/sysctl/openbsd-5.6-sysctl-2.txt";
+ # $file = "$fake_data_dir/bsd/sysctl/obsd-6.8-sysctl-a-battery-sensor-1.txt";
+ # @temp = reader($file);
}
foreach (@temp){
$_ =~ s/\s*=\s*|:\s+/:/;
@@ -31804,12 +36470,12 @@ sub set_sysctl_data {
/^dev\.cpu/ || /^machdep\.(cpu|hlt_logical_cpus)/)){
push(@{$sysctl{'cpu'}}, $_);
}
- # only activate if using the diskname feature in dboot!!
+ # only activate if using the diskname feature in dboot!! note assign to $dboot.
elsif ($use{'bsd-disk'} && /^hw\.disknames/){
push(@{$dboot{'disk'}}, $_);
}
elsif ($use{'bsd-kernel'} && /^kern.compiler_version/){
- push(@{$dboot{'kernel'}}, $_);
+ push(@{$sysctl{'kernel'}}, $_);
}
elsif ($use{'bsd-machine'} &&
/^(hw\.|machdep\.dmi\.(bios|board|system)-)(date|product|serial(no)?|uuid|vendor|version)/){
@@ -31911,37 +36577,43 @@ sub get_uptime {
## UsbData
# %usb array indexes
-# 0 - bus id / sort id
-# 1 - device id
-# 2 - path_id
-# 3 - path
-# 4 - class id
-# 5 - subclass id
-# 6 - protocol id
-# 7 - vendor:chip id
-# 8 - usb version
-# 9 - interfaces
-# 10 - ports
-# 11 - vendor
-# 12 - product
-# 13 - device-name
-# 14 - type string
-# 15 - driver
-# 16 - serial
-# 17 - speed
-# 18 - configuration - not used
-# 19 - power mW bsd only, not used yet
-# 20 - product rev number
-# 21 - driver_nu [bsd only]
+# 0: bus id / sort id
+# 1: device id
+# 2: path_id
+# 3: path
+# 4: class id
+# 5: subclass id
+# 6: protocol id
+# 7: vendor:chip id
+# 8: usb version
+# 9: interfaces
+# 10: ports
+# 11: vendor
+# 12: product
+# 13: device-name
+# 14: type string
+# 15: driver
+# 16: serial
+# 17: speed (bits, Si base 10, [MG]bps)
+# 18: configuration - not used
+# 19: power mW bsd only, not used yet
+# 20: product rev number
+# 21: driver_nu [bsd only]
+# 22: admin usb rev info
+# 23: rx lanes
+# 24: tx lanes
+# 25: speed (Bytes, IEC base 2, [MG]iBs
+# 26: absolute path
{
package UsbData;
my (@working);
my (@asound_ids,$b_asound,$b_hub,$addr_id,$bus_id,$bus_id_alpha,
$chip_id,$class_id,$device_id,$driver,$driver_nu,$ids,$interfaces,
-$name,$network_regex,$path,$path_id,$power,$product,$product_id,
-$protocol_id,$rev,$serial,$speed,$subclass_id,$type,$version,$vendor,
-$vendor_id);
+$name,$network_regex,$path,$path_id,$power,$product,$product_id,$protocol_id,
+$mode,$rev,$serial,$speed_si,$speed_iec,$subclass_id,$type,$version,
+$vendor,$vendor_id);
my $b_live = 1; # debugger file data
+
sub set {
eval $start if $b_log;
${$_[0]} = 1; # set checked boolean
@@ -31962,10 +36634,20 @@ sub set {
sys_data('main');
}
@{$usb{'main'}} = sort {$a->[0] cmp $b->[0]} @{$usb{'main'}} if $usb{'main'};
- main::log_data('dump','$usb{audio}: ',$usb{'audio'}) if $b_log;
- main::log_data('dump','$usb{bluetooth}: ',$usb{'bluetooth'}) if $b_log;
- main::log_data('dump','$usb{graphics}: ',$usb{'graphics'}) if $b_log;
- main::log_data('dump','$usb{network}: ',$usb{'network'}) if $b_log;
+ if ($b_log){
+ main::log_data('dump','$usb{audio}: ',$usb{'audio'});
+ main::log_data('dump','$usb{bluetooth}: ',$usb{'bluetooth'});
+ main::log_data('dump','$usb{disk}: ',$usb{'disk'});
+ main::log_data('dump','$usb{graphics}: ',$usb{'graphics'});
+ main::log_data('dump','$usb{network}: ',$usb{'network'});
+ }
+ if ($dbg[55]){
+ print '$usb{audio}: ', Data::Dumper::Dumper $usb{'audio'};
+ print '$usb{bluetooth}: ', Data::Dumper::Dumper $usb{'bluetooth'};
+ print '$usb{disk}: ', Data::Dumper::Dumper $usb{'disk'};
+ print '$usb{graphics}: ', Data::Dumper::Dumper $usb{'graphics'};
+ print '$usb{network}: ', Data::Dumper::Dumper $usb{'network'};
+ }
eval $end if $b_log;
}
@@ -31994,7 +36676,6 @@ sub lsusb_data {
$chip_id = $working[5];
@temp = @working[6..$#working];
$name = main::remove_duplicates(join(' ', @temp));
- $name = $name;
# $type = check_type($name,'','');
$type ||= '';
# do NOT set bus_id_alpha here!!
@@ -32023,12 +36704,13 @@ sub lsusb_data {
push(@{$usb{'main'}},[@working]);
# print join("\n",@working),"\n\n=====\n";
}
- print Data::Dumper::Dumper $usb{'main'} if $dbg[6];
+ print 'lsusb-pre-sys: ', Data::Dumper::Dumper $usb{'main'} if $dbg[6];
sys_data('lsusb') if $usb{'main'};
- print Data::Dumper::Dumper $usb{'main'} if $dbg[6];
+ print 'lsusb-w-sys: ', Data::Dumper::Dumper $usb{'main'} if $dbg[6];
main::log_data('dump','$usb{main}: plain',$usb{'main'}) if $b_log;
eval $end if $b_log;
}
+
# ugen0.1: <Apple OHCI root HUB> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=SAVE (0mA)
# ugen0.2: <MediaTek 802.11 n WLAN> at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (160mA)
# note: tried getting driver/ports from dmesg, impossible, waste of time
@@ -32060,7 +36742,8 @@ sub usbconfig_data {
undef @working;
}
elsif (/^([a-z_-]+)([0-9]+)\.([0-9]+):\s+<[^>]+>\s+at usbus([0-9]+)\b/){
- ($class_id,$cfg,$power,$speed,$subclass_id,$type) = ();
+ ($class_id,$cfg,$power,$rev,$mode,$speed_si,$speed_iec,$subclass_id,
+ $type) = ();
($product,$product_id,$vendor,$vendor_id) = ('','','','');
$hub_id = $2;
$addr_id = $3;
@@ -32076,25 +36759,28 @@ sub usbconfig_data {
# odd, using \b after ) doesn't work as expected
# note that bsd spd=FULL has no interest since we get that from the speed
if (/\b(speed|spd)\s*=\s*([\S]+)\s+\(([^\)]+)\)/){
- $speed = prep_speed($3);
+ $speed_si = $3;
}
if (/\b(power|pwr)\s*=\s*([\S]+)\s+\(([0-9]+mA)\)/){
$power = $3;
process_power(\$power) if $power;
}
+ version_data('bsd',\$speed_si,\$speed_iec,\$rev,\$mode);
$working[0] = $bus_id_alpha;
$working[1] = $addr_id;
$working[2] = $path_id;
$working[3] = '';
- $working[8] = usb_rev($speed);
+ $working[8] = $rev;
$working[9] = '';
$working[10] = $ports;
$working[15] = $driver;
- $working[17] = $speed;
+ $working[17] = $speed_si;
$working[18] = $cfg;
$working[19] = $power;
$working[20] = '';
$working[21] = $driver_nu;
+ $working[22] = $mode;
+ $working[25] = $speed_iec;
}
elsif (/^bDeviceClass\s*=\s*0x00([a-f0-9]{2})\s*(<([^>]+)>)?/){
$class_id = $1;
@@ -32129,9 +36815,10 @@ sub usbconfig_data {
}
}
main::log_data('dump','$usb{main}: usbconfig',$usb{'main'}) if $b_log;
- print Data::Dumper::Dumper $usb{'main'} if $dbg[6];
+ print 'usbconfig: ', Data::Dumper::Dumper $usb{'main'} if $dbg[6];
eval $end if $b_log;
}
+
# Controller /dev/usb2:
# addr 1: full speed, self powered, config 1, UHCI root hub(0x0000), Intel(0x8086), rev 1.00
# port 1 addr 2: full speed, power 98 mA, config 1, USB Receiver(0xc52b), Logitech(0x046d), rev 12.01
@@ -32153,9 +36840,10 @@ sub usbdevs_data {
$bus_id = $1;
}
elsif (/^addr\s([0-9]+):\s([^,]+),[^,0-9]+([0-9]+ mA)?,\s+config\s+([0-9]+),\s?([^,]+)\(0x([0-9a-f]{4})\),\s?([^,]+)\s?\(0x([0-9a-f]{4})\)/){
+ ($mode,$rev,$speed_si,$speed_iec) = ();
$hub_id = $1;
$addr_id = $1;
- $speed = prep_speed($2);
+ $speed_si = $2; # requires prep
$power = $3;
$chip_id = "$6:$8";
$config = $4;
@@ -32166,6 +36854,7 @@ sub usbdevs_data {
$ports = 0;
process_power(\$power) if $power;
$port_value = '';
+ version_data('bsd',\$speed_si,\$speed_iec,\$rev,\$mode);
$working[0] = $bus_id_alpha;
$working[1] = $addr_id;
$working[2] = $path_id;
@@ -32174,24 +36863,27 @@ sub usbdevs_data {
$working[5] = '';
$working[6] = '';
$working[7] = $chip_id;
- $working[8] = usb_rev($speed);
+ $working[8] = $rev;
$working[9] = '';
$working[10] = $ports;
$working[13] = $name;
$working[14] = 'Hub';
$working[15] = '';
$working[16] = '';
- $working[17] = $speed;
+ $working[17] = $speed_si;
$working[18] = $config;
$working[19] = $power;
$working[20] = '';
+ $working[22] = $mode;
+ $working[25] = $speed_iec;
}
elsif (/^port\s([0-9]+)\saddr\s([0-9]+):\s([^,]+),[^,0-9]*([0-9]+\s?mA)?,\s+config\s+([0-9]+),\s?([^,]+)\(0x([0-9a-f]{4})\),\s?([^,]+)\s?\(0x([0-9a-f]{4})\)/){
+ ($rev,$mode,$speed_iec,$speed_si) = ();
$port = $1;
- $addr_id = "$2";
+ $addr_id = $2;
+ $speed_si = $3;
$power = $4;
$config = $5;
- $speed = prep_speed($3);
$chip_id = "$7:$9";
$name = main::remove_duplicates("$8 $6");
$type = check_type($name,'','');
@@ -32201,6 +36893,7 @@ sub usbdevs_data {
$path_id = "$bus_id-$hub_id.$port";
$bus_id_alpha = bus_id_alpha($path_id);
process_power(\$power) if $power;
+ version_data('bsd',\$speed_si,\$speed_iec,\$rev,\$mode);
$working[0] = $bus_id_alpha;
$working[1] = $addr_id;
$working[2] = $path_id;
@@ -32209,7 +36902,7 @@ sub usbdevs_data {
$working[5] = '';
$working[6] = '';
$working[7] = $chip_id;
- $working[8] = usb_rev($speed);
+ $working[8] = $rev;
$working[9] = '';
$working[10] = $ports;
$working[11] = '';
@@ -32218,10 +36911,12 @@ sub usbdevs_data {
$working[14] = $type;
$working[15] = '';
$working[16] = '';
- $working[17] = $speed;
+ $working[17] = $speed_si;
$working[18] = $config;
$working[19] = $power;
$working[20] = '';
+ $working[22] = $mode;
+ $working[25] = $speed_iec;
}
elsif (/^port\s([0-9]+)\spowered/){
$ports++;
@@ -32262,17 +36957,20 @@ sub usbdevs_data {
$working[20] = '';
}
elsif ($b_multi &&
- /^([^,]+),\s+(self powered|power\s+([0-9]+\s+mA)),\s+config\s([0-9]+),\s+rev\s+([0-9\.]+)(,\s+i?Serial\s(\S*))?/i){
- $speed = prep_speed($1);
- $rev = usb_rev($speed);
+ /^([^,]+),\s+(self powered|power\s+([0-9]+\s+mA)),\s+config\s([0-9]+),\s+rev\s+([0-9\.]+)(,\s+i?Serial\s(\S*))?/i){
+ ($mode,$rev,$speed_iec,$speed_si) = ();
+ $speed_si = $1;
$power = $3;
process_power(\$power) if $power;
+ version_data('bsd',\$speed_si,\$speed_iec,\$rev,\$mode);
$working[8] = $rev;
$working[16] = $7 if $7;
- $working[17] = $speed;
+ $working[17] = $speed_si;
$working[18] = $4; # config number
$working[19] = $power;
$working[20] = $5; # product rev
+ $working[22] = $mode;
+ $working[25] = $speed_iec;
}
# 1 or more drivers supported
elsif ($b_multi && /^driver:\s*([^,]+)$/){
@@ -32293,7 +36991,7 @@ sub usbdevs_data {
}
}
main::log_data('dump','$usb{main}: usbdevs',$usb{'main'}) if $b_log;
- print Data::Dumper::Dumper $usb{'main'} if $dbg[6];
+ print 'usbdevs: ', Data::Dumper::Dumper $usb{'main'} if $dbg[6];
eval $end if $b_log;
}
@@ -32322,13 +37020,13 @@ sub usb_grabber {
else {
my $file;
if ($fake{'usbdevs'}){
- $file = "$fake_data_dir/lsusb/bsd-usbdevs-v-1.txt";
+ $file = "$fake_data_dir/usb/usbdevs/bsd-usbdevs-v-1.txt";
}
elsif ($fake{'usbconfig'}){
- $file = "$fake_data_dir/lsusb/bsd-usbconfig-list-v-1.txt";
+ $file = "$fake_data_dir/usb/usbconfig/bsd-usbconfig-list-v-1.txt";
}
else {
- $file = "$fake_data_dir/lsusb/mdmarmer-lsusb.txt";
+ $file = "$fake_data_dir/usb/lsusb/mdmarmer-lsusb.txt";
}
@data = main::reader($file,'strip');
}
@@ -32349,24 +37047,24 @@ sub usb_grabber {
sub sys_data {
eval $start if $b_log;
my ($source) = @_;
- my ($configuration,$ports,$usb_version);
+ my ($configuration,$lanes_rx,$lanes_tx,$ports,$mode,$rev);
my (@drivers,@uevent);
my $i = 0;
my @files = main::globber('/sys/bus/usb/devices/*');
# we want to get rid of the hubs with x-0: syntax, those are hubs found in /usbx
@files = grep {!/\/[0-9]+-0:/} @files;
# print join("\n", @files);
- foreach (@files){
+ foreach my $file (@files){
# be careful, sometimes uevent is not readable
- @uevent = (-r "$_/uevent") ? main::reader("$_/uevent") : undef;
+ @uevent = (-r "$file/uevent") ? main::reader("$file/uevent") : undef;
if (@uevent && ($ids = main::awk(\@uevent,'^(DEVNAME|DEVICE\b)',2,'='))){
- @drivers = ();
($b_hub,$class_id,$protocol_id,$subclass_id) = (0,0,0,0);
- ($configuration,$driver,$interfaces,$name,$ports,$product,$serial,$speed,
- $type,$usb_version,$vendor) = ('','','','','','','','','','','');
- # print Cwd::abs_path($_),"\n";
- # print "f1: $_\n";
- $path_id = $_;
+ (@drivers,$lanes_rx,$lanes_tx,$mode,$rev,$speed_iec,$speed_si) = ();
+ ($configuration,$driver,$interfaces,$name,$ports,$product,$serial,
+ $type,$vendor) = ('','','','','','','','','');
+ # print Cwd::abs_path($file),"\n";
+ # print "f1: $file\n";
+ $path_id = $file;
$path_id =~ s/^.*\///;
$path_id =~ s/^usb([0-9]+)/$1-0/;
# if DEVICE= then path = /proc/bus/usb/001/001 else: bus/usb/006/001
@@ -32377,29 +37075,32 @@ sub sys_data {
$bus_id_alpha = bus_id_alpha($path_id);
$device_id = int($working[3]);
# this will be a hex number
- $class_id = sys_item("$_/bDeviceClass");
- # $subclass_id = sys_item("$_/bDeviceSubClass");
- # $protocol_id = sys_item("$_/bDeviceProtocol");
+ $class_id = sys_item("$file/bDeviceClass");
+ # $subclass_id = sys_item("$file/bDeviceSubClass");
+ # $protocol_id = sys_item("$file/bDeviceProtocol");
$class_id = hex($class_id) if $class_id;
# $subclass_id = hex($subclass_id) if $subclass_id;
# $protocol_id = hex($protocol_id) if $protocol_id;
# print "$path_id $class_id/$subclass_id/$protocol_id\n";
- $power = sys_item("$_/bMaxPower");
+ $power = sys_item("$file/bMaxPower");
process_power(\$power) if $power;
# this populates class, subclass, and protocol id with decimal numbers
- @drivers = uevent_data("$_/[0-9]*/uevent");
- push(@drivers, uevent_data("$_/[0-9]*/*/uevent")) if !$b_hub;
- $ports = sys_item("$_/maxchild") if $b_hub;
+ @drivers = uevent_data("$file/[0-9]*/uevent");
+ push(@drivers, uevent_data("$file/[0-9]*/*/uevent")) if !$b_hub;
+ $ports = sys_item("$file/maxchild") if $b_hub;
if (@drivers){
main::uniq(\@drivers);
$driver = join(',', sort @drivers);
}
- $interfaces = sys_item("$_/bNumInterfaces");
- $serial = sys_item("$_/serial");
- $usb_version = sys_item("$_/version");
- $speed = sys_item("$_/speed");
- $configuration = sys_item("$_/configuration");
- $power = sys_item("$_/bMaxPower");
+ $interfaces = sys_item("$file/bNumInterfaces");
+ $lanes_rx = sys_item("$file/rx_lanes");
+ $lanes_tx = sys_item("$file/tx_lanes");
+ $serial = sys_item("$file/serial");
+ $rev = sys_item("$file/version");
+ $speed_si = sys_item("$file/speed");
+ version_data('sys',\$speed_si,\$speed_iec,\$rev,\$mode,$lanes_rx,$lanes_tx);
+ $configuration = sys_item("$file/configuration");
+ $power = sys_item("$file/bMaxPower");
process_power(\$power) if $power;
$class_id = sprintf("%02x", $class_id) if defined $class_id && $class_id ne '';
$subclass_id = sprintf("%02x", $subclass_id) if defined $subclass_id && $subclass_id ne '';
@@ -32409,27 +37110,31 @@ sub sys_data {
if (!$b_hub && $usb{'main'}->[$i][13] && (!$type || $type eq '<vendor specific>')){
$type = check_type($usb{'main'}->[$i][13],$driver,$type);
}
- # print $type,"\n";
$usb{'main'}->[$i][0] = $bus_id_alpha;
$usb{'main'}->[$i][2] = $path_id;
- $usb{'main'}->[$i][3] = $_;
+ $usb{'main'}->[$i][3] = $file;
$usb{'main'}->[$i][4] = $class_id;
$usb{'main'}->[$i][5] = $subclass_id;
$usb{'main'}->[$i][6] = $protocol_id;
- $usb{'main'}->[$i][8] = $usb_version;
+ $usb{'main'}->[$i][8] = $rev;
$usb{'main'}->[$i][9] = $interfaces;
$usb{'main'}->[$i][10] = $ports if $ports;
if ($type && $b_hub && (!$usb{'main'}->[$i][13] ||
- $usb{'main'}->[$i][13] =~ /^linux foundation/i)){
+ $usb{'main'}->[$i][13] =~ /^linux foundation/i)){
$usb{'main'}->[$i][13] = "$type";
}
$usb{'main'}->[$i][14] = $type if ($type && !$b_hub);
$usb{'main'}->[$i][15] = $driver if $driver;
$usb{'main'}->[$i][16] = $serial if $serial;
- $usb{'main'}->[$i][17] = $speed if $speed;
+ $usb{'main'}->[$i][17] = $speed_si if $speed_si;
$usb{'main'}->[$i][18] = $configuration;
$usb{'main'}->[$i][19] = $power;
$usb{'main'}->[$i][20] = '';
+ $usb{'main'}->[$i][22] = $mode;
+ $usb{'main'}->[$i][23] = $lanes_rx;
+ $usb{'main'}->[$i][24] = $lanes_tx;
+ $usb{'main'}->[$i][25] = $speed_iec if $speed_iec;
+ $usb{'main'}->[$i][26] = Cwd::abs_path($file);
assign_usb_type($usb{'main'}->[$i]);
# print join("\n",@{$usb{'main'}->[$i]}),"\n\n";# if !$b_hub;
last;
@@ -32437,13 +37142,13 @@ sub sys_data {
}
}
else {
- $chip_id = sys_item("$_/idProduct");
- $vendor_id = sys_item("$_/idVendor");
+ $chip_id = sys_item("$file/idProduct");
+ $vendor_id = sys_item("$file/idVendor");
# 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 = sys_item("$file/product");
$product = main::clean($product) if $product;
- $vendor = sys_item("$_/manufacturer");
+ $vendor = sys_item("$file/manufacturer");
$vendor = main::clean($vendor) if $vendor;
if (!$b_hub && ($product || $vendor)){
if ($vendor && $product && $product !~ /$vendor/){
@@ -32471,12 +37176,12 @@ sub sys_data {
$usb{'main'}->[$i][0] = $bus_id_alpha;
$usb{'main'}->[$i][1] = $device_id;
$usb{'main'}->[$i][2] = $path_id;
- $usb{'main'}->[$i][3] = $_;
+ $usb{'main'}->[$i][3] = $file;
$usb{'main'}->[$i][4] = $class_id;
$usb{'main'}->[$i][5] = $subclass_id;
$usb{'main'}->[$i][6] = $protocol_id;
$usb{'main'}->[$i][7] = "$vendor_id:$chip_id";
- $usb{'main'}->[$i][8] = $usb_version;
+ $usb{'main'}->[$i][8] = $rev;
$usb{'main'}->[$i][9] = $interfaces;
$usb{'main'}->[$i][10] = $ports;
$usb{'main'}->[$i][11] = $vendor;
@@ -32485,21 +37190,27 @@ sub sys_data {
$usb{'main'}->[$i][14] = $type;
$usb{'main'}->[$i][15] = $driver;
$usb{'main'}->[$i][16] = $serial;
- $usb{'main'}->[$i][17] = $speed;
+ $usb{'main'}->[$i][17] = $speed_si;
$usb{'main'}->[$i][18] = $configuration;
$usb{'main'}->[$i][19] = $power;
$usb{'main'}->[$i][20] = '';
+ $usb{'main'}->[$i][22] = $mode;
+ $usb{'main'}->[$i][23] = $lanes_rx;
+ $usb{'main'}->[$i][24] = $lanes_tx;
+ $usb{'main'}->[$i][25] = $speed_iec;
+ $usb{'main'}->[$i][26] = Cwd::abs_path($file);
assign_usb_type($usb{'main'}->[$i]);
$i++;
}
# print "$path_id ids: $bus_id:$device_id driver: $driver ports: $ports\n==========\n"; # if $dbg[6];;
}
}
- print Data::Dumper::Dumper $usb{'main'} if $source eq 'main' && $dbg[6];
+ print 'usb-sys: ', Data::Dumper::Dumper $usb{'main'} if $source eq 'main' && $dbg[6];
main::log_data('dump','$usb{main}: sys',$usb{'main'}) if $source eq 'main' && $b_log;
eval $end if $b_log;
}
-# get driver, interface [type:] data
+
+# Get driver, interface [type:] data
sub uevent_data {
my ($path) = @_;
my ($interface,$interfaces,$temp,@interfaces,@drivers);
@@ -32554,6 +37265,7 @@ sub uevent_data {
}
return @drivers;
}
+
sub sys_item {
my ($path) = @_;
my ($item);
@@ -32562,15 +37274,16 @@ sub sys_item {
$item = main::trimmer($item) if $item;
return $item;
}
+
sub assign_usb_type {
my ($row) = @_;
- # it's a hub
- # a device will always be the second or > device on the bus, although
- # nested hubs of course can be > 1 too. No need to build these if none of
- # lines are showing.
+ # It's a hub. A device will always be the second or > device on the bus,
+ # although nested hubs of course can be > 1 too. No need to build these if
+ # none of lines are showing.
if (($row->[4] && $row->[4] eq '09') ||
- ($row->[14] && $row->[14] eq 'Hub') || $row->[1] <= 1 ||
- (!$show{'audio'} && !$show{'bluetooth'} && !$show{'graphic'} && !$show{'network'})){
+ ($row->[14] && lc($row->[14]) eq 'hub') || $row->[1] <= 1 ||
+ (!$show{'audio'} && !$show{'bluetooth'} && !$show{'disk'} &&
+ !$show{'graphic'} && !$show{'network'})){
return;
}
$row->[13] = '' if !defined $row->[13]; # product
@@ -32579,29 +37292,45 @@ sub assign_usb_type {
set_asound_ids() if $show{'audio'} && !$b_asound;
set_network_regex() if $show{'network'} && !$network_regex;
# NOTE: a device, like camera, can be audio+graphic
+ # NOTE: 13, 14 can be upper/lower case, so use i.
if ($show{'audio'} && (
(@asound_ids && $row->[7] && (grep {$row->[7] eq $_} @asound_ids)) ||
- ($row->[14] =~ /Audio/) || ($row->[15] && $row->[15] =~ /audio/) ||
- ($row->[13] && lc($row->[13]) =~ /(audio|\bdac[0-9]*\b|headphone|\bmic(rophone)?\b)/))){
+ ($row->[14] && $row->[14] =~ /audio/i) ||
+ ($row->[15] && $row->[15] =~ /audio/) ||
+ ($row->[13] && lc($row->[13]) =~ /(audio|\bdac[0-9]*\b|headphone|\bmic(rophone)?\b)/i)
+ )){
push(@{$usb{'audio'}},$row);
}
- if ($show{'graphic'} && ($row->[14] && ($row->[14] =~ /Video/) ||
+ if ($show{'graphic'} && (
+ ($row->[14] && $row->[14] =~ /video/i) ||
($row->[15] && $row->[15] =~ /video/) ||
- ($row->[13] && lc($row->[13]) =~ /(camera|\bdvb-t|\b(pc)?tv\b|video|webcam)/))){
+ ($row->[13] && lc($row->[13]) =~ /(camera|\bdvb-t|\b(pc)?tv\b|video|webcam)/i)
+ )){
push(@{$usb{'graphics'}},$row);
}
- elsif ($show{'bluetooth'} && ($row->[14] && $row->[14] =~ /Bluetooth/ ||
- ($row->[15] && $row->[15] =~ /\b(btusb|ubt)\b/))){
+ # we want to catch bluetooth devices, which otherwise can trip network regex
+ elsif (($show{'bluetooth'} || $show{'network'}) && (
+ ($row->[14] && $row->[14] =~ /bluetooth/i) ||
+ ($row->[15] && $row->[15] =~ /\b(btusb|ubt)\b/) ||
+ ($row->[13] && $row->[13] =~ /bluetooth/i)
+ )){
push(@{$usb{'bluetooth'}},$row);
}
+ elsif ($show{'disk'} && (
+ ($row->[14] && $row->[14] =~ /mass storage/i) ||
+ ($row->[15] && $row->[15] =~ /storage/)
+ )){
+ push(@{$usb{'disk'}},$row);
+ }
elsif ($show{'network'} && (
- ($row->[14] && $row->[14] =~ /(Ethernet|Network|WiFi)/i) ||
+ ($row->[14] && $row->[14] =~ /(ethernet|network|wifi)/i) ||
($row->[15] && $row->[15] =~ /(^ipw|^iwl|wifi)/) ||
- ($row->[13] && $row->[13] =~ /($network_regex)/i))){
- # print "$1\n";
+ ($row->[13] && $row->[13] =~ /($network_regex)/i)
+ )){
push(@{$usb{'network'}},$row);
}
}
+
sub device_type {
my ($data) = @_;
my ($type);
@@ -32615,54 +37344,86 @@ sub device_type {
$subclass_id = $types[1];
$protocol_id = $types[2];
}
- if ($types[0] eq '1'){$type = 'Audio';}
+ if ($types[0] eq '1'){
+ $type = 'audio';}
elsif ($types[0] eq '2'){
- if ($types[1] eq '2'){$type = 'Abstract (modem)';}
- elsif ($types[1] eq '6'){$type = 'Ethernet Network';}
- elsif ($types[1] eq '10'){$type = 'Mobile Direct Line';}
- elsif ($types[1] eq '12'){$type = 'Ethernet Emulation';}
- else {$type = 'Communication';}
+ if ($types[1] eq '2'){
+ $type = 'abstract (modem)';}
+ elsif ($types[1] eq '6'){
+ $type = 'ethernet network';}
+ elsif ($types[1] eq '10'){
+ $type = 'mobile direct line';}
+ elsif ($types[1] eq '12'){
+ $type = 'ethernet emulation';}
+ else {
+ $type = 'communication';}
}
elsif ($types[0] eq '3'){
- if ($types[2] eq '0'){$type = 'HID';} # actual value: None
- elsif ($types[2] eq '1'){$type = 'Keyboard';}
- elsif ($types[2] eq '2'){$type = 'Mouse';}
- }
- elsif ($types[0] eq '6'){$type = 'Still Imaging';}
- elsif ($types[0] eq '7'){$type = 'Printer';}
- elsif ($types[0] eq '8'){$type = 'Mass Storage';}
+ if ($types[2] eq '0'){
+ $type = 'HID';} # actual value: None
+ elsif ($types[2] eq '1'){
+ $type = 'keyboard';}
+ elsif ($types[2] eq '2'){
+ $type = 'mouse';}
+ }
+ elsif ($types[0] eq '6'){
+ $type = 'still imaging';}
+ elsif ($types[0] eq '7'){
+ $type = 'printer';}
+ elsif ($types[0] eq '8'){
+ $type = 'mass storage';}
# note: there is a bug in linux kernel that always makes hubs 9/0/0
elsif ($types[0] eq '9'){
- if ($types[2] eq '0'){$type = 'Full speed or root hub';}
- elsif ($types[2] eq '1'){$type = 'Hi-speed hub with single TT';}
- elsif ($types[2] eq '2'){$type = 'Hi-speed hub with multiple TTs';}
+ if ($types[2] eq '0'){
+ $type = 'full speed or root hub';}
+ elsif ($types[2] eq '1'){
+ $type = 'hi-speed hub with single TT';}
+ elsif ($types[2] eq '2'){
+ $type = 'hi-speed hub with multiple TTs';}
# seen protocol 3, usb3 type hub, but not documented on usb.org
- elsif ($types[2] eq '3'){$type = 'Super-speed hub';}
+ elsif ($types[2] eq '3'){
+ $type = 'super-speed hub';}
# this is a guess, never seen it
- elsif ($types[2] eq '4'){$type = 'Super-speed+ hub';}
- }
- elsif ($types[0] eq '10'){$type = 'CDC-Data';}
- elsif ($types[0] eq '11'){$type = 'Smart Card';}
- elsif ($types[0] eq '13'){$type = 'Content Security';}
- elsif ($types[0] eq '14'){$type = 'Video';}
- elsif ($types[0] eq '15'){$type = 'Personal Healthcare';}
- elsif ($types[0] eq '16'){$type = 'Audio-Video';}
- elsif ($types[0] eq '17'){$type = 'Billboard';}
- elsif ($types[0] eq '18'){$type = 'Type-C Bridge';}
- elsif ($types[0] eq '88'){$type = 'Xbox';}
- elsif ($types[0] eq '220'){$type = 'Diagnostic';}
+ elsif ($types[2] eq '4'){
+ $type = 'super-speed+ hub';}
+ }
+ elsif ($types[0] eq '10'){
+ $type = 'CDC-data';}
+ elsif ($types[0] eq '11'){
+ $type = 'smart card';}
+ elsif ($types[0] eq '13'){
+ $type = 'content security';}
+ elsif ($types[0] eq '14'){
+ $type = 'video';}
+ elsif ($types[0] eq '15'){
+ $type = 'personal healthcare';}
+ elsif ($types[0] eq '16'){
+ $type = 'audio-video';}
+ elsif ($types[0] eq '17'){
+ $type = 'billboard';}
+ elsif ($types[0] eq '18'){
+ $type = 'type-C bridge';}
+ elsif ($types[0] eq '88'){
+ $type = 'Xbox';}
+ elsif ($types[0] eq '220'){
+ $type = 'diagnostic';}
elsif ($types[0] eq '224'){
- if ($types[1] eq '1'){$type = 'Bluetooth';}
+ if ($types[1] eq '1'){
+ $type = 'bluetooth';}
elsif ($types[1] eq '2'){
- if ($types[2] eq '1'){$type = 'Host Wire Adapter';}
- elsif ($types[2] eq '2'){$type = 'Device Wire Adapter';}
- elsif ($types[2] eq '3'){$type = 'Device Wire Adapter';}
+ if ($types[2] eq '1'){
+ $type = 'host wire adapter';}
+ elsif ($types[2] eq '2'){
+ $type = 'device wire adapter';}
+ elsif ($types[2] eq '3'){
+ $type = 'device wire adapter';}
}
}
# print "$data: $type\n";
return $type;
}
-# device name/driver string based test, return <vendor specific> if not detected
+
+# Device name/driver string based test, return <vendor specific> if not detected
# for linux based tests, and empty for bsd tests
sub check_type {
my ($name,$driver,$type) = @_;
@@ -32681,12 +37442,12 @@ sub check_type {
$name =~ /(camera|display|\bdvb-t|\b(pc)?tv\bvideo|webcam)/){
$type = 'Video';
}
- elsif ($name =~ /(wlan|wi-?fi|802\.1[15]|(11|54|108|240|300|450|1300)\s?mbps|(11|54|108|240)g\b|wireless[\s-][gn]\b|wireless.*adapter)/){
+ elsif ($name =~ /(wlan|wi-?fi|802\.1[15]|(11|54|108|240|300|433|450|900|1300)\s?mbps|(11|54|108|240)g\b|wireless[\s-][bgn]\b|wireless.*adapter)/){
$type = 'WiFi';
}
# note, until freebsd match to actual drivers, these top level driver matches aren't interesting
elsif (($driver && $bsd_type && $driver =~ /\b(muge)\b/) ||
- $name =~ /(ethernet|\blan|802\.3|100?\/1000?|gigabit)/){
+ $name =~ /(ethernet|\blan|802\.3|100?\/1000?|gigabit|10\s?G(b|ig)?E)/){
$type = 'Ethernet';
}
# note: audio devices show HID sometimes, not sure why
@@ -32699,6 +37460,7 @@ sub check_type {
}
return $type;
}
+
# linux only, will create a positive match to sound devices
sub set_asound_ids {
$b_asound = 1;
@@ -32713,94 +37475,250 @@ sub set_asound_ids {
}
main::log_data('dump','@asound_ids',\@asound_ids) if $b_log;
}
-### USB networking search string data, because some brands can have other products than
-### wifi/nic cards, they need further identifiers, with wildcards.
-### putting the most common and likely first, then the less common, then some specifics
+
+# USB networking search string data, because some brands can have other products
+# than wifi/nic cards, they need further identifiers, with wildcards. Putting
+# the most common and likely first, then the less common, then some specifics
sub set_network_regex {
# belkin=050d; d-link=07d1; netgear=0846; ralink=148f; realtek=0bda;
# Atmel, Atheros make other stuff. NOTE: exclude 'networks': IMC Networks
- # ralink has bluetooth as well as networking; (WG|WND?A)[0-9][0-9][0-9] netgear IDs
+ # intel, ralink bluetooth as well as networking; (WG|WND?A)[0-9][0-9][0-9] netgear IDs
$network_regex = 'Ethernet|gigabit|\bISDN|\bLAN\b|Mobile\s?Broadband|';
$network_regex .= '\bNIC\b|wi-?fi|Wireless[\s-][GN]\b|WLAN|';
$network_regex .= '802\.(1[15]|3)|(10|11|54|108|240|300|450|1300)\s?Mbps|(11|54|108|240)g\b|100?\/1000?|';
$network_regex .= '(100?|N)Base-?T\b|';
$network_regex .= '(Actiontec|AirLink|Asus|Belkin|Buffalo|Dell|D-Link|DWA-|ENUWI-|';
- $network_regex .= 'Ralink|Realtek|Rosewill|RNX-|Samsung|Sony|TEW-|TP-Link';
+ $network_regex .= 'Ralink|Realtek|Rosewill|RNX-|Samsung|Sony|TEW-|TP-Link|';
$network_regex .= 'Zonet.*ZEW.*).*Wireless|';
+ # Note: Intel Bluetooth wireless interface < should be caught by bluetooth tests
$network_regex .= '(\bD-Link|Network(ing)?|Wireless).*(Adapter|Interface)|';
$network_regex .= '(Linksys|Netgear|Davicom)|';
$network_regex .= 'Range(Booster|Max)|Samsung.*LinkStick|\b(WG|WND?A)[0-9][0-9][0-9]|';
$network_regex .= '\b(050d:935b|0bda:8189|0bda:8197)\b';
}
-# try to guess at usb rev version from speeds
-sub usb_rev {
- return if !$_[0] || ! main::is_numeric($_[0]);
- my $rev;
- if ($_[0] < 2){$rev = '1.0';}
- elsif ($_[0] < 13){$rev = '1.1';}
- elsif ($_[0] < 481){$rev = '2.0';}
- elsif ($_[0] < 5001){$rev = '3.0';}
- elsif ($_[0] < 10001){$rev = '3.1';}
- elsif ($_[0] < 20001){$rev = '3.2';}
- elsif ($_[0] < 40001){$rev = '4.0';}
- return $rev;
+
+# For linux, process rev, get mode. For bsds, get rev, speed.
+# args: 0: sys/bsd; 1: speed_si; 2: speed_iec; 3: rev; 4: rev_info; 5: rx lanes;
+# 6: tx lanes
+# 1,2,3,4 passed by reference.
+sub version_data {
+ return if !${$_[1]};
+ if ($_[0] eq 'sys'){
+ if (${$_[3]} && main::is_numeric(${$_[3]})){
+ # as far as we know, 4 will not have subversions, but this may change,
+ # check how /sys reports this in coming year(s)
+ if (${$_[3]} =~ /^4/){
+ ${$_[3]} = ${$_[3]} + 0;
+ }
+ else {
+ ${$_[3]} = sprintf('%.1f',${$_[3]});
+ }
+ }
+ # BSD rev is synthetic, it's a hack. And no lane data, so not trying.
+ if ($b_admin && ${$_[1]} && ${$_[3]} && $_[5] && $_[6] &&
+ ${$_[3]} =~ /^[1234]/){
+ if (${$_[3]} =~ /^[12]/){
+ if (${$_[1]} == 1.5){
+ ${$_[4]} = '1.0';}
+ elsif (${$_[1]} == 12){
+ ${$_[4]} = '1.1';}
+ elsif (${$_[1]} == 480){
+ ${$_[4]} = '2.0';}
+ }
+ # Note: unless otherwise indicated, 1 lane is 1rx+1tx.
+ elsif (${$_[3]} =~ /^3/){
+ if (${$_[1]} == 5000){
+ ${$_[4]} = '3.2 gen-1x1';} # 1 lane
+ elsif (${$_[1]} == 10000){
+ if ($_[6] == 1){
+ ${$_[4]} = '3.2 gen-2x1';} # 1 lane
+ elsif ($_[6] == 2){
+ ${$_[4]} = '3.2 gen-1x2';} # 2 lane
+ }
+ elsif (${$_[1]} == 20000){
+ if ($_[6] == 1){
+ ${$_[4]} = '3.2 gen-3x1';} # 1 lane
+ elsif ($_[6] == 2){
+ ${$_[4]} = '3.2 gen-2x2';} # 2 lane
+ }
+ # just in case rev: 3.x shows these speeds
+ elsif (${$_[1]} == 40000){
+ if ($_[6] == 1){
+ ${$_[4]} = '4-v1 gen-4x1';} # 1 lane
+ elsif ($_[6] == 2){
+ ${$_[4]} = '4-v1 gen-3x2';} # 2 lane
+ }
+ elsif (${$_[1]} == 80000){
+ ${$_[4]} = '4-v2 gen-4x2'; # 2 lanes
+ }
+ ${$_[4]} = main::message('usb-mode-mismatch') if !${$_[4]};
+ }
+ # NOTE: no realworld usb4 data, unclear if these gen are reliable.
+ # possible /sys will expose v1/v2/v3. Check future data.
+ elsif (${$_[3]} =~ /^4/){
+ # gen 2: 10gb x 1 ln
+ if (${$_[1]} < 10001){
+ ${$_[4]} = '4-v1 gen-2x1';} # 1 lane
+ # gen2: 10gb x 2 ln; gen3: 20gb x 1 ln. Confirm
+ elsif (${$_[1]} < 20001){
+ if ($_[6] == 2){
+ ${$_[4]} = '4-v1 gen-2x2';} # 2 lanes
+ elsif ($_[6] == 1){
+ ${$_[4]} = '4-v1 gen-3x1';} # 1 lane
+ }
+ # gen3: 20gb x 2 ln; gen4 40gb x 1 ln. Confirm
+ elsif (${$_[1]} < 40001){
+ if ($_[6] == 2){
+ ${$_[4]} = '4-v1 gen-3x2';} # 2 lanes
+ elsif ($_[6] == 1){
+ ${$_[4]} = '4-v2 gen-4x1';} # 1 lane
+ }
+ # 40gb x 2 ln
+ elsif (${$_[1]} < 80001){
+ ${$_[4]} = '4-v2 gen-4x2';} # 2 lanes
+ # 3 lanes: 2 tx+tx @ 60gb, 1 rx+rx @ 40gb, wait for data
+ elsif (${$_[1]} < 120001){
+ ${$_[4]} = '4-v2 gen-4x3-asym'; # 3 lanes, asymmetric
+ }
+ ${$_[4]} = main::message('usb-mode-mismatch') if !${$_[4]};
+ }
+ }
+ }
+ else {
+ (${$_[1]},${$_[3]}) = prep_speed(${$_[1]});
+ # bsd rev hardcoded. We want this set to undef if bad data
+ ${$_[3]} = usb_rev(${$_[1]}) if !${$_[3]};
+ }
+ # Add Si/IEC units
+ if ($extra > 0 && ${$_[1]}){
+ # 1 == 1000000 bits
+ my $si = ${$_[1]};
+ if (${$_[1]} >= 1000){
+ ${$_[1]} = (${$_[1]}/1000) . ' Gb/s';
+ }
+ else {
+ ${$_[1]} = ${$_[1]} . ' Mb/s';
+ }
+ if ($b_admin){
+ $si = (($si*1000**2)/8);
+ if ($si < 1000000){
+ ${$_[2]} = sprintf('%0.0f KiB/s',($si/1024));
+ }
+ elsif ($si < 1000000000){
+ ${$_[2]} = sprintf('%0.1f MiB/s',$si/1024**2);
+ }
+ else {
+ ${$_[2]} = sprintf('%0.2f GiB/s',($si/1024**3));
+ }
+ }
+ }
+ # print Data::Dumper::Dumper \@_;
}
+
+## BSD SPEED/REV ##
+# Mapping of speed string to known speeds. Unreliable, very inaccurate, and some
+# unconfirmed. Without real data source can never be better than a decent guess.
+# args: 0: speed string
sub prep_speed {
return if !$_[0];
- my $speed = $_[0];
+ my $speed_si = $_[0];
+ my $rev;
if ($_[0] =~ /^([0-9\.]+)\s*Mb/){
- $speed = $1;
+ $speed_si = $1;
}
elsif ($_[0] =~ /^([0-9\.]+)+\s*Gb/){
- $speed = $1 * 1000;
+ $speed_si = $1 * 1000;
+ }
+ elsif ($_[0] =~ /usb4?\s?120/i){
+ $speed_si = 120000;# 4 120Gbps
+ $rev = '4';
+ }
+ elsif ($_[0] =~ /usb4?\s?80/i){
+ $speed_si = 80000;# 4 80Gbps
+ $rev = '4';
}
- elsif ($_[0] =~ /usb\s?40/i){
- $speed = 40000;# 4 40gbps
+ elsif ($_[0] =~ /usb4?\s?40/i){
+ $speed_si = 40000;# 4 40Gbps
+ $rev = '4';
}
- elsif ($_[0] =~ /usb\s?20/i){
- $speed = 20000;# 4 20gbps
+ elsif ($_[0] =~ /usb4?\s?20/i){
+ $speed_si = 20000;# 4 20Gbps
+ $rev = '4';
+ }
+ elsif ($_[0] =~ /usb\s?20|super[\s-]?speed\s?(\+|plus) gen[\s-]?2x2/i){
+ $speed_si = 20000;# 3.2 20Gbps
+ $rev = '3.2';
}
# could be 3.2, 20000 too, also superspeed+
elsif ($_[0] =~ /super[\s-]?speed\s?(\+|plus)/i){
- $speed = 10000;# 3.1; # can't trust bsds to use superspeed+ but we'll hope
+ $speed_si = 10000;# 3.1; # can't trust bsds to use superspeed+ but we'll hope
+ $rev = '3.1';
}
elsif ($_[0] =~ /super[\s-]?speed/i){
- $speed = 5000;# 3.0;
+ $speed_si = 5000;# 3.0;
+ $rev = '3.0';
}
elsif ($_[0] =~ /hi(gh)?[\s-]?speed/i){
- $speed = 480; # 2.0,
+ $speed_si = 480; # 2.0,
+ $rev = '2.0';
}
elsif ($_[0] =~ /full[\s-]?speed/i){
- $speed = 12; # 1.1 - could be full speed 1.1/2.0
+ $speed_si = 12; # 1.1 - could be full speed 1.1/2.0
+ $rev = '1.1';
}
elsif ($_[0] =~ /low?[\s-]?speed/i){
- $speed = 1.5; # 1.5 - could be 1.0, or low speed 1.1/2.0
+ $speed_si = 1.5; # 1.5 - could be 1.0, or low speed 1.1/2.0
+ $rev = '1.0';
}
- return $speed;
+ else {
+ undef $speed_si; # we don't know what the syntax was
+ }
+ return ($speed_si,$rev);
}
-sub process_power {
- return if !${$_[0]};
- ${$_[0]} =~ s/\s//g;
- # ${$_[0]} = '' if ${$_[0]} eq '0mA'; # better to handle on output
+
+# Try to guess at usb rev version from speed. Unreliable, very inaccurate.
+# Note: this will probably be so inaccurate with USB 3.2/4 that it might be best
+# to remove this feature at some point, unless better data sources found.
+# args: 0: speed
+sub usb_rev {
+ return if !$_[0] || !main::is_numeric($_[0]);
+ my $rev;
+ if ($_[0] < 2){
+ $rev = '1.0';}
+ elsif ($_[0] < 13)
+ {$rev = '1.1';}
+ elsif ($_[0] < 481){
+ $rev = '2.0';}
+ # 5 Gbps
+ elsif ($_[0] < 5001)
+ {$rev = '3.0';}
+ # 10 Gbps, this can be 3.1, 3.2 or 4
+ elsif ($_[0] < 10001){
+ $rev = '3.1';}
+ # SuperSpeed 'USB 20Gbps', this can be 3.2 or 4
+ elsif ($_[0] < 20001){
+ $rev = '3.2';}
+ # 4 does not use 4.x syntax, and real lanes/rev/speed data source required.
+ # 4: 10-120 Gbps. Update once data available for USB 3.2/4 speed strings
+ elsif ($_[0] < 120001){
+ $rev = '4';}
+ return $rev;
}
-# this is used to create an alpha sortable bus id for main $usb[0]
+
+## UTILITIES ##
+# This is used to create an alpha sortable bus id for main $usb[0]
sub bus_id_alpha {
my ($id) = @_;
$id =~ s/^([1-9])-/0$1-/;
$id =~ s/([-\.:])([0-9])\b/${1}0$2/g;
return $id;
}
-}
-# note: seen instance in android where reading file hangs endlessly!!!
-sub get_wakeups {
- eval $start if $b_log;
- return if %risc;
- my ($wakeups);
- my $path = '/sys/power/wakeup_count';
- $wakeups = reader($path,'strip',0) if -r $path;
- eval $end if $b_log;
- return $wakeups;
+sub process_power {
+ return if !${$_[0]};
+ ${$_[0]} =~ s/\s//g;
+ # ${$_[0]} = '' if ${$_[0]} eq '0mA'; # better to handle on output
+}
}
########################################################################
@@ -32812,18 +37730,20 @@ sub get_wakeups {
{
package OutputGenerator;
my ($items,$subs);
+
sub generate {
eval $start if $b_log;
my ($item,%checks);
- main::set_ps_aux() if !$loaded{'ps-aux'};
+ PsData::set_cmd() if !$loaded{'ps-cmd'};
main::set_sysctl_data() if $use{'sysctl'};
main::set_dboot_data() if $bsd_type && !$loaded{'dboot'};
# note: ps aux loads before logging starts, so create debugger data here
if ($b_log){
- # I don't think we need to see this, it's long, but leave in case we do
+ # With logging, we already get ps wwwaux so no need to get it again here
# main::log_data('dump','@ps_aux',\@ps_aux);
main::log_data('dump','@ps_cmd',\@ps_cmd);
}
+ print Data::Dumper::Dumper \@ps_cmd if $dbg[61];
if ($show{'short'}){
$item = short_output();
assign_data($item);
@@ -32897,6 +37817,7 @@ sub generate {
assign_data($item);
}
if ($show{'disk'} || $show{'disk-basic'} || $show{'disk-total'} || $show{'optical'}){
+ UsbData::set(\$checks{'usb'}) if !$checks{'usb'};
$item = item_handler('Drives','disk');
assign_data($item);
}
@@ -32943,13 +37864,13 @@ sub generate {
}
eval $end if $b_log;
}
+
## Short, Info, System Items ##
sub short_output {
eval $start if $b_log;
my $num = 0;
my $kernel_os = ($bsd_type) ? 'OS' : 'Kernel';
my ($cpu_string,$speed,$speed_key,$type) = ('','','speed','');
- my $memory = MemoryData::get('string');
my $cpu = CpuItem::get('short');
if (ref $cpu eq 'ARRAY' && scalar @$cpu > 1){
$type = ($cpu->[2]) ? " (-$cpu->[2]-)" : '';
@@ -33005,7 +37926,8 @@ sub short_output {
$disk_string = "$used/$size";
}
}
- $memory ||= 'N/A';
+ my $memory = MemoryData::get('short');
+ $memory = 'N/A' if !$memory;
# print join('; ', @cpu), " sleep: $cpu_sleep\n";
if (!$loaded{'shell-data'} && $ppid && (!$b_irc || !$client{'name-print'})){
ShellData::set();
@@ -33032,51 +37954,73 @@ sub short_output {
main::key($prefix,1,0,'SHORT') => $data,
};
}
+
sub info_item {
eval $start if $b_log;
my $num = 0;
- my $gcc_alt = '';
my $running_in = '';
my $data_name = main::key($prefix++,1,0,'Info');
- my ($b_gcc,$gcc,$index);
- my ($gpu_ram,$parent,$percent,$total,$used) = (0,'','','','');
- my $gccs = main::get_gcc_data();
- if (@$gccs){
- $gcc = shift @$gccs;
- if ($extra > 1 && @$gccs){
- $gcc_alt = join('/', @$gccs);
- }
- $b_gcc = 1;
- }
- $gcc ||= 'N/A';
+ my ($index);
+ my ($available,$gpu_ram,$parent,$percent,$used) = ('',0,'','','');
my $data = {
- $data_name => [{
- main::key($num++,0,1,'Processes') => scalar @ps_aux,
- main::key($num++,1,1,'Uptime') => main::get_uptime(),
- },],
+ $data_name => [{}],
};
- $index = scalar(@{$data->{$data_name}}) - 1;
- if ($extra > 2){
- my $wakeups = main::get_wakeups();
- $data->{$data_name}[$index]{main::key($num++,0,2,'wakeups')} = $wakeups if defined $wakeups;
- }
+ $index = 0;
if (!$loaded{'memory'}){
- my $memory = MemoryData::get('splits');
- if ($memory){
- my @temp = split(':', $memory);
- $gpu_ram = $temp[3] if $temp[3];
- $total = ($temp[0]) ? main::get_size($temp[0],'string') : 'N/A';
- $used = ($temp[1]) ? main::get_size($temp[1],'string') : 'N/A';
- $used .= " ($temp[2]%)" if $temp[2];
- if ($gpu_ram){
- $gpu_ram = main::get_size($gpu_ram,'string');
- }
+ main::MemoryData::row('info',$data->{$data_name}[$index],\$num,1);
+ if ($gpu_ram){
+ $data->{$data_name}[$index]{main::key($num++,0,2,'gpu')} = $gpu_ram;
}
- $data->{$data_name}[$index]{main::key($num++,1,1,'Memory')} = $total;
- $data->{$data_name}[$index]{main::key($num++,0,2,'used')} = $used;
+ $index++;
+ }
+ $data->{$data_name}[$index]{main::key($num++,0,1,'Processes')} = scalar @ps_aux;
+ my $uptime = main::get_uptime();
+ if ($bsd_type || $extra < 2){
+ $data->{$data_name}[$index]{main::key($num++,1,1,'Uptime')} = $uptime;
}
- if ($gpu_ram){
- $data->{$data_name}[$index]{main::key($num++,0,2,'gpu')} = $gpu_ram;
+ if (!$bsd_type && $extra > 1){
+ my $power = PowerData::get();
+ $data->{$data_name}[$index]{main::key($num++,1,1,'Power')} = '';
+ $data->{$data_name}[$index]{main::key($num++,0,2,'uptime')} = $uptime;
+ if ($power->{'states-avail'}){
+ $data->{$data_name}[$index]{main::key($num++,0,2,'states')} = $power->{'states-avail'};
+ }
+ my $resumes = (defined $power->{'suspend-resumes'}) ? $power->{'suspend-resumes'} : undef;
+ if ($extra > 2){
+ my $suspend = (defined $power->{'suspend-active'}) ? $power->{'suspend-active'} : '';
+ $data->{$data_name}[$index]{main::key($num++,1,2,'suspend')} = $suspend;
+ if ($b_admin && $power->{'suspend-avail'}){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'avail')} = $power->{'suspend-avail'};
+ }
+ if (defined $resumes){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'wakeups')} = $resumes;
+ if ($b_admin && $power->{'suspend-fails'}){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'fails')} = $power->{'suspend-fails'};
+ }
+ }
+ if (defined $power->{'hibernate-active'}){
+ $data->{$data_name}[$index]{main::key($num++,1,2,'hibernate')} = $power->{'hibernate-active'};
+ if ($b_admin && $power->{'hibernate-avail'}){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'avail')} = $power->{'hibernate-avail'};
+ }
+ if ($b_admin && $power->{'hibernate-image-size'}){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'image')} = $power->{'hibernate-image-size'};
+ }
+ }
+ if ($b_admin){
+ PsData::set_power();
+ if (@{$ps_data{'power-services'}}){
+ my $services;
+ main::make_list_value($ps_data{'power-services'},\$services,',','sort');
+ $data->{$data_name}[$index]{main::key($num++,0,2,'services')} = $services;
+ }
+ }
+ }
+ else {
+ if (defined $resumes){
+ $data->{$data_name}[$index]{main::key($num++,0,2,'wakeups')} = $resumes;
+ }
+ }
}
if ((!$b_display || $force{'display'}) || $extra > 0){
my $init = InitData::get();
@@ -33106,32 +38050,38 @@ sub info_item {
}
}
}
- if ($extra > 0){
- my $b_clang;
- my $clang_version = '';
- if (my $path = main::check_program('clang')){
- $clang_version = main::program_version($path,'clang',3,'--version');
- $clang_version ||= 'N/A';
- $b_clang = 1;
- }
- my $compiler = ($b_gcc || $b_clang) ? '': 'N/A';
- $data->{$data_name}[$index]{main::key($num++,1,1,'Compilers')} = $compiler;
- if ($b_gcc){
- $data->{$data_name}[$index]{main::key($num++,1,2,'gcc')} = $gcc;
- if ($extra > 1 && $gcc_alt){
- $data->{$data_name}[$index]{main::key($num++,0,3,'alt')} = $gcc_alt;
- }
- }
- if ($b_clang){
- $data->{$data_name}[$index]{main::key($num++,0,2,'clang')} = $clang_version;
- }
- }
+ $index++ if $extra > 0;
if ($extra > 0 && !$loaded{'package-data'}){
my $packages = PackageData::get('inner',\$num);
+
for (keys %$packages){
$data->{$data_name}[$index]{$_} = $packages->{$_};
}
}
+ if ($extra > 0){
+ my (%cc,$path);
+ foreach my $compiler (qw(clang gcc zigcc)){
+ my $comps = main::get_compiler_data($compiler);
+ if (@$comps){
+ $cc{$compiler}->{'version'} = shift @$comps;
+ if ($extra > 1 && @$comps){
+ $cc{$compiler}->{'alt'} = join('/', @$comps);
+ }
+ $cc{$compiler}->{'version'} ||= 'N/A'; # should not be needed after fix but leave in case undef
+ }
+ }
+ my $cc_value = ($cc{'clang'} || $cc{'gcc'} || $cc{'zigcc'}) ? '': 'N/A';
+ $data->{$data_name}[$index]{main::key($num++,1,1,'Compilers')} = $cc_value;
+ foreach my $compiler (qw(clang gcc zigcc)){
+ if ($cc{$compiler}){
+ $data->{$data_name}[$index]{main::key($num++,0,2,$compiler)} = $cc{$compiler}->{'version'};
+ if ($extra > 1 && $cc{$compiler}->{'alt'}){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'alt')} = $cc{$compiler}->{'alt'};
+ }
+ }
+ }
+ }
+ # $index++ if $extra > 1 && !$loaded{'shell-data'};
if (!$loaded{'shell-data'} && $ppid && (!$b_irc || !$client{'name-print'})){
ShellData::set();
}
@@ -33182,26 +38132,30 @@ sub info_item {
eval $end if $b_log;
return $data;
}
+
sub system_item {
eval $start if $b_log;
my ($cont_desk,$ind_dm,$num) = (1,2,0);
my ($index);
my $data_name = main::key($prefix++,1,0,'System');
- my ($desktop,$desktop_info,$desktop_key,$dm_key,$toolkit,$wm) = ('','','Desktop','dm','','');
- my (@desktop_data,$desktop_version,$tk_version,$wm_version);
+ my ($desktop,$desktop_key,$toolkit,$wm) = ('','Desktop','','');
+ my ($cs_curr,$cs_avail,@desktop_data,$de_components,$de_info,$de_info_v,
+ $de_version,$tools_running,$tools_avail,$tk_version,$wm_version);
my $data = {
$data_name => [{}],
};
- $index = scalar(@{$data->{$data_name}}) - 1;
+ $index = 0;
if ($show{'host'}){
$data->{$data_name}[$index]{main::key($num++,0,1,'Host')} = main::get_hostname();
}
+ my $dms = DmData::get();
+ my $dm_key = (!$dms->{'dm'} && $dms->{'lm'}) ? 'LM' : 'DM';
my $kernel_data = main::get_kernel_data();
$data->{$data_name}[$index]{main::key($num++,1,1,'Kernel')} = $kernel_data->[0];
$data->{$data_name}[$index]{main::key($num++,0,2,'arch')} = $kernel_data->[1];
$data->{$data_name}[$index]{main::key($num++,0,2,'bits')} = main::get_kernel_bits();
if ($extra > 0){
- my $compiler = CompilerVersion::get(); # get compiler data
+ my $compiler = KernelCompiler::get(); # get compiler data
if (scalar @$compiler != 2){
@$compiler = ('N/A', '');
}
@@ -33212,8 +38166,15 @@ sub system_item {
$data->{$data_name}[$index]{main::key($num++,0,3,'v')} = $compiler->[1];
}
}
+ if ($extra > 2){
+ main::get_kernel_clocksource(\$cs_curr,\$cs_avail);
+ $cs_curr ||= 'N/A';
+ $data->{$data_name}[$index]{main::key($num++,1,2,'clocksource')} = $cs_curr;
+ if ($b_admin && $cs_avail){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'avail')} = $cs_avail;
+ }
+ }
if ($b_admin && (my $params = KernelParameters::get())){
- # $index = scalar(@{$data{$data_name}}); # not on own line for now
# print "$params\n";
if ($use{'filter-label'}){
$params = main::filter_partition('system', $params, 'label');
@@ -33222,20 +38183,26 @@ sub system_item {
$params = main::filter_partition('system', $params, 'uuid');
}
$data->{$data_name}[$index]{main::key($num++,0,2,'parameters')} = $params;
- $index = scalar(@{$data->{$data_name}});
+
}
+ $index++;
# note: tty can have the value of 0 but the two tools
# return '' if undefined, so we test for explicit ''
if ($b_display){
- my $desktop_data = DesktopEnvironment::get();
+ my $desktop_data = DesktopData::get();
$desktop = $desktop_data->[0] if $desktop_data->[0];
- $desktop_version = $desktop_data->[1] if $desktop_data->[1];
- if ($extra > 0 && $desktop_data->[3]){
- $toolkit = $desktop_data->[2];
- $tk_version = $desktop_data->[3];
- }
- if ($extra > 2 && $desktop_data->[4]){
- $desktop_info = $desktop_data->[4];
+ if ($desktop){
+ $de_version = ($desktop_data->[1]) ? $desktop_data->[1] : 'N/A';
+ if ($extra > 0 && $desktop_data->[2]){
+ $toolkit = $desktop_data->[2];
+ if ($desktop_data->[1] || $desktop_data->[3]){
+ $tk_version = ($desktop_data->[3]) ? $desktop_data->[3] : 'N/A';
+ }
+ }
+ if ($b_admin && $desktop_data->[9] && $desktop_data->[10]){
+ $de_info = $desktop_data->[9];
+ $de_info_v = $desktop_data->[10];
+ }
}
# don't print the desktop if it's a wm and the same
if ($extra > 1 && $desktop_data->[5] &&
@@ -33244,12 +38211,21 @@ sub system_item {
$wm = $desktop_data->[5];
$wm_version = $desktop_data->[6] if $extra > 2 && $desktop_data->[6];
}
+ if ($extra > 2 && $desktop_data->[4]){
+ $de_components = $desktop_data->[4];
+ }
+ if ($extra > 2 && $desktop_data->[7]){
+ $tools_running = $desktop_data->[7];
+ }
+ if ($b_admin && $desktop_data->[8]){
+ $tools_avail = $desktop_data->[8];
+ }
}
if (!$b_display || (!$desktop && $b_root)){
ShellData::tty_number() if !$loaded{'tty-number'};
my $tty = $client{'tty-number'};
if (!$desktop){
- $desktop_info = '';
+ $de_components = '';
}
# it is defined, as ''
if ($tty eq '' && $client{'console-irc'}){
@@ -33267,43 +38243,60 @@ sub system_item {
$desktop = "$tty_type$tty";
}
$desktop_key = 'Console';
- $dm_key = 'DM';
$ind_dm = 1;
$cont_desk = 0;
}
+ else {
+ $dm_key = lc($dm_key);
+ }
$desktop ||= 'N/A';
$data->{$data_name}[$index]{main::key($num++,$cont_desk,1,$desktop_key)} = $desktop;
- if ($desktop_version){
- $data->{$data_name}[$index]{main::key($num++,0,2,'v')} = $desktop_version;
- }
- if ($toolkit){
- $data->{$data_name}[$index]{main::key($num++,1,2,'tk')} = $toolkit;
- }
- if ($tk_version){
- $data->{$data_name}[$index]{main::key($num++,0,3,'v')} = $tk_version;
- }
- if ($extra > 2){
- if ($desktop_info){
- $data->{$data_name}[$index]{main::key($num++,0,2,'info')} = $desktop_info;
+ if ($b_display){
+ if ( $de_version){
+ $data->{$data_name}[$index]{main::key($num++,0,2,'v')} = $de_version;
}
- }
- if ($extra > 1){
- if ($wm){
- $data->{$data_name}[$index]{main::key($num++,1,2,'wm')} = $wm;
- if ($wm_version){
- $data->{$data_name}[$index]{main::key($num++,0,3,'v')} = $wm_version;
+ if ($toolkit){
+ $data->{$data_name}[$index]{main::key($num++,1,2,'tk')} = $toolkit;
+ if ($tk_version){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'v')} = $tk_version;
}
}
- if ($extra > 2 && $b_display && defined $ENV{'XDG_VTNR'}){
- $data->{$data_name}[$index]{main::key($num++,0,2,'vt')} = $ENV{'XDG_VTNR'};
+ if ($de_info){
+ $data->{$data_name}[$index]{main::key($num++,1,2,'info')} = $de_info;
+ $data->{$data_name}[$index]{main::key($num++,0,3,'v')} = $de_info_v;
}
- my $dms = main::get_display_manager();
+ if ($extra > 1){
+ if ($wm){
+ $data->{$data_name}[$index]{main::key($num++,1,2,'wm')} = $wm;
+ if ($wm_version){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'v')} = $wm_version;
+ }
+ }
+ if ($extra > 2){
+ if ($de_components){
+ $data->{$data_name}[$index]{main::key($num++,0,2,'with')} = $de_components;
+ }
+ if ($tools_running || $tools_avail){
+ $tools_running ||= '';
+ $data->{$data_name}[$index]{main::key($num++,1,2,'tools')} = $tools_running;
+ if ($tools_avail){
+ $data->{$data_name}[$index]{main::key($num++,0,3,'avail')} = $tools_avail;
+ }
+ }
+ if (defined $ENV{'XDG_VTNR'}){
+ $data->{$data_name}[$index]{main::key($num++,0,2,'vt')} = $ENV{'XDG_VTNR'};
+ }
+ }
+ }
+ }
+ if ($extra > 1){
# note: version only present if proper extra level so no need to test again
- if (@$dms || $desktop_key ne 'Console'){
- if (@$dms && scalar @$dms > 1){
+ if (%$dms || $desktop_key ne 'Console'){
+ my $type = (!$dms->{'dm'} && $dms->{'lm'}) ? $dms->{'lm'}: $dms->{'dm'};
+ if ($type && @$type && scalar @$type > 1){
my $i = 0;
$data->{$data_name}[$index]{main::key($num++,1,$ind_dm,$dm_key)} = '';
- foreach my $dm_data (@{$dms}){
+ foreach my $dm_data (@{$type}){
$i++;
$data->{$data_name}[$index]{main::key($num++,1,($ind_dm + 1),$i)} = $dm_data->[0];
if ($dm_data->[1]){
@@ -33315,13 +38308,12 @@ sub system_item {
}
}
else {
- my $dm = ($dms && $dms->[0][0]) ? $dms->[0][0] : 'N/A';
+ my $dm = ($type && $type->[0][0]) ? $type->[0][0] : 'N/A';
$data->{$data_name}[$index]{main::key($num++,1,$ind_dm,$dm_key)} = $dm;
- if ($dms && $dms->[0][1]){
- $data->{$data_name}[$index]{main::key($num++,0,($ind_dm + 1),'v')} = $dms->[0][1];
+ if ($type && @{$type} && $type->[0][1]){
+ $data->{$data_name}[$index]{main::key($num++,0,($ind_dm + 1),'v')} = $type->[0][1];
}
}
-
}
}
# if ($extra > 2 && $desktop_key ne 'Console'){
@@ -33329,16 +38321,16 @@ sub system_item {
# $data->{$data_name}[$index]{main::key($num++,0,1,'vc')} = $tty if $tty ne '';
# }
my $distro_key = ($bsd_type) ? 'OS': 'Distro';
- my @distro_data = DistroData::get();
- my $distro = $distro_data[0];
- $distro ||= 'N/A';
- $data->{$data_name}[$index]{main::key($num++,1,1,$distro_key)} = $distro;
- if ($extra > 0 && $distro_data[1]){
- $data->{$data_name}[$index]{main::key($num++,0,2,'base')} = $distro_data[1];
+ my $distro = DistroData::get();
+ $distro->{'name'} ||= 'N/A';
+ $data->{$data_name}[$index]{main::key($num++,1,1,$distro_key)} = $distro->{'name'};
+ if ($extra > 0 && $distro->{'base'}){
+ $data->{$data_name}[$index]{main::key($num++,0,2,'base')} = $distro->{'base'};
}
eval $end if $b_log;
return $data;
}
+
## Item Processors ##
sub assign_data {
return if !$_[0] || ref $_[0] ne 'HASH';
@@ -33349,6 +38341,7 @@ sub assign_data {
push(@$items,$_[0]);
}
}
+
sub item_handler {
eval $start if $b_log;
my ($key,$item,$arg) = @_;
@@ -33359,6 +38352,7 @@ sub item_handler {
return {main::key($prefix++,1,0,$key) => $rows};
}
}
+
sub set_subs {
$subs = {
'audio' => \&AudioItem::get,
diff --git a/inxi.1 b/inxi.1
index f0ded7a..d515dbb 100644
--- a/inxi.1
+++ b/inxi.1
@@ -1,5 +1,5 @@
.\" inxi.1 - manpage for inxi system information tool
-.\" Copyright (C) 2022 Harald Hope
+.\" Copyright (C) 2024 Harald Hope
.\"
.\" This program is free software; you can redistribute it and/or modify
.\" it under the terms of the GNU General Public License as published by
@@ -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 "2022\-10\-31" "inxi" "inxi manual"
+.TH INXI 1 "2024\-02-06"inxi" "inxi manual"
.SH NAME
inxi \- Command line system information script for console and IRC
@@ -23,17 +23,17 @@ inxi \- Command line system information script for console and IRC
.SH SYNOPSIS
\fBinxi\fR
-\fBinxi\fR [\fB\-AbBCdDEfFGhiIjJlLmMnNopPrRsSuUVwyYzZ\fR]
+\fBinxi\fR [\fB\-AbBCdDEfFGhiIjJlLmMnNopPrRsSuUwyYzZ\fR]
\fBinxi\fR [\fB\-c -NUMBER\fR]
[\fB\-\-sensors\-exclude SENSORS\fR] [\fB\-\-sensors\-use SENSORS\fR]
[\fB\-t\fR [\fBc\fR|\fBm\fR|\fBcm\fR|\fBmc\fR][\fBNUMBER\fR]]
-[\fB\-v NUMBER\fR] [\fB\-W LOCATION\fR]
+[\fB\-v NUMBER\fR] [\fB\-w [LOCATION]\fR]
[\fB\-\-weather\-unit\fR {\fBm\fR|\fBi\fR|\fBmi\fR|\fBim\fR}] [\fB\-y WIDTH\fR]
\fBinxi\fR [\fB\-\-edid\fR] [\fB\-\-memory\-modules\fR]
[\fB\-\-memory\-short\fR] [\fB\-\-recommends\fR] [\fB\-\-sensors\-default\fR]
-[\fB\-\-slots\fR]
+[\fB\-\-slots\fR] [\fB\-\-version\fR] [\fB\-\-version\-short\fR]
\fBinxi\fB [\fB\-x\fR|\fB\-xx\fR|\fB\-xxx\fR|\fB\-a\fR] \fB\-OPTION(s)\fR
@@ -43,9 +43,9 @@ advanced options.
.SH DESCRIPTION
\fBinxi\fR is a command line system information script built for console and
IRC. It is also used a debugging tool for forum technical support to quickly
-ascertain users' system configurations and hardware. inxi shows system
-hardware, CPU, drivers, Xorg, Desktop, Kernel, gcc version(s), Processes, RAM
-usage, and a wide variety of other useful information.
+ascertain users' system configurations and hardware. inxi shows system hardware,
+CPU, drivers, Xorg, Desktop, Kernel, compiler version(s), Processes, RAM usage,
+and a wide variety of other useful information.
\fBinxi\fR output varies depending on whether it is being used on CLI or IRC,
with some default filters and color options applied only for IRC use.
@@ -128,8 +128,26 @@ keep things simple.
.TP
.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.
+Show Audio/sound device(s) information, including device driver. Shows active
+sound API(s) and sound server(s).
+
+Supported APIs: ALSA, OSS, sndio. Supported servers: aRts (artsd), Enlightened
+Sound Daemon (esound, esd), JACK, NAS (Network Audio System, nasd), PipeWire,
+PulseAudio, RoarAudio, sndiod.
+
+Use \fB\-Ax\fR to show all sound APIs/servers detected, including inactive,
+\fB\-Axx\fR to see API/Server helper daemons/plugin/modules, and \fB\-Aa\fR to
+see API/sound server tools.
+
+.nf
+\fBAudio:
+ Device\-1: C-Media CMI8788 [Oxygen HD Audio] driver: snd_virtuoso
+ Device\-2: AMD Cedar HDMI Audio [Radeon HD 5400/6300/7300 Series]
+ driver: snd_hda_intel
+ Device\-3: AMD Family 17h HD Audio driver: snd_hda_intel
+ API: ALSA v: k5.19.0\-16.2\-liquorix\-amd64 status: kernel\-api
+ Server\-1: PulseAudio v: 16.1 status: active\fR
+.fi
.TP
.B \-b \fR, \fB\-\-basic\fR
@@ -178,6 +196,10 @@ See \fB\-E\fR.
See \fBOUTPUT CONTROL OPTIONS\fR.
.TP
+.B \-\-config\fR, \fB\-\-configuration\fR
+Show active configuration values, by file, and exit.
+
+.TP
.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),
@@ -221,7 +243,7 @@ Sample:
.TP
.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,
+Show optical drive data as well as \fB\-D\fR HDD/SSD 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
that we are aware of, so it will simply show the floppy ID without any extra
@@ -229,9 +251,9 @@ data. \fB\-xx\fR adds a few more features.
.TP
.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
+Show HDD/SSD drive info. Shows total drive space and used percentage. The drive
+used percentage includes space used by swap partition(s), since those are not
+usable for data storage. Also, unmounted partitions are not counted in drive use
percentages since inxi has no access to the used amount.
If the system has RAID or other logical storage, and if inxi can determine
@@ -248,17 +270,17 @@ Without logical storage detected:
\fBLocal Storage: total: 2.89 TiB used: 1.51 TiB (52.3%)\fR
-Also shows per disk information: Disk ID, type (if present), vendor (if
-detected), model, and size. See \fBExtra Data Options\fR (\fB\-x\fR options)
-and \fBAdmin Extra Data Options\fR (\fB\-\-admin\fR options) for many more
-features.
+Also shows per drive information: Disk ID, type (FireWire, Removable, USB if
+present), vendor (if detected), model, and size. See \fBExtra Data Options\fR
+(\fB\-x\fR options) and \fBAdmin Extra Data Options\fR (\fB\-\-admin\fR options)
+for many more features.
.TP
.B \-E\fR, \fB\-\-bluetooth\fR
Show bluetooth device(s), drivers. Show \fBReport:\fR with HCI ID, state,
-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.
+address per device (requires \fBbtmgmt\fR, \fBbt\-adapter\fR, or
+\fBhciconfig\fR), and if available (hciconfig, btmgmt 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
and rfkill\fR software and hardware blocked states, and rfkill ID.
@@ -305,14 +327,9 @@ in order to avoid spamming. ARM CPUs: show \fBfeatures\fR items.
.TP
.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 \-t \-u
-\-x\fR unless you use those arguments in the command, e.g.:
-\fBinxi \-Frmxx\fR
-
-.TP
-.B \-\-gpu\fR
-Deprecated. See \fB\-G \-a\fR.
+\fB\-J\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 \-t \-u \-x\fR
+unless you use those arguments in the command, e.g.: \fBinxi \-Frmxx\fR
.TP
.B \-G \fR, \fB\-\-graphics\fR
@@ -324,7 +341,7 @@ and active \fBgpu:\fR drivers), display protocol (if available), display server
\fBDisplay: x11 server: Xorg v: 1.15.1\fR
-or
+or:
\fBDisplay: wayland server: X.org v: 1.20.1 with: Xwayland v: 20.1\fR
@@ -332,10 +349,14 @@ If protocol is not detected, shows:
\fBDisplay: server: Xorg 1.15.1\fR
-Also shows screen resolution(s) (per monitor/X screen). Shows graphics API used,
-like OpenGL. For X.org: OpenGL renderer, OpenGL core profile version/OpenGL
-version; for VESA: data (for Xvesa); for Wayland: GBM/EGL data (not
-implemented).
+Adds \fBwith: Xwayland v:...\fR if xwayland server is installed, regardless of
+protocol.
+
+Also shows screen resolution(s) (per monitor/X screen). Shows graphics API
+information (if available). EGL: EGL version, drivers, acdtive platforms;
+OpenGL: renderer, OpenGL core profile version/OpenGL version (if core/compat
+versions different, shows that as well); Vulkan: Vulkan version, drivers,
+surfaces;VESA: data (for Xvesa).
Compositor information will show if detected using \fB\-xx\fR option or always
if detected and Wayland since the compositor is the server with Wayland.
@@ -347,7 +368,7 @@ advanced monitor data (full modes, chroma, etc.).
.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 <width>\fR to temporarily override the defaults or actual window width.
+\fB\-y [width]\fR to temporarily override the defaults or actual window width.
.TP
.B \-i \fR, \fB\-\-ip\fR
@@ -357,17 +378,20 @@ Show WAN IP address and local interfaces (latter requires \fBifconfig\fR or
Shows both IPv4 and IPv6 link IP addresses.
.TP
+.B \-\-ip\-limit\fR, \fB\-\-limit [\-1 \- x]\fR
+Raise or lower max output limit of IP addresses for \fB\-i\fR. \fB\-1\fR
+removes limit.
+
+.TP
.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/target, packages).
-Note: if \fB\-m\fR is used or triggered, the memory item will show in the main
-Memory: report of \fB\-m\fR, not in \fB\Info:\fR.
+Note: if \fB\-m\fR or \fB\-tm\fR are active, the memory item will show in the
+main Memory: report of \fB\-m\fR/\fB\-tm\fR/, not in \fB\Info:\fR.
-Raspberry Pi only: uses \fBvcgencmd get_mem gpu\fR to get gpu RAM amount, if
-user is in video group and \fBvcgencmd\fR is installed. Uses this result to
-increase the \fBMemory:\fR amount and \fBused:\fR amounts.
+See \fB\-m\fR for explanation of \fBMemory:\fR fields and values..
.TP
.B \-j\fR, \fB\-\-swap\fR
@@ -394,12 +418,15 @@ generally shows BusID / DeviceID (except for tree view, which shows ports).
Examples: \fBDevice\-3: 4\-3.2.1:2\fR or \fBHub: 4\-0:1\fR
The \fBrev: 2.0\fR item refers to the USB revision number, like \fB1.0\fR or
-\fB3.1\fR.
+\fB3.1\fR.
+
+Use \fB\-Jx\fR for basic Si base 10 bits/s speed, \fB\-Jxx\fR for Si and IEC
+base 2 Bytes/s speeds. \fB\-Ja\fR adds USB mode.
.TP
.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.
+to show partition labels. Requires one of those options.
Sample: \fB\-ojpl\fR.
@@ -484,16 +511,30 @@ Physical memory array data shows array capacity, number of devices supported,
and Error Correction information. Devices shows locator data (highly variable in
syntax), type (eg: \fBtype: DDR3\fR)size, speed.
-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: \fBinxi \-m\fR uses either \fBdboot\fR (BSDs), \fBdmidecode\fR, or
+\fBudevadm\fR (Linux) to collect the RAM data. Not all boards have DMI RAM data
+available.
+
+\fBdmidecode\fR 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.
+
+\fBudevadm\fR can be run by non\-superuser, or if dmidecode is not installed
+(Linux only). It has a slightly less reliable dmi table outut, and does not seem
+to support more than 1 board memory array, but is pretty good. Voltages may be
+wrong however.
+
+Both \fBdmidecode\fR and \fBudevadm\fR need a DMI table with RAM data to create
+the report. Most SBC/SOC boards don't have dmi based RAM data. But most other
+machines do.
+
+\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
+Note: If \fB\-m\fR is triggered RAM available/used report will appear in this
section, not in \fB\-I\fR or \fB\-tm\fR items.
-Because \fBdmidecode\fR data is extremely unreliable, inxi will try to make
+Because \fBdmi\fR source data is somewhat unreliable, inxi will try to make
best guesses. If you see \fB(check)\fR after the capacity number, you should
check it with the specifications. \fB(est)\fR is slightly more reliable, but
you should still check the real specifications before buying RAM. Unfortunately
@@ -501,16 +542,16 @@ there is nothing \fBinxi\fR can do to get truly reliable data about the system
RAM; maybe one day the kernel devs will put this data into \fB/sys\fR, and make
it real data, taken from the actual system, not dmi data. For most people, the
data will be right, but a significant percentage of users will have either a
-wrong max module size, if present, or max capacity.
+wrong max module size, if available, or max capacity.
-Under dmidecode, \fBSpeed:\fR is the expected speed of the memory
-(what is advertised on the memory spec sheet) and \fBConfigured Clock Speed:\fR
-is what the actual speed is now. To handle this, if speed and configured speed
+Under dmidecode/udevadm, \fBspeed:\fR is the expected speed of the memory
+(\fBspec:\fR, what is advertised on the memory spec sheet) and \fBactual:\fR,
+what the actual speed is now. To handle this, if speed and configured speed
values are different, you will see this instead:
-\fBspeed: spec: [specified speed] MT/S actual: [actual] MT/S\fR
+\fBspeed: spec: [specified speed] MT/s actual: [actual] MT/s\fR
-Also, if DDR, and speed in MHz, will change to: \fBspeed: [speed] MT/S
+Also, if DDR, and speed in MHz, will change to: \fBspeed: [speed] MT/s
([speed] MHz)\fR
If the detected speed is logically absurd, like 1 MT/s or 69910 MT/s, adds:
@@ -518,7 +559,8 @@ If the detected speed is logically absurd, like 1 MT/s or 69910 MT/s, adds:
.nf
\fBMemory:
- RAM: total: 31.38 GiB used: 20.65 GiB (65.8%)
+ System RAM: total: 32 GiB note: est. available: 31.38 GiB
+ used: 20.65 GiB (65.8%)
Array\-1: capacity: N/A slots: 4 note: check EC: N/A
Device\-1: DIMM_A1 type: DDR3 size: 8 GiB speed: 1600 MT/s (800 MHz)
Device\-2: DIMM_A2 type: DDR3 size: 8 GiB speed: spec: 1600 MT/s (800 MHz)
@@ -531,6 +573,50 @@ If the detected speed is logically absurd, like 1 MT/s or 69910 MT/s, adds:
See \fB\-\-memory\-modules\fR and \fB\-\-memory\-short\fR if you want a
shorter report.
+Notes on \fBSystem RAM:\fR / \fBMemory:\fR report item:
+
+* \fBtotal:\fR and \fBigpu:\fR do not show for short form.
+
+* The \fBtotal:\fR can come from several possible sources:
+
+\- If not superuser, and if \fI/sys/devices/system/memory\fR exists, it will
+estimate the total RAM based on how many RAM blocks and their size. Sometimes
+the block count is not an exact match to installed RAM, and inxi will attempt to
+guess the actual RAM amount, except for virtual machines. When it synthesizes
+the actual physical RAM total, it will show \fBnote: est.\fR.
+
+Note that not all kernels are compiled to support generating this /sys
+directory (kernel needs to be compiled with \fBCONFIG_MEMORY_HOTPLUG\fR).
+
+\- For OpenBSD and not superuser, the total comes from the detected RAM in
+dboot, if available.
+
+\- If superuser, and if \fB\-m\fR used, it comes from the dmidecode RAM totals
+if available, and if not, it comes from counting up the System RAM ranges in
+\fI/proc/iomem\fR (Linux only), then rounding up, since that total is usually
+slightly under the actual physical RAM total. If inxi is unsure about the total,
+it will show \fBnote: est.\fB.
+
+If no total data found, shows \fBtotal: N/A\fB.
+
+* The \fBavailable:\fR item is the total installed RAM minus some reserved and
+kernel code RAM (and in some cases iGPU assigned main system RAM) that is
+allocated on system boot, and thus is generally less than the actual physical
+RAM installed. This is called MemTotal in free/meminfo even though it isn't,
+though it is the total available the kernel has to work with.
+
+* The \fBused:\fR is the percent of the available RAM used, NOT of the total
+physical RAM.
+
+* The \fBigpu:\fR item either comes from Raspberry Pi gpu RAM, or from
+\fI/proc/iomem\fR. The latter source is Linux + superuser only, and is not
+guaranteed to be accurate, but sometimes is. That is for iGPU system RAM used,
+not for standalone GPUs with their own internal RAM. Not all types of internal
+VRAM are detectable, it depends on how the hardware assigns RAM to iGPU.
+
+Raspberry Pi uses \fBvcgencmd get_mem gpu\fR to get gpu RAM amount, if
+user is in video group and \fBvcgencmd\fR is installed.
+
.TP
.B \-\-memory\-modules\fR, \fB\-\-mm\fR
Memory (RAM) data. Show only RAM arrays and modules in Memory report.
@@ -573,11 +659,6 @@ Show Advanced Network device information in addition to that produced by
.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 \-\-nvidia\fR, \fB\-\-nv\fR
-.br
-Deprecated. See \fB\-Ga\fR.
.TP
.B \-o \fR, \fB\-\-unmounted\fR
@@ -605,6 +686,31 @@ To show partition labels or UUIDs (when available and relevant), use with
\fB\-l\fR or\fB \-u\fR.
.TP
+.B \-\-partitions\-sort\fR, \fB\-\-ps\fR \
+[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 \-P \fR, \fB\-\-partitions\fR
Show basic Partition information.
Shows, if detected: \fB/ /boot /boot/efi /home /opt /tmp /usr /usr/home /var
@@ -626,13 +732,15 @@ Show distro repository data. Currently supported repo types:
\fBAPK\fR (Alpine Linux + derived versions)
-\fBAPT\fR (Debian, Ubuntu + derived versions, as well as RPM based
-APT distros like PCLinuxOS or Alt\-Linux)
+\fBAPT\fR (Debian, Ubuntu + derived versions, as well as rpm based
+apt distros like PCLinuxOS or Alt\-Linux)
\fBCARDS\fR (NuTyX + derived versions)
\fBEOPKG\fR (Solus)
+\fBNETPKG\fR (Zenwalk/Slackware)
+
\fBNIX\fR (NixOS + other distros as alternate package manager)
\fBPACMAN\fR (Arch Linux, KaOS + derived versions)
@@ -647,12 +755,22 @@ APT distros like PCLinuxOS or Alt\-Linux)
\fBPORTS\fR (OpenBSD, FreeBSD, NetBSD + derived OS types)
+\fBSBOPKG\fR (Slackware + derived versions)
+
+\fBSBOUI\fR (Slackware + derived versions)
+
\fBSCRATCHPKG\fR (Venom + derived versions)
\fBSLACKPKG\fR (Slackware + derived versions)
+\fBSLAPT_GET\fR (Slackware + derived versions)
+
+\fBSLPKG\fR (Slackware + derived versions)
+
\fBTCE\fR (TinyCore)
+\fBTAZPKG\fR (Slitaz)
+
\fBURPMI\fR (Mandriva, Mageia + derived versions)
\fBXBPS\fR (Void)
@@ -739,6 +857,8 @@ Make sure that there is no space between letters and numbers (e.g. write as
If the \fB\-I\fR or \fB\-m\fR lines are not triggered, will also show the
system RAM used/total information.
+See \fB\-m\fR for explanation of \fBSystem RAM:\fR fields and values.
+
.TP
.B \-t cm\fR
\- CPU+memory. With \fB\-x\fR, shows also CPU or memory for that process on
@@ -746,8 +866,8 @@ same line.
.TP
.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.
+Show UUIDs. Use with \fB\-j\fR, \fB\-M\fR \fB\-o\fR, \fB\-p\fR, and \fB\-P\fR to
+show partition/system board (not common) UUIDs. Requires one of those options.
Sample: \fB\-opju\fR.
@@ -757,30 +877,42 @@ Note \- Maintainer may have disabled this function.
If inxi \fB\-h\fR has no listing for \fB\-U\fR then it's disabled.
-Auto\-update script. Note: if you installed as root, you must be root to
-update, otherwise user is fine. Also installs / updates this man page to:
+Auto\-update inxi or pinxi. Note: if you installed as root, you must be root to
+update, otherwise user is fine. Also installs / updates current man page to:
\fB/usr/local/share/man/man1\fR (if \fB/usr/local/share/man/\fR exists
AND there is no inxi man page in \fB/usr/share/man/man1\fR, otherwise it
goes to \fB/usr/share/man/man1\fR). This requires that you be root to write
to that directory. See \fB\-\-man\fR or \fB\-\-no\-man\fR to force or disable
man install.
+\fB\-U\fR accepts the following options (inxi and pinxi):
+
+No arg \- Get from main git branch.
+
+3 \- Get the dev server (smxi.org) version. Be aware that pinxi when taken from
+here can be very unstable during active development! The inxi version is the
+stable master branch version. Also useful to update if you have SSL issues and
+\fB\-\-no\-ssl\fR works.
+
+4 \- Get the dev server (smxi.org) FTP version (same as 3 version). Use if SSL
+issues and \fB\-\-no\-ssl\fR doesn't work. For very old systems with SSL 1, you
+will probably need to use this option, which bypasses HTTP downloading, and uses
+straight FTP to get the file from smxi.org server.
+
+[http|https|ftp] \- Get a version of $self_name from your own server. Use the
+full download path, e.g.
+
+\fB\inxi -U https://myserver.com/inxi\fR
+
+For failed downloads, use the debug option \fB\-\-dbg 1\fR in addition to get
+more verbose failure reports.
+
.TP
.B \-\-usb\fR
.br
See \fB\-J\fR.
.TP
-.B \-V\fR, \fB\-\-version\fR
-inxi full version and license information. Prints information then exits.
-
-.TP
-.B \-\-version\-short\fR, \fB\-\-vs\fR
-inxi single line version information. Prints information if not short form
-(which shows version info already). Does not exit unless used without any other
-options. Can be used with normal line options.
-
-.TP
.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.
@@ -809,7 +941,7 @@ min/max 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)
+/boot\fR. Shows full drive data (\fB\-D\fR)
.TP
.B \-v 5
@@ -838,49 +970,53 @@ of optical drives.
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 \-\-version\fR, \fB\-\-vf\fR
+inxi full version and license information. Prints information then exits.
+.TP
+.B \-\-version\-short\fR, \fB\-\-vs\fR
+inxi single line version information. Prints information if not short form
+(which shows version info already). Does not exit unless used without any other
+options. Can be used with normal line options, and prints version info line as
+first line of output.
+
+.TP
+.B \-w \fR, \fB\-\-weather [location]\fR
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
meant for widget type weather monitoring, or Conky type use. It is meant to get
weather when you need to see it, for example, on a remote server. If you did not
type the weather option in manually, it's an automated request.
-.TP
-.B \-W\fR, \fB\-\-weather\-location <location_string>\fR
-Get weather/time for an alternate location. Accepts postal/zip code[, country],
-city,state pair, or latitude,longitude. Note: city/country/state names must
-not contain spaces. Replace spaces with '\fB+\fR' sign. Don't place spaces
-around any commas. Postal code is not reliable except for North America and
-maybe the UK. Try postal codes with and without country code added. Note that
-City,State applies only to USA, otherwise it's City,Country. If country name
-(english) does not work, try 2 character country code (e.g. Spain: es;
-Great Britain: gb).
+Adds weather line for your current location (by IP address) if no location
+requested. To get weather for an alternate location, add \fB[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.
+
+With optional \fB[location]\fR \- get weather/time for an alternate location.
+Accepts postal/zip code[, country], city,state pair, or latitude,longitude.
+Note: city/country/state names must not contain spaces. Replace spaces with
+the '\fB+\fR' sign. Don't place spaces around any commas. Postal code is not
+reliable except for North America and maybe the UK. Try postal codes with and
+without country code added. Note that City,State applies only to USA, otherwise
+it's City,Country. If country name (english) does not work, try 2 character
+country code (e.g. Spain: es; Great Britain: gb).
See \fIhttps://en.wikipedia.org/wiki/ISO_3166\-1_alpha\-2\fR for current 2
letter country codes.
Use only ASCII letters in city/state/country names.
-Examples: \fB\-W 95623,us\fR OR \fB\-W Boston,MA\fR OR
-\fB\-W 45.5234,\-122.6762\fR OR \fB\-W new+york,ny\fR OR \fB\-W bodo,norway\fR.
-
-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
-meant for widget type weather monitoring, or Conky type use. It is meant to get
-weather when you need to see it, for example, on a remote server. If you did not
-type the weather option in manually, it's an automated request.
+Examples: \fB\-w\fR OR \fB\-w 95623,us\fR OR \fB\-w Boston,MA\fR OR
+\fB\-w 45.5234,\-122.6762\fR OR \fB\-w new+york,ny\fR OR \fB\-w bodo,norway\fR.
.TP
-.B \-\-weather\-source\fR, \fB\-\-ws <unit>\fR
+.B \-\-weather\-source\fR, \fB\-\-ws [source-id]\fR
[\fB1\-9\fR] Switches weather data source. Possible values are \fB1\-9\fR.
\fB1\-4\fR will generally be active, and \fB5\-9\fR may or may not be active,
so check. \fB1\fR may not support city / country names with spaces (even if
you use the \fB+\fR sign instead of space). \fB2\fR offers pretty good data,
-but may not have all small city names for \fB\-W\fR.
+but may not have all small city names for \fB\-w location\fR.
Please note that the data sources are not static per value, and can change any
time, or be removed, so always test to verify which source is being used for
@@ -889,7 +1025,7 @@ on occasions, so try each one and see which you prefer. If you get unsupported
source message, it means that number has not been implemented.
.TP
-.B \-\-weather\-unit <unit>\fR
+.B \-\-weather\-unit\fR, \fB\-\-wu [unit]\fR
[\fBm\fR|\fBi\fR|\fBmi\fR|\fBim\fR] Sets weather units to metric (\fBm\fR),
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.
@@ -947,8 +1083,9 @@ 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.
+Filter partition UUIDs from \fB\-j\fR, \fB\-o\fR, \fB\-p\fR, \fB\-P\fR,
+\fB\-Sa\fR (root=UUID=...), \fB\-Mxxx\fR board UUID. Useful in specialized
+cases.
.TP
.B \-\-zv\fR, \fB\-\-filter\-v\fR, \fB\-\-filter\-vulnerabilities\fR
@@ -968,12 +1105,12 @@ The following options allow for modifying the output in various ways.
Set color scheme. If no scheme number is supplied, 0 is assumed.
.TP
-.B \-c \fR[\fB94\fR\-\fB99\fR]
+.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 <color number>\fR
+piped or redirected. You must use the explicit runtime \fB\-c [color number]\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
@@ -1007,6 +1144,11 @@ Konversation etc.
Setting a specific color type removes the global color selection.
.TP
+.B \-\-export [json|screen|xml]\fR
+.br
+See \fB\-\-output\fR.
+
+.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
@@ -1020,11 +1162,6 @@ level only applied if output width is less than max wrap width (see
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
@@ -1036,38 +1173,26 @@ 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
+.B \-\-output\fR, \fB \-\-export [json|screen|xml]\fR
Change data output type. Requires \-\-output\-file if not \fBscreen\fR.
+See this page \fIhttps://smxi.org/docs/inxi-json-xml-output.htm\fR BEFORE you
+post an issue about not understanding, or being unable to use, the output
+format! That gives a fairly complete explanation of what the output means, and
+how to work with it. It is not a tutorial, and it will not teach you to program,
+if you don't know how to work with json/xml structures using a proper language,
+then this feature is not meant for you.
+
.TP
-.B \-\-output\-file [full path to output file|print]\fR
+.B \-\-output\-file, \fB \-\-export\-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.
+.B \-\-separator\fR, \fB\-\-sep [character(s)]\fR
+Change the default output key: value separator \fB:\fR to something else. Make
+permanent with configuration item \fBSEP2_CONSOLE\fR.
.TP
.B \-\-wrap\-max [integer]\fR
@@ -1161,7 +1286,7 @@ vendor [product] information.
\- Adds PCI/USB ID of each device.
-\- Adds non-running sound servers, if detected.
+\- Adds inactive sound servers/APIs, if detected.
.TP
.B \-x \-B\fR
@@ -1245,7 +1370,7 @@ doas users: see \fBman doas.conf\fR for setup.
You can force use of \fBhddtemp\fR for all drives using \fB\-\-hddtemp\fR.
-\- If free LVM volume group size detected (root required), show \fBlvm-free:\fR
+\- If free LVM volume group size detected (root required), show \fBlvm\-free:\fR
on Local Storage line. This is how much unused space the VGs contain, that is,
space not assigned to LVs.
@@ -1258,9 +1383,9 @@ specific vendor [product] information.
\- Adds driver version (if available) for each device.
-\- Adds (if available, and \fBhciconfig\fR only) LMP (HCI if no LMP data,
-and HCI if HCI/LMP versions are different) version (if available)
-for each HCI ID.
+\- Adds (if available, \fBbtmgmt\fR, \fBhciconfig\fR only) LMP (HCI if no LMP
+data, and HCI if HCI/LMP versions are different) version (if available) for each
+HCI ID.
.TP
.B \-x \-G\fR
@@ -1271,13 +1396,17 @@ for each HCI ID.
\- Adds (if available and/or relevant) \fBvendor:\fR item, which shows
specific vendor [product] information.
-\- \fBX.org:\fR Adds direct rendering status.
-
\- \fBX.org:\fR Adds (for single GPU, nvidia driver) screen number that GPU is
running on.
\- Adds device temperature for each discrete device (Linux only).
+\- For EGL, adds active/inactive platform report.
+
+\- For OpenGL (\fBX.org\fR only) adds direct render status, GLX version.
+
+\- For Vulkan, adds device count.
+
.TP
.B \-x \-i\fR
\- Adds IP v6 additional scope data, like Global, Site, Temporary for
@@ -1308,8 +1437,8 @@ values, as with global temporary, and global temporary deprecated.
\- Adds current init system (and init rc in some cases, like OpenRC).
With \fB\-xx\fR, shows init/rc version number, if available.
-\- Adds default system gcc. With \fB\-xx\fR, also show other installed gcc
-versions.
+\- Adds default system compilers. With \fB\-xx\fR, also show other installed
+compiler versions.
\- Adds current runlevel/target (not available with all init systems).
@@ -1325,15 +1454,21 @@ discover those.
available.
.TP
-.B \-x \-j\fR, \fB\-x \-\-swap\fR
+.B \-x \-j\fR (\fB\-\-swap\fR)
Add \fBmapper:\fR. See \fB\-x \-o\fR.
.TP
.B \-x \-J\fR (\fB\-\-usb\fR)
\- For Devices, adds driver(s).
+\- Adds, if available, USB speed in base 10 bits/s (Si) units \fBMb/s\fR or
+\fBGb/s\fR (may be incorrect on BSDs due to non reliable data source). These are
+base 10 bits per second. This unit corresponds to the standard units the USB
+consortium uses to indicate speeds, but not to how most of the rest of your
+system reports sizes. Use \fB\-Jxx\fR to add base 2 IEC Byte/second speeds.
+
.TP
-.B \-x \-L\fR, \fB\-x \-\-logical\fR
+.B \-x \-L\fR (\fB\-\-logical\fR)
\- Adds \fBdm: dm-x\fR to VG > LV and other Device types. This can help
tracking down which device belongs to what.
@@ -1379,7 +1514,7 @@ bitmap (if present). Resync line, shows blocks synced/total blocks.
.TP
.B \-x \-S\fR
-\- Adds Kernel gcc version.
+\- Adds Kernel compiler version.
\- Adds to \fBDistro:\fR \fBbase:\fR if detected. System base will only be
seen on a subset of distributions. The distro must be both derived from a
@@ -1398,7 +1533,7 @@ found for each distribution system base detection.
(\fB\-xt m\fR).
.TP
-.B \-x \-w \fR, \fB\-W\fR
+.B \-x \-w\fR
\- Adds humidity and barometric pressure.
\- Adds wind speed and direction.
@@ -1409,15 +1544,22 @@ found for each distribution system base detection.
\- Adds PCIe speed and lanes item (Linux only, if detected).
+\- Adds for USB devices USB rev, speed, lanes (lanes Linux only).
+
+\- Adds \fBwith: [item] \fBstatus: [state/plugin]\fR helper daemons/plugins for
+the sound API/server.
+
.TP
.B \-xx \-B\fR
+\- Adds current power use, in watts.
+
\- Adds serial number.
.TP
.B \-xx \-D\fR
-\- Adds disk serial number.
+\- Adds HDD/SSD drive serial number.
-\- Adds disk speed (if available). This is the theoretical top speed of the
+\- Adds drive speed (if available). This is the theoretical top speed of the
device as reported. This speed may be restricted by system board limits,
eg. a SATA 3 drive on a SATA 2 board may report SATA 2 speeds, but this is
not completely consistent, sometimes a SATA 3 device on a SATA 2 board reports
@@ -1434,18 +1576,22 @@ For a PCIe 3 NVMe drive, with speed of \fB8 GT/s\fR and \fB4\fR lanes
\fBspeed: 31.6 Gb/s lanes: 4\fR
-\- Adds disk duid, if available. Some BSDs have it.
+\- Adds HDD/SSD drive duid, if available. Some BSDs have it.
+
+\- Adds for USB drives USB rev, speed, lanes (lanes Linux only).
.TP
.B \-xx \-E\fR (\fB\-\-bluetooth\fR)
\- Adds vendor:product ID of each device.
-\- Adds (\fBhciconfig \fRonly) LMP subversion (and/or HCI revision
-if applicable) for each device.
-
\- Adds PCIe speed and lanes item (Linux only, and if PCIe bluetooth, which is
rare).
+\- Adds for USB devices USB rev, speed, lanes (lanes Linux only).
+
+\- Adds (\fBhciconfig \fRonly) LMP subversion (and/or HCI revision if
+applicable) for each device.
+
.TP
.B \-xx \-G\fR
Triggers much more complete Screen/Monitor output.
@@ -1473,6 +1619,8 @@ or more \fBMonitors\fR.
\- Adds PCIe speed and lanes item (Linux only, and if PCIe device and detected).
+\- Adds for USB devices USB rev, speed, lanes (lanes Linux only).
+
\- Adds output port IDs, active, off (connected but disabled, like a closed
laptop lid) and empty. Example:
@@ -1534,17 +1682,27 @@ grid of monitors that the \fBXorg\fR \fBScreen\fR is composed of.
real monitor size, not the Xorg full Screen diagonal size, which can be quite
different.
-\- For free drivers, adds OpenGL compatibility version number if available. For
-nonfree drivers, the core version and compatibility versions are usually the
-same. Example:
+\- For EGL, shows platform by specific platforms, with driver and egl version if
+different from the main one.
+
+\- For OpenGL, adds ES version (\fBes\-v\fR) if available. If the Display line
+did not find an X11 display ID, the ID (e.g. \fB:0.0\fR) will show here instead.
+
+\- For OpenGL, Vulkan, adds \fBdevice-\ID\fR, if available.
-\fBv: 3.3 Mesa 11.2.0 compat\-v: 3.0\fR
+\- For Vulkan, adds per Device ID report (type, driver, device\-ID).
.TP
.B \-xx \-I\fR
+\- Addes \fBPower:\fR parent for power data children \fBuptime:\fR and adds
+\fBwakeups:\fR. Wakeups shows how many times the machine has been woken from
+suspend state during current uptime period (if available, Linux only). 0 value
+means the machine has not been suspended.
+
\- Adds init type version number (and rc if present).
-\- Adds other detected installed gcc versions (if present).
+\- Adds alternate (\fBalt:\fR) detected installed compiler versions (if
+present).
\- Adds system default runlevel/target, if detected. Supports Systemd / Upstart
/SysVinit type defaults.
@@ -1565,8 +1723,12 @@ swap types (for \fB\-j\fR).
.B \-xx \-J\fR (\fB\-\-usb\fR)
\- Adds vendor:chip id.
+\- Adds USB lanes. Uses tx (transmit) lane count for total unless rx and tx
+counts are different (eg: \fBlanes: rx: 2 tx: 4\fR). Linux only.
+See \fB\-Ja\fR for sample output.
+
.TP
-.B \-xx \-L\fR, \fB\-xx \-\-logical\fR
+.B \-xx \-L\fR (\fB\-\-logical\fR)
\- Adds internal LVM Logical volumes, like raid image and meta data volumes.
\- Adds full list of Components, sub\-components, and their physical devices.
@@ -1597,12 +1759,17 @@ this data available.
\- Adds chassis information, if data is available. Also shows BIOS
ROM size if using \fBdmidecode\fR.
+\- Adds board part number (\fBpart\-nu:\fR) if available. This is not commonly
+found.
+
.TP
.B \-xx \-N\fR
\- Adds vendor:product ID for each device.
\- Adds PCIe speed and lanes item (Linux only, and if PCIe device and detected).
+\- Adds for USB devices USB rev, speed, lanes (lanes Linux only).
+
.TP
.B \-xx \-r\fR
\- Adds to \fBPackages:\fR info. See \fB\-Ixx\fR
@@ -1620,17 +1787,19 @@ shows progress bar.
.TP
.B \-xx \-S\fR
-\- Adds display manager (\fBdm\fR) type, if present. If none, shows N/A.
-Supports most known display managers, including gdm, gdm3,
-idm, kdm, lightdm, lxdm, mdm, nodm, sddm, slim, tint, wdm, and xdm.
-\- Adds, if run in X, window manager type (\fBwm\fR), if available. Not all
-window managers are supported. Some desktops support using more than one
-window manager, so this can be useful to see what window manager is actually
-running. If none found, shows nothing. Uses a less accurate fallback tool
-\fBwmctrl\fR if \fBps\fR tests fail to find data.
+\- Adds desktop toolkit (\fBtk:\fR), if available (Xfce/KDE/Trinity/Gnome etc).
+
+\- Adds, if run in X, window manager (\fBwm:\fR), if available. Not all window
+managers are supported. File issue to request a missing one. Some desktops
+support using more than one window manager, so this can be useful to see what
+window manager is actually running. If none found, shows nothing. Uses a less
+accurate fallback tool \fBwmctrl\fR if \fBps\fR tests fail to find data.
-\- Adds desktop toolkit (\fBtk\fR), if available (Xfce/KDE/Trinity).
+\- Adds display/login manager (\fBdm:\fR/\fBlm:\fR), if present. If none, shows
+N/A. Supports most known display/login managers, including elogind, entrance,
+gdm, gdm3, greetd, kdm, lemurs, lightdm, lxdm, ly, mdm, mlogind, nodm, sddm,
+seatd, slim, slimski, tint, wdm, xdm, and several others, added as discovered.
.TP
.B \-xx \-\-slots\fR
@@ -1639,7 +1808,7 @@ running. If none found, shows nothing. Uses a less accurate fallback tool
\- Adds slot voltage, if available.
.TP
-.B \-xx \-w \fR, \fB\-W\fR
+.B \-xx \-w\fR
\- Adds wind chill, heat index, and dew point, if available.
\- Adds cloud cover, rain, snow, or precipitation (amount in previous hour
@@ -1677,22 +1846,24 @@ CPU does not support SMT.
.TP
.B \-xxx \-D\fR
-\- Adds disk firmware revision number (if available).
+\- Adds HDD/SSD drive firmware revision number (if available).
-\- Adds disk partition scheme (in most cases), e.g. \fBscheme: GPT\fR.
+\- Adds drive partition scheme (in most cases), e.g. \fBscheme: GPT\fR.
Currently not able to detect all schemes, but handles the most common, e.g.
\fBGPT\fR or \fBMBR\fR.
-\- Adds disk type (\fBHDD\fR/\fBSSD\fR), rotation speed (in some but not all
-cases), e.g. \fBtype: HDD rpm: 7200\fR, or \fBtype: SSD\fR if positive SSD
+\- Adds drive tech (\fBHDD\fR/\fBSSD\fR), rotation speed (in some but not all
+cases), e.g. \fBtech: HDD rpm: 7200\fR, or \fBtech: SSD\fR if positive SSD
identification was made. If no HDD, rotation, or positive SSD ID found, shows
-\fBtype: N/A\fR. Not all HDD spinning disks report their speed, so even if they
+\fBtech: N/A\fR. Not all HDD spinning disks report their speed, so even if they
are spinning, no rpm data will show.
.TP
.B \-xxx \-E\fR (\fB\-\-bluetooth\fR)
\- Adds, if present, PCI/USB class ID.
+\- Adds, if present, bluetooth device class ID.
+
\- Adds (\fBhciconfig \fRonly) HCI version, revision.
.TP
@@ -1720,11 +1891,18 @@ right.
\- \fBWayland:\fR Adds to Monitors \fBscale:\fR (if detected).
+\- For EGL, shows hardware based driver(s) (\fBhw:\fR), with the related
+hardware, like AMD or Intel.
+
+\- For Vulkan, adds layer count, per device driver hardware vendor (not
+displayed if device name is present with \fB\-a\fR).
+
.TP
.B \-xxx \-I\fR
-\- For \fBUptime:\fR adds \fBwakeups:\fR to show how many times the machine
-has been woken from suspend state during current uptime period (if available,
-Linux only). 0 value means the machine has not been suspended.
+\- For \fBPower:\fR adds supported system power \fBstates:\fR, active
+\fBsuspend:\fR type, active \fBhibernate:\fR type. See
+\fIhttps://www.kernel.org/doc/html/v4.15/admin-guide/pm/sleep-states.html\fR
+for full explanation of states and actions.
\- For \fBShell:\fR adds \fB(su|sudo|login)\fR to shell name if present.
@@ -1740,8 +1918,6 @@ uses the \fBwhoami\fR test.
\- Adds \fBinterfaces:\fR for non hub devices.
-\- Adds, if available, USB speed in \fBMbits/s\fR or \fBGbits/s\fR.
-
\- Adds, if present, USB class ID.
\- Adds, if non 0, max power in mA.
@@ -1768,6 +1944,11 @@ different from each other. If they are the identical, displays same as
\fB\-xxm\fR voltage report. Use \fB\-ma\fR to always see them.
.TP
+.B \-xxx \-M\fR
+\- Adds, if present, board/chassis UUID, This is also activated by
+\fB\-\-uuid\fR.
+
+.TP
.B \-xxx \-N\fR
\- Adds, if present, serial number.
@@ -1785,21 +1966,27 @@ RAID events)
.TP
.B \-xxx \-S\fR
-\- Adds, if in X, or with \fB--display\fR, bar/dock/panel/tray items
-(\fBinfo\fR). If none found, shows nothing. Supports desktop items like
-gnome\-panel, lxpanel, xfce4\-panel, lxqt\-panel, tint2, cairo-dock, trayer,
-and many others.
+\- Adds current kernel clock source, if available (Linux only).
\- Adds (if present), window manager (\fBwm\fR) version number.
-\- Adds (if present), display manager (\fBdm\fR) version number.
+\- Adds, if in X, or with \fB--display\fR, bar/dock/menu/panel/tray components
+(\fBwith:\fR). If none found, shows nothing. Examples: cairo-dock, docky,
+gnome\-panel, lxpanel, tint2, trayer, lxqt\-panel, xfce4\-panel and many
+others.
+
+\- Adds (if present) \fBtools:\fR item for all detected running screensavers,
+screen lockers. Note that not all screen lockers run as daemons/services, some
+are just programs called by other tools or actions.
\- Adds (if available, and in display), virtual terminal (\fBvt\fR) number.
These are the same as \fBctrl+alt+F[x]\fR numbers usually. Some systems
have this, some don't, it varies.
+\- Adds (if present), display/login manager (\fBdm\fR) version number.
+
.TP
-.B \-xxx \-w \fR, \fB\-W\fR
+.B \-xxx \-w \fR
\- Adds location (city state country), observation altitude (if available),
weather observation time (if available), sunset/sunrise (if available).
@@ -1823,6 +2010,11 @@ knows could possibly be used instead.
or lanes, \fBlink\-max: gen: speed: lanes:\fR (only items different from primary
shown).
+\- Adds list of detected audio server tools (\fBtools: [tools]\fR) to API/Server
+lines, like alsamixer, jack_control, pactl, pavuctl, pw-cli, sndioctl, etc.
+
+\- Adds for USB devices USB mode (Linux only).
+
.TP
.B \-a \-C\fR
.br
@@ -1995,8 +2187,11 @@ any further action.
\- Adds, for USB or other external drives, actual model name/serial if
available, and different from enclosure model/serial, and corrects block sizes
-if necessary. Adds in drive temperature for some drives as well, and other
-useful data.
+if necessary.
+
+\- Adds for USB drives USB mode (Linux only).
+
+\- Adds in drive temperature for some drives as well, and other useful data.
.TP
.B \-a \-E\fR (\fB\-\-bluetooth\fR)
@@ -2008,6 +2203,11 @@ and Service Classes.
or lanes, \fBlink\-max: gen: speed: lanes:\fR (only items different from primary
shown. Bluetooth PCIe rare).
+\- Adds for USB devices USB mode (Linux only).
+
+\- Adds, if present, bluetooth \fBstatus:\fR discoverable, active discoverable,
+and pairing items.
+
.TP
.B \-a \-G\fR
\- Adds, if present, possible \fBalternate:\fR kernel modules capable of driving
@@ -2030,6 +2230,8 @@ Includes extended non free Nvidia legacy informatin (Linux and Nvidia only), and
issues, shows extra data that can help diagnose/debug. Adds \fBcode:\fR item if
found and not the same as \fBarch:\fR.
+\- Adds for USB devices USB mode (Linux only).
+
.nf
\fBinxi \-Gaz
Graphics:
@@ -2076,36 +2278,50 @@ shown).
\- Adds to Monitors \fBbuilt:\fR, \fBgamma:\fR, \fBratio:\fR (if found).
+\- Adds to OpenGL device memory and unified status, if present.
+
+\- Adds to Vulkan full device report, with full device names, ids, drivers,
+driver versions, surfaces.
+
X.org sample (with both \fBxdpyinfo\fR and \fBxrandr\fR data available):
.nf
\fBinxi \-aGz
Graphics:
- Device\-1: AMD Cedar [Radeon HD 5000/6000/7350/8350 Series] vendor: XFX Pine
- driver: radeon v: kernel alternate: amdgpu arch: TeraScale\-2
- code: Evergreen process: TSMC 32\-40nm built: 2009\-15 pcie: gen: 1
- speed: 2.5 GT/s lanes: 16 link\-max: gen: 2 speed: 5 GT/s ports:
- active: DVI\-I\-1,VGA\-1 empty: HDMI\-A\-1 bus\-ID: 0a:00.0
- chip\-ID: 1002:68f9 class\-ID: 0300
- Display: x11 server: X.Org v: 1.21.1.3 with: Xwayland v: 22.1.0
- compositor: xfwm v: 4.16.1 driver: X: loaded: modesetting dri: r600
+ Device\-1: AMD Cedar [Radeon HD 5000/6000/7350/8350 Series]
+ vendor: XFX Pine driver: radeon v: kernel alternate: amdgpu
+ arch: TeraScale\-2 code: Evergreen process: TSMC 32\-40nm
+ built: 2009\-15 pcie: gen: 1 speed: 2.5 GT/s lanes: 16 link\-max:
+ gen: 2 speed: 5 GT/s ports: active: DVI\-I\-1,VGA\-1 empty: HDMI\-A\-1
+ bus\-ID: 0a:00.0 chip\-ID: 1002:68f9 class\-ID: 0300 temp: 58.0 C
+ Display: x11 server: X.Org v: 1.21.1.7 with: Xwayland v: 22.1.9
+ compositor: xfwm v: 4.18.0 driver: X: loaded: modesetting dri: r600
gpu: radeon display\-ID: :0.0 screens: 1
- Screen\-1: 0 s-res: 2560x1024 s-dpi: 96 s\-size: 677x270mm (26.65x10.63")
- s\-diag: 729mm (28.7")
+ Screen\-1: 0 s\-res: 2560x1024 s\-dpi: 96
+ s\-size: 677x270mm (26.65x10.63") s\-diag: 729mm (28.7")
Monitor\-1: DVI\-I\-1 pos: primary,left model: Samsung SyncMaster
- serial: <filter> built: 2004 res: 1280x1024 hz: 60 dpi: 96 gamma: 1.2
- size: 338x270mm (13.31x10.63") diag: 433mm (17") ratio: 5:4 modes:
- max: 1280x1024 min: 720x400
- Monitor\-2: VGA\-1 pos: right model: Dell 1908FP serial: <filter>
- built: 2008 res: 1280x1024 hz: 60 dpi: 86 gamma: 1.4
- size: 376x301mm (14.8x11.85") diag: 482mm (19") ratio: 5:4 modes:
- max: 1280x1024 min: 720x400
- API: OpenGL renderer: AMD CEDAR (DRM 2.50.0 / 5.16.0-11.1\-liquorix-amd64 LLVM
- 12.0.1) v: 3.3 Mesa 21.2.6 compat\-v: 3.1 direct render: Yes
- ....\fR
+ serial: H9NX842662 built: 2004 res: 1280x1024 hz: 60 dpi: 96
+ gamma: 1.2 size: 338x270mm (13.31x10.63") diag: 433mm (17")
+ ratio: 5:4 modes: max: 1280x1024 min: 720x400
+ Monitor\-2: VGA\-1 pos: right model: Dell 1908FP
+ serial: G434H87HRA2D built: 2008 res: 1280x1024 hz: 60 dpi: 86
+ gamma: 1.4 size: 376x301mm (14.8x11.85") diag: 482mm (19")
+ ratio: 5:4 modes: max: 1280x1024 min: 720x400
+ API: EGL v: 1.5 hw: drv: amd r600 platforms: device: 0 drv: r600
+ device: 1 drv: swrast gbm: egl: 1.4 drv: kms_swrast surfaceless:
+ drv: r600 x11: drv: r600 inactive: wayland
+ API: OpenGL v: 4.5 vendor: x.org mesa v: 22.3.6 glx\-v: 1.4
+ es\-v: 3.1 direct\-render: yes renderer: AMD CEDAR (DRM 2.50.0 /
+ 6.4.3\-1\-liquorix\-amd64 LLVM 15.0.6) device\-ID: 1002:68f9
+ memory: 1000 MiB unified: no
+ API: Vulkan v: 1.3.250 layers: 3 device: 0 type: cpu
+ name: llvmpipe (LLVM 15.0.6 256 bits) driver: mesa llvmpipe
+ v: 22.3.6 (LLVM 15.0.6) device\-ID: 10005:0000 surfaces: xcb,xlib\fR
.fi
+
Wayland sample, with Sway/swaymsg:
.nf
-\fBinxi \-aGz
+\fB
+inxi \-aGz
Graphics:
Device\-1: AMD Cedar [Radeon HD 5000/6000/7350/8350 Series] vendor: XFX Pine
driver: radeon v: kernel alternate: amdgpu arch: TeraScale 2
@@ -2113,7 +2329,7 @@ Graphics:
gen: 2 speed: 5 GT/s ports: active: DVI\-I\-1,VGA\-1 empty: HDMI\-A\-1
bus\-ID: 0a:00.0 chip\-ID: 1002:68f9 class\-ID: 0300
Display: wayland server: Xwayland v: 21.1.4 compositor: sway v: 1.6.1
- driver: gpu: radeon d\-rect: 2560x1024
+ driver: dri: r600 gpu: radeon d\-rect: 2560x1024
Monitor-1: DVI\-I\-1 pos: right model: SyncMaster serial: <filter>
built: 2004 res: 1280x1024 hz: 60 dpi: 96 gamma: 1.2
size: 340x270mm (13.4x10.6") diag: 434mm (17.1") ratio: 5:4 modes:
@@ -2122,31 +2338,47 @@ Graphics:
res: 1280x1024 hz: 60 gamma: 1.4 dpi: 86 gamma: 1.4
size: 380x300mm (15.0x11.8") diag: 484mm (19.1") ratio: 5:4 modes:
max: 1280x1024 min: 720x400
- API: GBM/EGL
- Message: Wayland GBM/EGL data currently not available.
+ API: OpenGL v: 4.6 compat\-v: 4.5 vendor: x.org mesa v: 22.3.6
+ glx\-v: 1.4 direct\-render: yes renderer: AMD CEDAR (DRM 2.50.0 /
+ 6.4.3\-1\-liquorix\-amd64 LLVM 15.0.6) device\-ID: 1002:68f9
+ API: EGL v: 1.5 hw: drv: amd r600 platforms: device: 0
+ drv: r600 device: 1 drv: swrast surfaceless: drv: r600 wayland:
+ drv: r600 inactive: gbm,x11
.fi
+
.TP
.B \-a \-I\fR
+\- Adds to \fBPower:\fR other hibernate and suspend available (\fBavail:\fR)
+states, hibernate suspend \fBimage:\fR size, and if any suspend failures
+(\fBfails:\fR), how many.
+
+\- Adds power daemons/services (\fBservices:\fR) running. Note not all services
+are daemons.
+
\- Adds to Packages number of lib packages detected per package manager. Also
adds detected package managers with 0 packages listed. Adds package manager
tools (supported: rpm, dpkg, pkgtool) Moves to \fBRepos\fR if \fB\-ra\fR.
+\- Adds service control tool, tested for in the following order: \fBsystemctl
+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.
+
.nf
\fBinxi \-aI
Info:
- ....
- Init: systemd v: 245 target: graphical.target (5) default: graphical.target
- Compilers: gcc: 9.3.0 alt: 5/6/7/8/9 Packages: pm: apt pkgs: 3681 libs: 2096
- tools: apt, apt\-get,aptitude pm: rpm pkgs: 0 Shell: ksh v: A_2020.0.0
- default: Bash v: 5.0.16 running\-in: kate inxi: 3.1.04\fR
+ Memory: total: N/A available: 31.27 GiB used: 14.9 GiB (47.7%)
+ Processes: 651 Power: uptime: 8d 21h 32m states: freeze,mem,disk
+ suspend: deep avail: s2idle wakeups: 14 fails: 3 hibernate: platform
+ avail: shutdown,reboot,suspend,test_resume image: 12.49 GiB
+ services: upowerd,xfce4\-power\-manager Init: systemd v: 255
+ target: graphical (5) default: graphical tool: systemctl
+ Packages: pm: dpkg pkgs: 3960 libs: 2184 tools: apt,apt\-get,aptitude
+ pm: rpm pkgs: 0 Compilers: gcc: 13.2.0 alt: 5/6/8/9/10/11/12 Shell: Bash
+ v: 5.2.21 running\-in: xfce4\-terminal pinxi: 3.3.32\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. 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]
+.B \-a \-j\fR (\fB\-\-swap\fR), \fB\-a \-P\fR [swap], \fB\-a \-P\fR [swap]
\- Adds swappiness and vfs cache pressure, and a message to indicate if the
value is the default value or not (Linux only, and only if available). If not
the default value, shows default value as well, e.g.
@@ -2159,10 +2391,48 @@ For \fB\-j\fR row 1 output:
\fBKernel: swappiness: 60 (default) cache\-pressure: 90 (default 100)\fR
+\- Adds zswap data for row 1 output:
+
+\fBzswap: [yes/no] compressor: [type] max-pool: xx%\fR
+
+\- Adds for zram swap type: active compression type, available compression
+types, and max compression streams.
+
\- Adds device kernel major:minor number (Linux only).
.TP
-.B \-a \-L\fR
+.B \-a \-J\fR (\fB\-\-usb)\fR
+\- Adds, if available, USB speed in IEC units \fBMiB/s\fR or \fBGiB/s\fR (may
+be incorrect on BSDs due to non reliable data source). These are base 2 Bytes
+per second.
+
+\- Adds USB mode (Linux only), which is the technical terms the USB group uses
+to describe USB revisions. In cases where speed and rev are an unknown
+combination, (and probably at least one is wrong) shows message.
+
+There are no granular data sources in BSDs for accurate revision/lane/speed
+information, so mode cannot be determined.
+
+Sample:
+.nf
+\fB
+Hub\-1: 1\-0:1 info: hi\-speed hub with single TT ports: 14 rev: 2.0
+ speed: 480 Mb/s (57.2 MiB/s) lanes: 1 mode: 2.0 chip\-ID: 1d6b:0002
+ class\-ID: 0900
+Device\-1: 1-4:2 info: Wacom ET\-0405A [Graphire2 (4x5)] type: mouse
+ driver: usbhid,wacom interfaces: 1 rev: 1.1 speed: 1.5 Mb/s (183 KiB/s)
+ lanes: 1 mode: 1.0 power: 40mA chip\-ID: 056a:0011 class\-ID: 0301
+Hub\-2: 2\-0:1 info: Super\-speed hub ports: 8 rev: 3.1
+ speed: 10 Gb/s (1.16 GiB/s) lanes: 1 mode: 3.2 gen\-2x1 chip\-ID: 1d6b:0003
+ class\-ID: 0900
+Device\-1: 2\-8:5 info: SanDisk Ultra type: mass storage driver: usb\-storage
+ interfaces: 1 rev: 3.0 speed: 5 Gb/s (596.0 MiB/s) lanes: 1 mode: 3.2 gen\-1x1
+ power: 896mA chip\-ID: 0781:5581 class\-ID: 0806
+ serial: <filter>\fR
+.fi
+
+.TP
+.B \-a \-L\fR (\fB\-\-logical)
\- Expands Component report, shows size / maj-min of components and devices, and
mapped name for logical components. Puts each component/device on its own line.
@@ -2172,6 +2442,8 @@ mapped name for logical components. Puts each component/device on its own line.
.B \-a \-m\fR
\- Expands volts to include curr/min/max values even if they are all identical.
+\- Adds RAM module firmware version, if detected. Not common.
+
.TP
.B \-a \-n\fR, \fB\-a \-N\fR, \fB\-a \-i\fR
\- Adds, if present, possible \fBalternate:\fR kernel modules capable of driving
@@ -2184,6 +2456,12 @@ knows could possibly be used instead.
or lanes, \fBlink\-max: gen: speed: lanes:\fR (only items different from primary
shown).
+\- Adds for USB devices USB mode (Linux only).
+
+\- Adds \fBInfo:\fR line (\fB\-n\fR, \fB\-i\fR only), with running network type
+\fBservices:\fR. Note not all services are daemons. For example,
+\fBNetworkManager\fR can be started with \fB\-\-no\-daemon\fR flag.
+
.TP
.B \-a \-o\fR
\- Adds device kernel major:minor number (Linux only).
@@ -2219,9 +2497,17 @@ Component report to 1 component per line.
.TP
.B \-a \-S\fR
+\- Adds alternate kernel clock sources, if available (Linux only).
+
\- Adds kernel boot parameters to \fBKernel\fR section (if detected). Support
varies by OS type.
+\- Adds advanced desktop (\fBinfo:\fR) item, and version. Currently supports KDE
+Frameworks and version.
+
+\- Adds other available (\fBavail:\fR) screensavers/lockers in \fBtools:\fR
+section. These are ones installed, but not necessarily active or running.
+
.TP
.B \-a \-\-slots\fR
\- Adds PCI children of the main slot bus ID, and their types and class IDs,
@@ -2274,9 +2560,8 @@ basically forces the downloader selection to use \fBPerl 5.x\fR
may help bypass issues with downloading.
.TP
-.B \-\-bt\-tool [bt\-adapter|hciconfig|rfkill]\fR
-Force the use of the given tool for bluetooth report (\fB\-E\fR). \fBrfkill\fR
-does not support mac address data.
+.B \-\-bt\-tool [bt\-adapter|btmgmt|hciconfig|rfkill]\fR
+See \fB\-\-force [tool name]\fR. Used to set \fB\-E\fR report tool.
.TP
.B \-\-dig\fR
@@ -2315,6 +2600,10 @@ as a comma separated list:
\fBinxi \-MJ --force dmidecode,lsusb\fR
+\- \fBbt\-adapter\fR \- Force use of bt\-adapter tool in \fB\-E\fR.
+
+\- \fBbtmgmt\fR \- Force use of btmgmt tool in \fB\-E\fR.
+
\- \fBcolors\fR \- Same as \fB\-Y \-2\fR . Do not remove colors from piped or
redirected output.
@@ -2323,18 +2612,25 @@ redirected output.
\- \fBhddtemp\fR \- Force use of hddtemp instead of /sys temp data for disks.
+\- \fBifconfig\fR \- Force use of IF tool ifconfig for \fB\-i\fR.
+
+\- \fBip\fR \- Force use of IF ip tool for \fB\-i\fR (default).
+
\- \fBlsusb\fR \- Forces the USB data generator to use \fBlsusb\fR as data
source (default). Overrides \fBUSB_SYS\fR in user configuration file(s).
-\- \fBrpm\fR, \fBpkg\fR \- Force override of disabled RPM package counts on
-primarily RPM run systems due to unacceptably slow execution times for this
+\- \fBrfkill\fR \- Force use of rfkill tool in \fB\-E\fR. \fBrfkill\fR does not
+support mac address data.
+
+\- \fBrpm\fR, \fBpkg\fR \- Force override of disabled rpm package counts on
+primarily rpm run systems due to unacceptably slow execution times for this
command:
.nf
\fBrpm \-qa \-\-nodigest \-\-nosignature\fR
.fi
-Even on newer RPM systems, in virtual machines, running rpm package list query
+Even on newer rpm systems, in virtual machines, running rpm package list query
takes more than 0.15 seconds (compared to 0.01 to 0.05 for dpkg, pacman, pkgtool
etc) for just this single feature, which is north of 10% of total execution time
for \fBinxi \-bar\fR. On bare metal this can hit 1 second or more in our tests.
@@ -2352,6 +2648,9 @@ lm\-sensors data was found anyway, but if \fBlm\-sensors\fR was installed, and
returned no data, it's most likely if not nearly certain that \fB/sys\fR will
also not return data.
+\- \fBudevadm\fR \- Forces use of udevadm as data source (currently \fB\-m\fR
+RAM data).
+
\- \fBusb\-sys\fR \- Forces the USB data generator to use \fB/sys\fR as data
source instead of \fBlsusb\fR (Linux only).
@@ -2374,6 +2673,10 @@ 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 \-\-ifconfig\fR
+Shortcut. See \fB\-\-force ifconfig\fR.
+
+.TP
.B \-\-man\fR
Updates / installs man page with \fB\-U\fR if \fBpinxi\fR or using \fB\-U 3\fR
dev branch. (Only active if \fB\-U\fR is is not disabled by maintainers).
@@ -2414,10 +2717,10 @@ behavior.
.TP
.B \-\-no\-ssl\fR
-Skip SSL certificate checks for all downloader actions (\fB\-U\fR, \fB\-w\fR,
-\fB\-W\fR, \fB\-i\fR). Use if your system does not have current SSL certificate
-lists, or if you have problems making a connection for any reason. Works with
-\fBWget\fR, \fBCurl\fR, \fBPerl HTTP::Tiny\fR and \fBFetch\fR.
+Skip SSL certificate checks for all downloader actions (\fB\-U\fR, \fB\-w\fR,
+\fB\-i\fR). Use if your system does not have current SSL certificate lists, or
+if you have problems making a connection for any reason. Works with \fBWget\fR,
+\fBCurl\fR, \fBPerl HTTP::Tiny\fR and \fBFetch\fR.
.TP
.B \-\-no\-sudo\fR
@@ -2505,7 +2808,7 @@ color codes in the output, use the \fB\-c [color ID]\fR flag.
The sign you need to use this is extra numbers before the key/value pairs of
the output of your program. These are IRC, not TTY, color codes. Please post a
-github issue if you find you need to use \fB\-\-tty\fR (including the full
+codeberg.org issue if you find you need to use \fB\-\-tty\fR (including the full
\fB\-Ixxx\fR line) so we can figure out how to add your program to the list of
whitelisted programs.
@@ -2554,8 +2857,8 @@ Accepts one or more comma separated dbg specific debugging numbers.
and fetch. Shows more downloader action information. Shows some more information
for Perl downloader.
-\fB1\-xx\fR \- See github \fBinxi\-perl/docs/inxi\-values.txt\fR for specific
-specialized debugging options. There are a lot.
+\fB1\-xx\fR \- See codeberg.org \fBinxi\-perl/docs/inxi\-values.txt\fR for
+specific specialized debugging options. There are a lot.
.TP
.B \-\-debug [1\-3]\fR
@@ -2595,6 +2898,13 @@ removes the debug data directory and the tar.gz file.
See \fB\-\-ftp\fR for uploading to alternate locations.
.TP
+.B \-\-debug\-id [string]\fR
+Insert string to file name for debugger. This is helpful so you can add for
+instance a username to a debugger dataset to make it easy to find.
+
+Sample: \fB\-\-debug 22 \-\-debug\-id mrmazda\fR
+
+.TP
.B \-\-fake\-data\-dir\fR
Developer only: Change default location of $fake_data_dir, which is where files
are for \fB\-\-fake {item}\fR items.
@@ -2703,23 +3013,30 @@ inxi will read its configuration/initialization files in the
following order:
\fB/etc/inxi.conf\fR contains the default configurations. These can be
-overridden by creating a \fB/etc/inxi.d/inxi.conf\fR file (global override,
-which will prevent distro packages from changing or overwriting your edits. This
-method is recommended if you are using a distro packaged inxi and want to
-override some configuration items from the package's default
+overridden by creating a \fB/etc/inxi.conf.d/inxi.conf\fR file (global
+override), which will prevent distro packages from changing or overwriting your
+edits. This method is recommended if you are using a distro packaged inxi and
+want to override some global configuration items from the package's default
\fB/etc/inxi.conf\fR file but don't want to lose your changes on a package
-update.
+update.
+
+In case the distro is using either \fB/usr/etc\fR or \fB/usr/local/etc\fR as non
+core tool default location, inxi will use those paths instead, with the
+\fBinxi.conf.d/inxi.conf\fR override option.
-You can old override, per user, with a user configuration file found in one of
+You can also override, per user, with a user configuration file found in one of
the following locations (inxi will store its config file using the following
-precedence:
+precedence):
if \fB$XDG_CONFIG_HOME\fR is not empty, it will go there, else if
-\fB$HOME/.conf/inxi.conf\fR exists, it will go there, and as a last default,
+\fB$HOME/.config/inxi.conf\fR exists, it will go there, and as a last default,
the legacy location is used), i.e.:
-\fB$XDG_CONFIG_HOME/inxi.conf\fR > \fB$HOME/.conf/inxi.conf\fR >
-\fB$HOME/.inxi/inxi.conf\fR
+\fB$XDG_CONFIG_HOME/inxi.conf\fR > \fB$HOME/.config/inxi.conf\fR >
+\fB$HOME/.inxi/inxi.conf\fR > \fB/usr/etc/inxi.conf\fR >
+\fB/usr/etc/inxi.conf.d/inxi.conf\fR > \fB/usr/local/etc/inxi.conf\fR >
+\fB/usr/local/etc/inxi.conf.d/inxi.conf\fR > \fB/etc/inxi.conf.d/inxi.conf\fR >
+\fB/etc/inxi.conf\fR
.SH CONFIGURATION OPTIONS
@@ -2800,7 +3117,8 @@ Override with \fB\-\-sensors\-default\fR. See \fB\-\-sensors\-exclude\fR.
\fBSENSORS_USE\fR Use only supplied sensor array[s]. Override with
\fB\-\-sensors\-default\fR. See \fB\-\-sensors\-use\fR.
-\fBSEP2_CONSOLE\fR Replaces default key / value separator of '\fB:\fR'.
+\fBSEP2_CONSOLE\fR Replaces default key / value separator of '\fB:\fR'. Test
+with \fB\-\-separator\fR.
\fBUSB_SYS\fR Forces all USB data to use \fB/sys\fR instead of \fBlsusb\fR.
@@ -2830,7 +3148,7 @@ options available in \fB\-c 94\-99\fR.
NOTE: All default and configuration file set color values are removed when
output is piped or redirected. You must use the explicit
-\fB\-c <color number>\fR option if you want colors to be present in the
+\fB\-c [color number]\fR option if you want colors to be present in the
piped/redirected output (creating a PDF for example).
\fBCONSOLE_COLOR_SCHEME\fR The color scheme for console output (not in
@@ -2864,21 +3182,28 @@ data inxi uses to parse out its report.
.TP
.B Issue Report
File an issue report:
-.I https://github.com/smxi/inxi/issues
+.I https://codeberg.org/smxi/inxi/issues
.TP
.B Forums
Post on inxi forums:
.I https://techpatterns.com/forums/forum\-33.html
.TP
-.B IRC irc.oftc.net#smxi
-You can also visit
-.I irc.oftc.net
-\fRchannel:\fI #smxi\fR to post issues.
+.B IRC irc.oftc.net\fR / \fBirc.libera.chat\fR
+You can also visit \fRchannel:\fI #smxi\fR to post issues on either network.
.SH HOMEPAGE
-.I https://github.com/smxi/inxi
+.I https://codeberg.org/smxi/inxi
+\fR \- Home of inxi source repository
+
+.I https://codeberg.org/smxi/pinxi
+\fR \- Home of pinxi (inxi development version), docs and data.
.I https://smxi.org/docs/inxi.htm
+\fR \- The main docs for inxi. See pinxi repository for more technical
+resources.
+
+.I https://fosstodon.org/@smxi
+\fR \- Follow @smxi on Mastodon!
.SH AUTHOR AND CONTRIBUTORS TO CODE
@@ -2888,7 +3213,7 @@ is a fork of \fBlocsmif\fR's very clever \fBinfobash\fR script.
Original infobash author and copyright holder:
Copyright (C) 2005\-2007 Michiel de Boer aka locsmif
-inxi version: Copyright (C) 2008\-2021 Harald Hope
+inxi version: Copyright (C) 2008\-2023 Harald Hope
This man page was originally created by Gordon Spencer (aka aus9) and is
maintained by Harald Hope (aka h2 or TechAdmin).
@@ -2936,6 +3261,10 @@ inconsistencies is much appreciated.
For a huge boost to BSD support, Stan Vandiver, who did a lot of testing
and setup many remote access systems for testing and development.
+For testing, bug finding, suggestions, feature requests, MrMazda. He has over
+the years has helped shape inxi into what it is today, in particular but not
+limited to, the Graphics features.
+
All the inxi package maintainers, distro support people, forum moderators,
and in particular, sys admins with their particular issues, which almost always
help make inxi better, and any others who contribute ideas, suggestions, and
diff --git a/inxi.changelog b/inxi.changelog
index a16d6c8..b1fb5b5 100644
--- a/inxi.changelog
+++ b/inxi.changelog
@@ -1,4 +1,2801 @@
================================================================================
+Version: 3.3.33
+Patch: 00
+Date: 2024-02-06
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+A quick point release, one critical bug fix, and a few new features and
+enhancements. Extended the running service from Info: Power: services: to
+Network: Info: services:. The PsData refactor makes this quite easy to do. So
+why not?
+
+Also in terms of general usability, added an error handler for options that
+require primary options to be meaningful, that was already there for --label and
+--uuid, but there are several other similar modifier options that were not
+handled.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. GRAPHICS: Codeberg user malcolmlewis, for being the first to find a fatal bug
+(see BUGS 1) in the newly shipped inxi 3.3.32 codebase. Not complex bug, just
+stupid coding error.
+
+2. OPTIONS: mrmazda has been wanting an options handler that tells users when
+they use an option that only modifies another, without using the primary option.
+That is now working.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1. INFO/NETWORK: Terminology: daemon/service/process: following:
+https://serverfault.com/questions/129055/is-there-a-difference-between-a-\
+daemon-and-a-service
+
+* A "Service" could refer to either a Daemon or a Service.
+
+* A daemon is a subset of services that always run in memory waiting to service
+a request.
+
+For example, NetworkManager can be started with --no-daemon option, but still
+be running as an active service, thus, there is a difference.
+
+Note that to remove this ambiguity we use the term: services:
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. GRAPHICS: GraphicsItem::map_monitor_ids(): a stray bit of old syntax tripped
+an impossible data error. Cause was accidentally make a array index be an index
+pointing to an array reference index, leading to failure. Thanks codeberg user
+malcolmlewis for triggering this case, which is not super easy to trip. Never
+tripped in any recent testing, but valid and a bug.
+https://codeberg.org/smxi/inxi/issues/298
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. DistroData: Removed a stray print debugger.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1. SYSTEM: DistroData: Added final distro/base name cleaners, remove duplicate
+'words' that are not numbers from the distro name if they occur in base name.
+Also handles a corner case where name and base are the same string, then it
+just sets base to empty. Only runs with -Sx and successful name and base
+detection.
+
+2. OPTIONS: Moved and updated these from Output Control section to main options:
+
+* Added --ip-limit as synonym for --limit so it fits better with --ip.
+
+* Added --partition-sort, --ps to --partitions-sort, that makes it fit better
+with --partition/--partition-full. It only shows --partitions*, but supports
+either syntax so it doesn't matter how you remember it.
+
+* Added new error handler type: arg-modifier which is used to show missing
+primary option when primary option modifier is used, like --sleep/-C,
+-p/--partitions-sort, -l/-p, and so on.
+
+3. MACHINE: --uuid/-u now also activates UUID item, like partitions. Keeping
+-a adding behavior since we want all that info, but make use of -u consistent
+now that using uuid in machine report. Not common though.
+
+4. NETWORK: -n/-i -a now trip a services: report, with a new line:
+Info: services: [services]. These can be daemons or services, same as with Power
+services:.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1a. MAN/OPTIONS: Re-arranged option locations, moved back to their modified
+options in primary options. Those didn't fit there, they should have been next
+to the options they modify.
+
+* Moved --partition-sort back up to --partitions [from Output Control sections]
+
+* Moved --limit to --ip-limit next to --ip [from Output Control sections].
+
+1b. MAN/OPTIONS: changed daemons: to services:
+
+2. INFO: changed Power:... daemons: to services: due to the fact not all
+services are daemons, and some potential daemons can be started explicitly with
+--no-daemon flag (like NetworkManager), which means it is false to say it's a
+daemon.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1a. MAN/OPTIONS: See Change 1, moved --partitions-sort, --limit, back up to main
+options they modify to make it more readily obvious they belong together.
+
+2a. DOCS: inxi-battery.txt: updated, added TLP/tlp-stat info.
+
+2b. DOCS: inxi-network.txt: added DAEMONS tools section.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1a. DEBUG: moved the DesktopData::de_wm_debugger() to
+main::feature_debugger(). This is a useful tool and will be used for other
+complex user data debugging requirements where clear output helps develop and
+debug issue. Very useful for --dbg 63 so making general tool. Also used for new
+--dbg 66, DistroData, which works in similar way.
+
+1b. DEBUG: Added to SystemDebugger 'tlp-stat -s', forgot that one.
+
+1c. DEBUG: Added --dbg 66 for DistroData, like 63 for DesktopData.
+
+2. SYSTEM: DistroData: refactored to use primary $distro hash ref, this is also
+what is passed back to the System line generator now. Switched most variables to
+be hash keys, this allows for debugging and tracking what trips the distro data
+for --dbg 66, for logging, and to more rapidly check/add/update distro/base IDs.
+
+3a. CORE: OptionsHandler: small refactor, moved pledge block to set_pledge(),
+and moved all option modifier tests to check_modifiers(). This makes it more
+obvious each set is its own set of actions, and is easier to maintain.
+
+3b. CORE: main::error_handler(): new type: arg-modifier: used in 3a.
+
+3c. CORE: main::make_list_value() replaces main::set_join_sep(), now lists that
+can be too long and require a space after separator are generated all by
+reference, making for easier and more consistent long value outputs.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Tue, 06 Feb 2024 15:16:01 -0800
+
+================================================================================
+Version: 3.3.32
+Patch: 00
+Date: 2024-01-30
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+PACKAGERS: The code repo for inxi is codeberg.org/smxi/inxi. If you have not yet
+changed your packaging source url, you will need to do that. I have extended for
+a few months the mirror of codeberg inxi to github, but I will turn that mirror
+off fairly soon. The pinxi inxi-perl branch mirror is already turned off.
+
+--------------------------------------------------------------------------------
+
+This is a massive upgrade, featuring many core tool refactors, leading to
+significantly enhanced abilities to debug and add support for various features,
+particularly desktop type data, but any software type version reports as well.
+
+Many parts of the core logic have been touched, and the testing has been the
+most vigorous in recent memory, thanks to antiX and Slackware, and mrmazda, in
+particular for their significant help making these new features and upgrades
+far less buggy out of the box than would have otherwise been possible.
+
+* Finally, a reasonable quality RAM report for Linux with dmi table RAM data,
+without needing dmidecode or root! Uses udevadm, which despite some fairly
+significant weak poinots, is ok, except for issues like module voltage, which
+are stuck at a false value of 1. Also multi memory array system boards have poor
+to no native handling, so inxi tries to work around that failing.
+
+* A big improvement in ability to match xrandr X port ID to DRM port IDs, using
+a stable value found in each. This has been a long standing weak spot for multi
+monitor display IDs.
+
+* Power data, for suspend/hibernate, screensavers, closes a recent issue #292
+from chromer030. This also extended to running power daemons, and in -S, Desktop
+report, added screensaver and lockers in tools:.
+
+* A huge upgrade to all core Desktop/wm data, including new data types, complete
+internal refactoring, including of all program version data, ps based data, etc.
+This will massively reduce the risk of errors, bugs, etc, in the future, and
+also makes debugging and adding support for new de/wm far easier.
+
+* Note this change: Desktop info: has been repurposed to the new advanced DE
+info report (KDE Frameworks only currently), and the old info:, which was never
+well named, now is called with:, because it's a report on the various parts, or
+components, that make up the de/wm. Also the order was changed in the Desktop
+line: Desktop: v: [tk: [v:]] [info: v:] [wm: [v:]] [with:] [tools:] [dm:/lm:].
+
+* A big upgrade in the TinyX logic, which should work now to get resolutions for
+TinyCore and possibly other tiny x using distros. That includes detections for
+all known TinyX servers, not just Xvesa.
+
+* With TinyX fixes, now has full support for Slitaz, package manager, distro id,
+repos. And Alpine Linux was enhanced and upgraded re support as well with these
+fixes.
+
+OPTIONS REMOVAL/DEPRECATION:
+To free up upper case single letter options, merged -W with -w and removed -W,
+which now trips a removed option error. To prepare for -V being removed, that
+shows a deprecated message then the full version.
+
+Note that if you really care and want -V retained, file an issue, or contact
+inxi and say so. It will only really take one person who has a preference to
+retain -V to keep it. That will be decided next inxi, if nobody cared, then -V
+will be removed. Ideally say why you care, and why typing --vf is too much.
+
+The use of -W was always an error, forced I think by some options handling
+limits of bash. -V was just to have a single letter --version, but I think given
+-v is verbosity, -V is actually slightly confusing. Also, single letter options
+are in short supply now, and there's no point in wasting them on stuff where
+it's not really needed to get fast easy output for features.
+
+Also removed the long since deprecated --gpu, --nvidia, --nv, were removed, and
+will show option removed message.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. GRAPHICS: Android compositor: Thanks codeberg.org/smxi/inxi issue poster
+Mhowser for providing an Android data set from a rooted FxTec Pro1-X phone,
+which gave enough info to polish up and add some more Android support. But only
+on rooted devices, but Android doesn't let you learn much if the device is not
+rooted. That issue is lost because it was put on pinxi issues, before pinxi
+was switched to use inxi issues to avoid confusion.
+
+2. DOCS: data/audio/audio-datasets: mrmazda provided his large collection of
+audio data debuggers, which have alsa, systemctl, pulse, etc, debugging data.
+
+3. ONGOING: mrmazda, for finding and forwarding subtle to not so subtle issues.
+See Bugs 4, Fixes 6b. In this case pointed me to the relevant forum posting that
+exposed the error, which was enough to track it down.
+
+4. SYSTEM: DesktopData: The people over at antiX forums were really helpful
+finding/testing the new desktop/wm etc logic. Many glitches, errors, bugs, etc,
+found and corrected thanks to the excellent testing. ile and abc-nix in
+particular found some significant issues that were finally resolved. Also thanks
+to Brian Masinick, rokytnji, anticapitalista for helping making antiX for all
+these years.
+
+https://www.antixforum.com/forums/topic/testing-pinxi-next-inxi-user-ram-\
+report-no-root-sudo-and-much-more/
+
+5. RAM: The new udevadm was significantly improved and corrected thanks to the
+Slackware forums people. As is often the case, when it comes to having complex
+non-standard hardware, they came though, and exposed some key problems which let
+this new feature come out the door in much better shape than it would otherwise
+have done.
+
+https://www.linuxquestions.org/questions/slackware-14/new-inxi-pinxi-\
+features-user-ram-reports-and-much-more-testers-4175732843/
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1a. SYSTEM: DistroData: no obvious way to detect edubuntu, bunsenlabs, sorry.
+
+1b. SYSTEM: CompilerVersion::version_proc(): the /proc/version string is far
+too unreliable because distros keep making up new syntaxes, which makes regex
+parsing fail consistently over time. Ubuntu was the latest culprit. Need a
+better data source, ideally from /sys. Latest breaks handled with much looser
+regex, but only matter of time before a new string pattern breaks it.
+
+2. GRAPHICS: No API type data so far for non Xvesa TinyX servers. They don't
+seem to support the -list option like Xvesa does.
+
+3a. CORE: very old busybox ps did not accept any arguments, so will always fail.
+However, this is not important since new busybox has supported that for a long
+time.
+
+3b. CORE: in some cases, ps -wwjp $pppid truncates long command names, like
+io.elementary.t[erminal]. No idea why since -ww is supposed to make it not
+truncate.
+
+4. CPU: for at least AMD Threadripper 2950x 16 core, 2 die, core counts are
+wrong, but since I never got the required data, and can't guess, that will
+remain wrong until I get data from a comparable CPU to debug it using the CPU
+data pairs required to figure it out. Why people file issues that only their
+system data can resolve, then refuse to supply that data, is beyond me, I was
+hoping to get away from this type of problem by going to codeberg, but
+apparently it's a universal issue. My guess is that for the Zen+ only series, >
+1 die, the core numbers were per die, not per physical CPU as with all other
+AMDs and Intels. Just a guess though, not going to act on it because fix is very
+hard if that's the case, and I won't work on it without the real data.
+
+5. RAM: udevadm data:
+
+* For some reason, voltages are reported as 1, for all types, or not at all.
+This is almost certainly a bug with udevadm or the way it collects data, so inxi
+shows note: check when they are all equal to 1.
+
+* Unfortunately the udevadm authors neglected to provide RAM array and matching
+device handles so we can easily match array to device, and they also totally
+neglected reporting on actual arrays found, for systems with > 1 array, they
+list only the specs for the one array. inxi has to do the work to actually try
+to generate the array capacities etc. This relies on a weak hack, assume that
+Node [x] refers to the array, which so far has been the case, but very weak, and
+very poor execution by udevadm ram feature authors, sad to say.
+
+* As far as we can tell, udevadm does not support:
+udevadm info -p /devices/virtual/dmi/id
+option until somewhere between v245 (no support) and v249 (supported). This
+means that some distros that ship a pre 249 version will not get user RAM data.
+Known is Slackware 15.0 (but is in Current), TinyCore 14, and probably other
+tiny distros. Many LTS type frozen pool distros will probably not support it.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. SYSTEM: kernel gcc version: see FIXES 4a. While this is not a bug per se,
+since who can predict when a distro will change format to /proc/version, users
+might see it as one. This impacted various distros.
+
+2. INFO: init detection for busybox /sbin/init hung forever on slitaz, now
+works, and adds the busybox version as well. This was exposed by slitaz. Also
+was showing sysvinit for TinyCore, the slitaz fix also fixed the failure to ID
+BusyBox init on TC.
+
+3. CORE: see Fix 7b, inxi used wrong path for its .d config locations, never
+spotted it since I never use those, showed up in codeberg issue #295 when that
+did not work.
+
+4. GRAPHICS: EGL: see Fix 6b. Was missing one error message type, leading to
+undefined value print error.
+
+5. CPU: vascom in issue #297 reported an unset value error in disabled smt
+cpu speeds, see CODE 8. This required a CPU debugger data upgrade to handle
+more cleanly. It appears that a Perl behavior has changed, it was returning ''
+for undefined read, now seems to be returning the correct undefined. Or could
+be kernel that changed that, can't say, but creates buggy looking output with
+Perl errors. No actual data bugs though.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. DOWNLOADER: Small error in assignment could lead to onscreen error output.
+Not worth a new release fix. Added to inxi master as 3.3.31-2.
+
+2. SENSORS: corner case with undefined value where it's almost always defined
+for load_sys_data(). Shows undefined on screen output. Never seen this until
+today, but that's how it goes. Also added to inxi master as 3.3.31-2.
+
+3a. PARTITIONS: added possible filter path: /dev/(block/)?loop[0-9]+, saw that
+on Android.
+
+3b. PARTITIONS: added vboxsf, not a typo, that's a client mounted host fs for
+vbox, works like nfs/smb re filters etc. Never seen that one before, probably
+because I almost never use the host > guest shared folder feature of vbox.
+
+4a. SYSTEM: CompilerData: kernel gcc version: found _more_ syntaxes for the gcc
+string in /proc/version. The randomness of this string generation forced a redo
+of the regex, which should now catch almost any gcc/clang version number no
+matter how weird the syntax is. The new regex is much looser and handles all
+known variants.
+
+4b. SYSTEM: DesktopData:
+
+* Fixed broken fvwm-crystal ID, that one is tricky, and it got broken by
+accident a while back.
+
+* Fixed broken echinus hackedbox mvwm detections, had neglected to add those in
+PsData::set_gui() for some weird reason. Also had forgotten to add some of those
+to ProgramData::set_values(). Also note that TinyCore ships with hacked box, but
+their -version is broken, shows v: 2001 because they forgot to add in the actual
+version in the string. Forgetting to update all the locations of those string
+lists was a big reason that the ps handler was fully refactored, and all uses of
+its data, too hard to maintain when having to update in multiple locations the
+same value.
+
+* Fixed broken KDE 4 version, qt data. That has been broken for a while.
+
+* Fixed corner case where wm is detected, and is the same as de/wm parent, and
+is rejected, but then since wm is not populated, it runs wmctrl anyway, which
+can result in wrong results, like showing wm: wlroots wm [a generic term] for
+Hyprland wayland wm.
+
+* Fixed broken Muffin (Cinnamon wm) detection.
+
+* Added tk: GTK for Budgie, Pantheon. Added tk: Qt for lxqt variants. These
+often worked before, but now are more robust.
+
+* Fixed bad JWM wm version, was using --version, -v is right.
+
+* Fixed xfwm, was not showing xfwm4 etc, just xfwm.
+
+* Fixed spectrwm version detection, the old verbose string was simplified to:
+spectrwm x.y.z Build: a.b.c. Used filter method to dump the old verbose part.
+
+5. RECOMMENDS: wrong package name for pacman eglinfo, glxinfo.
+
+6a. GRAPHICS: gl_data():
+
+* fixed use of undefined $platform, missed some, those can and did spew out
+errors in some cases due to trying to use undefined hash key name.
+
+* fixed case where EGL version was not fully numeric: 1.4 (DRI2)
+
+6b. GRAPHICS: API data: see Bug 4. Was missing one api data error message type.
+This led to output of undefined value print errors. The real cause however was
+inconsistent naming of the gfx api message types, which is the main fix, along
+with adding the missing one. Now they all match and are easy to scan. Making
+things consistent internally has been a main goal of the 3.3.32 release.
+
+7a. CORE: See CODE 7b, fixed corner cases ps failures for older or more stripped
+down busybox ps. Now should handle all cases automatically.
+
+7b. CORE: Configs::set() had the wrong paths for all the .d directories, making
+those fail. Was missing the .conf part of the path, just showed inxi.d/. Oops.
+
+7c. CORE: main::set_basics(): found case where $ENV{'HOME'} undefined, which
+trips undefined concat errors. Attempt to set it manually with whoami and paths.
+
+8. PROCESSES: Long standing error, probably imported from original bash inxi,
+with -tm showed broken throttled message even though no throttling occured. This
+only happened with -tm, not -tc or -tcm.
+
+9. INFO: GCC versions: switched to ProgramData::full(). Fixed regex to allow the
+primary version number (12.2,9,4.8, etc)) for alt, we don't care about sub-sub
+versions there, but we do care about sub versions. Sort numeric for results,
+which corrects the odd order created by alpha sorts before. Fixed broken filter
+to exclude default gcc version from alt list.
+
+This fix also exposed alt gcc version detection failure on FreeBSD, different
+path, and different executable name syntax (/usr/bin/gcc-9 vs
+/usr/local/bin/gcc9 as well as an odd legacy numbering format for 4.8, 4.9
+(gcc48,gcc49).
+
+10. MACHINE: Fixed some BSD sysctl machine field name assignments that may have
+resulted in those fields never showing in output. Added some conditional tests
+as well. Also fixed and normalized some dmidecode mobo/chassis field names.
+
+11a. RAM: In some cases, module locator is only DIMM 1, without the channel. If
+Channel [A-Z]] is found in branch locator, prepend that to DIMM X to make actual
+location more obvious.
+
+11b. RAM: In cases of > 1 RAM array, failed to reset the slots active counter
+in each array. This led to silly looking active slots totals for the arrays.
+
+12. REPOS/INFO: PackageData for cases where distro uses a package manager non
+natively, like AltLinux with apt-get, but no dpkg, so can't get package counts.
+Now detects pm and uses right command to get package list and show tools.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1a. SYSTEM: DistroData:
+
+* Adding initial support for Ubuntu internal spins, like Kubuntu, Lubuntu,
+Xubuntu. Shows project name for distro, and adds base: Ubuntu for -Sx.
+
+* Forcing os-release use for Fedora, that captures spins like Onyx
+automatically. Was using redhat-release, which had the Fedora version string,
+but best to use os-release explicitly. Too bad we can't default everything to
+use os-release, but that's not reality.
+
+* Added in Fedora system base for variety of Fedora based distros. This corrects
+many from IDing as RHEL 39 etc, now shows Fedora. As with all derived distros,
+these ids are not all tested, but often work. Confirmed: Nobara, risiOS,
+Ultramarine. Not all are identifiable.
+
+* Added Devuan system base distros: crowz, dowse, etertics, exe, fluxuan,
+gnuinos gobmis, heads, miyo, refracta, star, virage. This should in many cases
+automatically cover the specific derived distro ID as well since those usually
+are in the 'PRETTY_NAME' field of /etc/os-release. Not exe, not star, I believe.
+
+* Added in Debian/Devuan system base support for Peppermint, that requires
+custom rule since the base can be either. Selection based on presence/absence of
+/etc/devuan_version.
+
+* Added special distro id where distro id is from distro-version file, but ID is
+only numeric. Slitaz does this for example. Takes file, slices off
+{-version,release}, then concatenates the distro name and number. This is
+uncommon, but should anyone else do it that way, easy to add now.
+
+1b. SYSTEM: DesktopData:
+
+* Added screensaver/locker (tools:) to -Sxxx/-Sa. -Sxxx shows running tools, and
+-Sa adds avail: for any installed, but not running. That's because many of these
+tools are not daemons, but are triggered by a daemon.
+
+* Added wm dawn, dusk. Those are dwm forks so assuming -v works the same for
+version (to stderr). Added wms w9wm, x9wm - assuming -version info same as for
+9wm, which is what they were forked from I believe.
+
+* Added CDE and dtwm, because, well, why not? No version for either. And NsCDE,
+which uses FVWM2 for wm.
+
+* Added Draco (a Lumina spin) support.
+
+* For -a and KDE, added advanced data info: frameworks v: x.y.z. Other desktops
+with comparable and detectable advanced data will be added as we find them. Note
+that this repurposed the previous use of the info: field name, which is now
+with:.
+
+* For qtile, spectrwm, and maybe others, they give wmctrl a false wm id, for
+some reason, now inxi gets rid of that since it's a fictional result, done
+deliberately, but is not the wm.
+
+* Item: info: added more bars, panels, menus, launchers.
+
+* Added --dbg 63 user debugger so we can track down how de/wm/tk detections
+happen, their data sources, etc. See CODE 4c. Much easier to say add --dbg 63
+than to say all the stuff to echo etc. antiX testers showed how useful this
+could be right away, as did dev vm testing for de/wm.
+
+* Added ELF toolkit data (Enlightenment, Moksha). The elf-version tool is not
+always there, but if it is, tk is easy to get.
+
+1c. SYSTEM/GRAPHICS: Added bismuth, maynard, orbment, polonium, swayfs
+compositors.
+
+1d. SYSTEM: DmData:
+
+* Added lm: (login mamager) type fallback, if no dm detected. Added seatd,
+elogind, greetd to the fallback lm. Some of those were in the main dm block
+before, but now they are detected as login managers in case where no dm was
+detected. This handles de, wm, wayland compositors using seatd, elogind, etc.
+
+* Added lemurs display manager. Not verified, don't know if --version info.
+
+2a. GRAPHICS: tentatively trying for Android Surfaceflinger, and other display
+data.
+
+2b. GRAPHICS: a long standing weakness, fuzzy mapping of X.org port IDs to
+DRM port IDs may be finally resulved, assuming xrandr --prop and drm device in
+/sys. Now matching connector_id to CONNECTOR_ID, which is an absolute match
+using an integer value ID. This now precedes all other mapping tests in the
+port ID mapper.
+
+2c. GRAPHICS: added support for all known tiny X display servers:
+
+Xchips Xfbdev Xi810 Xigs Xipaq Xmach64 Xmga Xmodesetting Xneomagic Xsavage
+Xsis530 Xtrident Xtrio Xts300 Xvesa
+
+I had no idea anything other than Xvesa existed, but apparently there's a bunch!
+Found this when testing TinyCore Pure64, which uses Xfbdev. I did not know that
+Xvesa only supports 32 bit either. This was exposed when testing on TinyCore
+Pure64.
+
+Also changed to dynamic detection using ps data, which then allows for sometimes
+getting the screen resolution as well from ps for TinyX servers. Also avoids
+cases where > 1 were installed but only 1 is running, of course.
+
+2d. GRAPHICS: Xfbdev may expose the virtual_size of screen assuming
+/sys/devices/platform/*/graphics/*/virtual_size exists.
+In test system, that's:
+/sys/devices/platform/vesa-framebuffer.0/graphics/fb0/virtual_size
+
+This allows showing resolution for at least Xfbdev TinyX systems, like TinyCore
+Pure64. No idea if this is a general thing or I just happened to find a case
+where it works.
+
+This goes along with adding the resolution from ps start string if present.
+
+2e. GRAPHICS: gfx vendor ID updates: AMD, Intel, Nvidia. This finally saw more
+IDs generated for their latest generation gpus, which had been sparse before.
+
+3a. INFO/REPOS: PackageData: added pm tools:
+
+* pacman: added baph, pacseek.
+
+* deb/apt: added muon.
+
+3b. INFO/REPOS: PackageData/RepoItem: added tazpkg (slitaz pm).
+
+3a. INFO: Power: added to wakeups, and created Power: type that turns on with
+-Ixxx:
+* uptime
+* states - suspend/hibernate types supported
+* suspend: active type
+ * other available types [-Ia]
+ * wakeups
+* hibernate: active type
+ * other available types [-Ia]
+ * hibernate image size [-Ia]
+
+-Ia: Adds Power daemons running.
+
+This closes issue #292 for adding power state report.
+
+3b. INFO: Compiler: added tentative support for zigcc. Also extended to support
+clang alt versions, along with BSD alt paths for clang, gcc alt locations. This
+adds support also for BSD type /usr/local/bin alt gcc/clang paths, so that data
+will suddenly appear for the inxi BSD users out there.
+
+4. VERSION: Along with deprecating -V, added --vf (--version shortcut), which
+goes along with --vs / --version-short to maybe easier to remember?
+
+5. WEATHER: Added --wu as short-cut for --weather-unit, no idea why that wasn't
+done already.
+
+6. REPOS: Added tazpkg (slitaz).
+
+7. CORE: Added /usr/etc, /usr/etc/inxi.conf.d, /usr/local/etc,
+/usr/local/etc/inxi.conf.d as possible default paths for inxi.conf files.
+Apparently IBM-Redhat is pushing for that change, which will ship first in
+Fedora. Also, the /usr/local/etc paths would let BSDs, that use /usr/local for
+non core, to put the inxi config in there instead, if they wanted. Though as far
+as I know, none of the BSDs is actively packaging inxi.
+
+8a. MACHINE: For -Mxx, show board part number (part-nu) if available. This
+usually comes from /sys product_sku or SKU Number in dmidecode, but can be
+sourced on other systems from different data sources.
+
+8b. MACHINE: Add (if detectable, bad data sources) device type for Elbrus.
+
+8c. MACHINE: Show board UUID with -Mxxx, if available. Filtered with --zu.
+
+9a. RAM: Added udevadm as possible non root RAM array/module data source.
+
+9b. RAM: Added for case of > 1 RAM system board array a Report: line for totals
+of arrays, capacity, used capacity, slots, used slots, eec, module type.
+
+10. CPU: more CPU microarch CPUID product IDs, for some future cpus as well.
+
+11. RECOMMENDS: Added wayland-info to display recommends now that it finally hit
+the repos.
+
+12. DRIVES: More disk vendors, new ID matches! Yes, it never ends, like the Way,
+like a river flowing from the mountains, like the sun and the moon...
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1. DOCS: data/audio: renamed and removed some stray gz files.
+
+2a. INFO: split into up to 3 separate primary lines, Memory, Power/Process/Init,
+Packages, depending on verbosity levels. This really cleans up something that
+has gotten increasingly messy and random over the years as features were added.
+
+2b. INFO: -Ixx triggers wakeups, instead of -Ixxx. Also, -Ixx triggers the
+parent Power: item that contains uptime:, wakeups:, and all the other power
+items from -Ixx and higher verbosity levels.
+
+2c. INFO: Compilers: changed order of detected compilers to be alphabetic
+(clang, gcc, zigcc), now that zigcc added might as well make it not gcc-centric
+as in past.
+
+3a. OPTIONS: -W/--weather-location are removed, and location is merged into -w
+[location], thus freeing up a redundant use of a primary single letter for a
+feature. Also, upper case letters were supposed to be used mainly for core,
+unique, features, not just a secondary feature of a secondary feature. Lower
+case only is what should have been used, like with -s. I am guessing that in
+inxi bash/gawk, I could not handle optional args, and thus had to use
+lower/upper, one for no arg, one for arg.
+
+3b. OPTIONS: -V is deprecated, and will show message. --vf/--version will
+activate full version info, along with --vs/--version-short for the 1 liner
+special short version.
+
+Also done to reclaim an upper case primary letter. If nobody complains, will
+remove -V next release, if someone complains, will keep -V / --version and
+remove deprecation message.
+
+-V is removed from help/man however so new users won't guess to use it, meaning
+eventually we can get rid of that -V and free it for better use.
+
+3c. OPTIONS: --gpu, --nvidia, --nv are removed. Those were replaced by -Ga a
+while ago. They were only temporary options used when the feature was first
+created, when it was not sure to remain.
+
+4a. SYSTEM: Display Manager (dm:) now is dynamically assigned, in cases where no
+dm but a login/seat manager like seatd, elogind running, which is more common
+with Wayland starts, now shows lm: (login manager) instead if one was found.
+Goes with CODE 3c refactor.
+
+4b. SYSTEM: changed Desktop info: to with: (for bars, docks, menu, panels,
+trays), which is more accurate, and switched info: to advanced de data, like KDE
+frameworks.
+
+4c. SYSTEM: changed output order, put wm: after de tk: info: and before with:.
+This turns it into a sentence: DE: + tk: + info: + wm: + with: + tools: + dm/lm:
+
+5. CORE: Configs::set() had wrong paths testing for config files, missing the
+.conf in inxi.conf.d. The old version was an accident. Just on off chance anyone
+actually used the wrong path, leaving those in the config path tests, but
+removed from man/options etc.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1a. DOCS: docs/inxi-graphics.txt: added ANDROID DATA, following some new
+information and research re Android display/compositors. Also refactored the doc
+file, and added more and better navigation and organization, particularly for
+DISPLAY SERVER DATA and MONITOR DATA. Moved COMPOSiTOR DATA to
+inxi-desktop-wms.txt.
+
+1b. DOCS: docs/inxi-distros.txt: updated for more distros and system base info.
+
+1c. DOCS: docs/inxi-power.txt: power state, screensaver/locker data.
+
+1d. DOCS: docs/inxi-tools-mapping.txt: added POWER section for screensaver/
+lockers.
+
+1e. DOCS: docs/inxi-values.txt: reorganized, improved navigation and
+organization. Ongoing updates to values for new features and debuggers.
+
+1f. DOCS: docs/inxi-init.txt: added BusyBox init, updated Upstart with warnings
+about pre-tests required.
+
+1g. DOCS: docs/inxi-desktop-wm.txt: These upgrades were done in conjunction with
+the related refactors, particularly of PsData and ProgramData.
+
+*added DISPLAY/LOGIN MANAGERS section, and documented all the dm/lm used. This
+goes with refactor into DmData of CODE 3c.
+
+* Added COMPOSITOR DATA (moved from inxi-graphics.txt) to make easier to match
+up wm/compositor data.
+
+* Added DESKTOP/WM INFO TOOLS itemized bars, docks, launchers, panels, menus,
+trays.
+
+2. DATA: data/audio: added huge collection of audio datasets from mrmazda.
+Thanks!
+
+3a. MAN/OPTIONS: Updates for power data for -Sxxx/-Sa, -Ixx/-Ixxx/-Ia.
+
+3b. MAN/OPTIONS: Removed references to -V, -W options, merged -W with -w.
+
+3c. MAN/OPTIONS: Edits, fixes, proofreading corrections of issues that have
+crept in over time.
+
+3d. MAN/OPTIONS: Removed --gpu, --nvidia, --nv, which were merged into -Ga a
+while ago.
+
+3e. MAN/OPTIONS: Changed gcc specific compiler to compiler generics, since now
+the old gcc\-centric compiler data supports clang alt versions, and zigcc.
+
+3f. MAN/OPTIONS: Updated -m for new udevadm DMI RAM data source.
+
+4. OPTIONS: Fixed some indentation errors.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1. Fixes 1, 2 were both due to some undefined values being improperly handled. 2
+was odd because it's literally never shown up before (using regex on undefined
+hash key), but it was a mistake in 3.3.31, just a Perl language thing that
+didn't do what I thought it would do..
+
+2a. GRAPHICS: xrandr_data(): switched to direct qx() for xrandr data, this
+allows checking for error return, which allows using --prop, which was not
+supported until xrandr 1.2 (~2009). Debian Etch had 1.1, for example. Also
+switched to array data since it's local to function. This is to get
+connector-id.
+
+2b. GRAPHICS: map_monitor_ids() now first tries to map via connector ID, and
+only falls back to the less reliable mapper tests if a match failed.
+
+2c. GRAPHICS: abstracted away from Xvesa only tests to TinyX X server tests.
+Note that so far only Xvesa appears to have an API via -list command.
+
+2d. GRAPHICS: failed to set empty array ref to $x_drivers when --force wayland
+is used, which made the @$x_drivers tests fail. Only devs would ever see this.
+
+3a. SYSTEM: DistroData: made debian_id() also support devuan ID via switch.
+Added redundancy testers for os_release codename append as well, using same
+logic. This refactor also removed some tests that would never have been true.
+
+3b. SYSTEM: main::get_display_manager(), had a silly error with creating
+globbing pattern that could have made it fail in the case, > 1 directories used
+to glob; refactored get_display_manager into DmData, which now also handles
+Display Managers and Login Managers, like greetd, seatd, elogind.
+
+3c. SYSTEM: DesktopData:
+* Changed DesktopEnvironment to DesktopData, to be more consistent.
+
+* Reordered, renamed subs, organized entire package to be more maintainable and
+consistent with newer inxi style.
+
+* DesktopData::wm_ps_xprop_data(). Reversed order, first now does ps tests, then
+xprop, was getting false detections for blackbox.
+
+* DesktopData::de_wm_debugger(). See 4c.
+
+* DesktopData: improved methods for getting gtk/qt desktop data, using new
+ProgramData::full version data return coupled with item_from_version(), avoids
+extra subshells to get the same data we already collected, but threw away.
+
+* DesktoppData::item_from_version(). Works with new ProgramData::full() option to get
+full version data ref returned, this avoids making multiple subshell calls to
+get two bits of data from same thing. Used for GTK and Qt data currently.
+
+* DesktoppData::set_xprop(): Fully refactored all xprop data to be more
+maintainable and clean.
+
+3d. SYSTEM: changed CompilerVersion which is for kernel compiler to the more
+obvious KernelCompiler, then moved it with the other kernel data tools.
+
+4a. DEBUGGING: SystemDebugger:
+
+* display_data(): added in xrandr --prop/--verbose to match upgraded xrandr data
+parsing.
+
+* system_data(): added fruid_print, udevadm commands.
+
+* system_files(): added/proc/bootdata.
+
+4b. DEBUGGING: added @dbg switches:
+
+* --dbg 58: $power data.
+
+* --dbg 59: $desktop data array (long overdue, no idea why that was left off).
+
+* --dbg 60: display_mamager $found].
+
+* --dbg 61: PsData::set_cmd(), print out @ps_cmd result working ps data.
+
+* --dbg 62: $compilers main::get_compiler_data().
+
+* --dbg 63: DesktopData::de_wm_debugger() for ps wm/comp/de output, and for
+DesktopData step by step results, so we know what detected what and how.
+
+* --dbg 64: ProgramData::version() print out full version data block.
+
+* --dbg 65: PackageData: print out raw %pms hash.
+
+5. ERROR HANDLER: Added option-deprecated, option-removed items, for -V, -W,
+--gpu/--nvidia/--nv type change/remove scenario.
+
+6a. CORE: fixed two stray redeclares of $start in OpticalItem::get() and
+RepoItem::get() which Perl 5.008.0 correctly notes is redeclaring it, but for
+some reason all newer Perl's accept. Funny things that show up testing on
+ancient systems, in this case, I'd say the original Perl was right and the new
+one is allowing something to happen it should not. Also changed $start in
+PartitionItem::set_filters to $begin to avoid that pussible clash.
+
+6b. CORE: Added filter type to main::filter, that way it can be used for other
+filters, like filter-uuid for non partitions.
+
+6c. CORE: Full ps logic refactor: PsData package created, merged in old
+set_ps_aux, set_ps_de_wm and changed them to methods set_cmd and set_de_wm.
+Refactored set_cmd to be much more robust and handle busybox automatically.
+
+* Changed global $load{'ps-aux'} to $load{'ps-cmd'} which makes more sense since
+that is what it was loading.
+
+* Old busybox failed if you supplied it with standard ps args, but new busybox
+accepts and ignores them. Now inxi checks if busybox ps, then dumps the args,
+and sets a busybox switch to allow for more ps data for busybox ps, which will
+be used to detect TinyX screen dimensions.
+
+* Got rid of global $b_busybox_ps and test for that, it is not used anymore.
+Added switch for busybox to use more columns of ps to try to trap -screen
+resolution for TinyX servers. Only some show that in ps.
+
+* Optimized subsequent uses of @ps_cmd by dumping stuff inxi will never need,
+like browsers, various servers, etc. Also run uniq() on result since we only
+nned one instance of each command for subsequent tests.
+
+* Switched to using full %ps_data, including for header position counts, which
+helps make much more robust odd ps types that might have CPU or RSS or MEM
+but not in the expected order, or incomplete. Before relied on hoping it would
+work and be consistent, which is not the case for BusyBox ps. Now all the hard
+coded indexes are dynamically set, using the header positions grabbed in
+PsData::set_cmd(). Specific detections added: info-active, tools-active,
+tools-test to avoid duplicating test arrays globally.
+
+* Got rid of @ps_gui global, replaced fully with granular de/wm/comp $ps_data
+hash arrays, which are then assembled as needed in each section, desktop and
+compositor, that might use them. This allowed, finally, for getting rid of all
+those redundant wm/comp items, now the wm/comp/de ids are set in only one place,
+PsData::set_gui(). This had been a long standing problem because I would forget
+to update one set of wm/comp, and had to do loops over and over when all that is
+required now is the initial searches through @ps_cmd, which is also much
+shorter, containing only the stuff inxi will need to check.
+
+Now to add a detection, wm, comp, tool, info, dm item, just need to add it in
+one place, ps_de_wm, and there are also no repetitions in there, which there
+were before. I expect this will make it much easier and less error prone to add
+new items to the various lists.
+
+* Added PsData::set_dm() to handle fallback dm detection, when none found in
+/run type directories. Only fires when nothing else found.
+
+* Added PsData::set_power() to handle power daemon detections.
+
+* Added --dbg 61 to print out @ps_cmd in output section, where it's also logged.
+Leaving it out was an oversight.
+
+6d. CORE: Program data refactor into package: ProgramData
+
+* Converted program_{data,values,version} and related subs into package
+ProgramData with public methods full(), values(), version().
+
+* Moved the entire package code block into the Items Data generator section.
+
+* Moved more program version that used hardcoded values in the caller to use
+full() and set_values() data instead, wherever practical.
+
+* Made version() use array refs from start to finish, and dumped the old method
+of using open on the text block from file or program version command result. Not
+clear why I ever did it that way, probably I did not understand refs when that
+was originally translated.
+
+* Added version data array ref return option, useful to avoid having to make
+double calls when getting stuff like toolkit version. Used for example in
+DesktopData::item_from_version().
+
+6e. CORE: Corrected paths for development fake data files, I'd forgotten to use
+$fake_data_dir global in many places, now all fake data paths use that single
+source, which can be changed using config or --fake-data-dir option.
+
+6f. CORE: main::grabber(): made sure all commands for this include the proper
+redirect, usually 2>/dev/null, several were missing that, which could in theory
+have led to visible error output on the screen.
+
+7a. INFO: InitData: got rid of redundant readlink /sbin/init, that's now read
+at first to $link, which is then what is tested in all following tests.
+
+7b. INFO: Refactored get_gcc_data() into get_compiler_data, which now supports
+gcc and clang to do FIX 9. Cleaned up, switched to ProgramData::full(), fixed
+weak globbing pattern, fixed broken compiler alt version exclude default
+installed compiler version.
+
+8a. CPU: Refactored, now all cpu fake data files are set in
+CpuItem::set_fake_data(), makes it easier to manage.
+
+8b. CPU: a change in either kernel /sys or Perl made Perl return udefined value
+where before it returned '' in cpuinfo data() (now cpuinfo_speed_sys()) speeds.
+
+8c. CPU: split out cpuinfo_speed_sys() from cpuinfo_data().
+
+9a. RAM: refactored dmidecode_data module data into separate functions so they
+can be used by udevadm_data_process as well. Made process_locator,
+process_manufacturer.
+
+9b. RAM: refactored the speed logic, now uses raw numeric plus units, so they
+can be worked with then reassembled more readily.
+
+9c. RAM: refactored speed_mapper, BSD matching table, to avoid loading entire
+mapping table each time. Brings logic closer to Linux logic.
+
+9d. RAM: refactored ram_output, split out arrays_output, which now handles
+--memory-short/--ms, and case of > 1 array detected, same format for both.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Tue, 30 Jan 2024 18:47:20 -0700
+
+================================================================================
+Version: 3.3.31
+Patch: 00
+Date: 2023-10-31
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+Packagers: remember, inxi repos and issue reports are now on codeberg.org - make
+sure to change your package scripts and URLs. Github will be mirrored for inxi
+for a little bit more, maybe I will extend it one more quarter depending, but
+source repos should be changed.
+
+--------------------------------------------------------------------------------
+
+A small point release, mainly for fixes and bugs, plus a few minor matching
+table updates. Also some core tools updates, which make supporting gpu devices
+easier over time, particularly nvidia ones. Also some gpu data updates, new
+nvidia 545, which was unexpected, came out, extending the time to next legacy by
+some months.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. GRAPHICS: GPU DATA: codeberg user malcolmlewis who also posted both the first
+pinxi issue, and the first codeberg issue. I had not thought nvidia would forget
+to add their own device IDs to their lists, but they did. This prompted an
+upgrade to the gpu_raw.pl/gpu_ids.pl to better handle manual add files for
+Nvidia, as well as better overall consistency for gpu data files and processing.
+
+2. SYSTEM: Wakeups: Mint user senjoz for alerting me to the well done but
+unfortunately localized to mint forums report on the wrong wakeup count report,
+because the data source was not what I thought it was.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1. Any distro forum person who finds issues related to inxi maybe being wrong or
+operating from false assumptions in terms of data sources should ideally find a
+way to report these issues directly, either via a codeberg issue, an email, or
+something else. It's not possible or practical to track every forum that uses
+inxi to debug user issues, so if members of those forums can be more proactive
+in terms of sending what appear to be valid issue reports to the inxi project,
+that will help a lot.
+
+2. GRAPHICS: GPU: no data for things like Biren and other non AMD/Intel/Nvidia
+GPUs. If you are into GPUs, by all means, help us out here!
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. INFO: main::get_wakeups(): I'd say that despite in the past largely being
+correct, using /sys/power/wakeup_count is a bug, but a bug that is excusable
+because the docs are just too opaque about what this thing actually refers to.
+My assumption re its meaning was clearly wrong.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. INFO: main::get_wakeups(): Issue reported via a Mint forum posting which I
+was alerted to.
+
+https://forums.linuxmint.com/viewtopic.php?p=2378107#p2378107
+
+This would have made it into inxi 3.3.30 easily since the patch is changing file
+name, but I unfortunetly did not become aware of it until right after the
+release, On my system, for example, with systemctl suspend instead of the not
+working xfce suspend from gui, I get 7 wakeup_count type events counted for each
+suspend event. On another system I have, almost same everything, except fully
+functioning xfce suspend feature, the success and wakeup_counts are matched.
+
+I found a value of 49000+ digging through my datasets, and I can find no
+pattern, nor can I find this clearly documented, so the behavior is simply going
+to be use the value, including 0, from /sys/power/suspend_stats/success and
+using it if it is defined, and getting rid of /sys/power/wakeup_count completely
+as a data source, which I am now no longer sure at all about the meaning of. 1
+of my systems has 7 events per resume, one, almost the same setup, has 1.
+
+2. GRAPHICS: GPU DATA: Many nvidia fixes, device ID lists updated and corrected.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1a. PARTITIONS: added puzzlefs, atomfs to excludes. It's unclear, but both sound
+like they are like isofs or something like that.
+
+2a. GRAPHICS: GPU DATA: added Nvidia Pascal, Hopper, Lovelace device IDs. See
+Code 1 for fixes to detections. Added AMD, Intel newer GPU IDs, going with Code
+1 and GPU data fixes.
+
+2b. GRAPHICS: GPU DATA: updated lists, added Nvidia current EOL data, added
+newer kernel/X.org last supported. Added two more memssage types for current,
+legacy messages. Found a site that lists EOL for the drivers, that helps.
+
+2c. GRAPHICS: GPU_DATA: added new 545 driver IDs, updated nv current to 545
+
+3. SYSTEM: Distro: Added ubuntu noble 24.04 system base ID.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1. DATA: pinxi/tools/lists: made file names consistent for gpu data types.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1. DOCS: docs/inxi-graphics.txt, docs/inxi-partitions.txt - ongoing updates for
+features. More GPU data added, new file system types.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1a. GRAPHICS: GPU DATA: pinxi/tools/gpu_raw.pl, pinxi/tools/gpu_ids.pl. Upgraded
+to enable basic manual additions to nvidia drivers. Also fixed detections for
+Hopper and Lovelace, those were too tight and I missed some device IDs there.
+
+Redid tools/gpu_raw.pl and gpu_ids.pl to have the more predictable file names.
+
+Also changed the file names to be consistent for nv data in pinxi/tools/lists/
+ gpu.[amd|intel].full
+ gpu.[amd|intel].full.sorted
+ gpu.[amd|intel].manual
+ gpu.amd.github
+ gpu.intel.com
+ gpu.nv.[driver].full
+ gpu.nv.[driver].full.sorted
+ gpu.nv.[driver].manual
+ gpu.nv.[driver].raw
+
+This let me bring all the lists up to date, and some manual fixes added in to
+some driver sets.
+
+1b. GRAPHICS: GPU_DATA: pinxi/tools/gpu_ids.pl - updated for Nvidia: new
+messages, current eol, filled out legacy drivers with their eol based on last
+nvidia driver release date.
+
+2. CORE: there were some pointless globals being used, as part of the overall
+effort to get rid of globals where sensible, else move them into hashes/arrays,
+makes code easier to maintain long term.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Tue, 31 Oct 2023 13:08:12 -0700
+
+================================================================================
+Version: 3.3.30
+Patch: 00
+Date: 2023-09-25
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+PACKAGERS! inxi repos are moved to https://codeberg.org/smxi/inxi
+
+The repos will mirror to github for a short amount of time, until after 3.3.30
+is released, then I am probably going to do some big changes in the structure of
+the inxi repo. Make sure to update your packaging tools and scripts for this
+change.
+
+--------------------------------------------------------------------------------
+
+Finally, a huge upgrade for Wayland future proofing, and other futures that are
+maybe coming, by adding EGL API, and Vulkan for good measure. This should handle
+wayland finally, that's been a stub forever, but finally realized eglinfo was a
+thing, and that vulkan as well could be a contender to replace OpenGL, at least
+that's what Mesa says on their site, and they should know.
+
+This handles one of the longest standing weak points of inxi graphics, being
+completely X11-centric, even though wayland support exists fairly extensively,
+but this glxinfo dependent feature was a niggling annoyance, now it's fairly
+ambivalent about which api tool you throw at it, the hardest is to give the
+right message for no data, or incomplete data. Note that eglinfo supplies at
+least software rendering out of X11 or Wayland, so we can now get some API data
+in console, including if supported, OpenGL data. Not all of it, but some of it.
+
+Also since now all the docs are split and granular, with the Graphics API
+upgrades, added data sample files from glxinfo, eglinfo, vulkaninfo, and vainfo
+for good measure, just to have some of the latter. This is one of the first time
+all the data used to develope a feature, docs for that feature, and the feature
+itself, are being shared and released at the same time.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1a. GRAPHICS: API: Arch user Chrome30 on github for requesting vulkan data, and
+providing the initial datasamples that made it possible to think about this new
+API feature.
+
+1b. CheckRecommends: Display packages: mrmazda, a frequent helper, checked and
+updated OpenSUSE and Fedora vulkan/egl/glx API tool package names. Those have
+been a bit fluid and many of the names I had were not right.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1a. GRAPHICS: nothing is perfect, for sudo/root the detections fail for OpenGL
+API messages, but fallbacks will make it a bit nicer than it was, with some
+data, instead of none as before.
+
+1b. GRAPHICS: API: I'm assuming that the greatest EGL version number found is
+the actual version, and lower versions are what that platform supports. This is
+an assumption, not a known fact, but finding this stuff clearly documented tends
+towards near impossibility, or takes forever to determine, so that's the
+assumption that is being used. Correct via issue and clear explanation with
+links to resources if this is incorrect.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. Nothing to speak of.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. PARTITIONS: had wekafs as a zfs type fs, it's not, it's more like NAS, cloud.
+Added to distributed list, and removed from zfs|btrfs|hammer list. I know, I
+know, will it ever matter? Probably not. But just in case, wouldn't want your
+local machine to report with petabytes of storage now would we!
+
+2. CheckRecommends: corrected some Fedora, SUSE package names.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1a. SYSTEM: DistroData: added Bodhi id method, /etc/bodhi/info file which is
+similar to /etc/lsb_release, updated system base detection as well. System base
+comes from /etc/os-release.
+
+1b. SYSTEM: DistroData: Added Nitrux system base (debian). Why they try hide
+this is beyond me. Maybe because they are not using a real PM, and don't include
+apt, who knows.
+
+2a. GRAPHICS: new nvidia gpu ids.
+
+2b. Graphics: EGL API data:
+* Shows eglinfo missing if appropriate, no data messages if appropriate.
+* -G shows EGL version(s), drivers, active platforms.
+* -Gx adds active/inactive platforms as sub items of platforms.
+* -Gxx shows platforms by platform, with egl version, driver. EGL version only
+shows if there were more than 1 detected, otherwise it shows with EGL v:
+* -Gxxx shows hw based on driver, if found, like vulkan.
+
+To avoid excess verbosity, does not show renderer OpenGL name per platform
+because it would be way too long and repetetive. And besides, that would show
+in OpenGL anyway, more or less, unless there are two different GPUs, which is a
+case that is not fully handled.
+
+2c. GRAPHICS: OpenGL data:
+* If glxinfo not present, or with null output due to root/no display, and if
+eglinfo available, and has OpenGL items, will populate most of OpenGL API with
+data, except for Direct Rendering and GLX version. Shows appropriate messages
+indicating it's EGL sourced for console, root, no data, or glxinfo missing.
+* -Gx adds GLX version, if detected.
+* -Gxx add: ES version, if detected; device-ID, if available. Also adds
+display-ID, if Display-ID was not found in the Display line (which probably
+means that xdpyinfo or xrandr were not installed). Does not always show since it
+already appeared in Display line if it was discovered.
+* -Ga adds device memory, and unified memory status (yes/no).
+
+2d. GRAPHICS: Vulkan API data:
+* Shows appropriate messages if vulkaninfo present, but no data found.
+* -G shows Vulkan version, drivers, and surfaces.
+* -Gx device counts.
+* -Gxx adds device by id, type, driver report.
+* -Gxxx adds layer count; adds device hardware vendor, based on mesa driver. Not
+for nvidia driver, since that is self evident. Goes away with -Ga if device name
+exists.
+* -Ga adds full device report, including per device names, ids, drivers, driver
+versions, surfaces.
+
+3. UPDATE: Because the smxi.org server no longer accepts TSL 1.1 based HTTP
+requests, added for extreme legacy systems a new update option, -U 4, which
+uses direct FTP download from smxi.org ftp server. If system set to default to
+perl downloader HTTP::Tiny it switches to using a non perl downloader
+automatically, like wget or curl.
+
+4. CPU: Microarch: got early zen5 possible IDs. Both Intel/AMD may have rough
+ID working well before they ship in public. CPU stuff has slowed down a lot,
+the 4,3n nodes are not easy, obviously.
+
+5. DRIVES: Many more drive vendors and drive IDs.
+
+6. RAM: More RAM vendors. Note that it's not unusual for a Drive vendor to also
+make RAM, and vice versa.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1a. GRAPHICS: For API, show OpenGL mesa-v: x.x.x separate from main API v:
+string. Also only shows the actual API version with v: now, like v: 4.5. Also
+shows vendor: nvidia v: 340.23 for nvidia, without mesa. Falls back for
+unhandled cases or syntaxes to the whole version string for v:.
+
+1b. GRAPHICS: For OpenGL, shows compat-v: always if present, that was a mistake
+not to show it unless -Gx, since otherwise you'd think you are running a
+different version. Not a common situation, but on legacy hardware, can happen.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1a. DOCS: docs/inxi-cpu.txt - reorganized into more coherent sections, like with
+like, etc. Added better top Sections navigation since there is so much data.
+
+1b. DOCS: docs/inxi-resources.txt - moved last code tricks to
+docs/tips-tricks.txt.
+
+1c. DOCS: new docs/ files inxi-battery.txt, inxi-debuggers.txt,
+inxi-devices.txt, inxi-kernel.txt, inxi-machine.txt, inxi-network.txt,
+inxi-raid-logical.txt, inxi-start-client.txt, inxi-tty.txt, inxi-weather.
+
+These new files cleaned out docs/inxi-data.txt and docs/inxi-resources.txt,
+which are now merely placeholder files, and have no data in them beyond pointers
+to the actual data files.
+
+1d. DOCS: docs/inxi-custom-recommends.txt updated for SUSE/Fedora packag name
+fixes and new eglinfo and vulkaninfo items.
+
+2a. DATA: moved more data from non public data to shared. Refactored directories
+to be better organized, and to follow the overall inxi data structures better.
+
+2b. DATA: added many more eglinfo, glxinfo, vulkaninfo to data/graphics. Also
+added some clinfo, vainfo just in case decide to support those APIs.
+
+3a. MAN/OPTIONS: updated for new graphics API features, new verbsity features,
+etc.
+
+3b. MAN/OPTIONS: added -U arguments for man, for some reason I'd left those out.
+Also removed options references to -U 1, 2, because those should never be used,
+if those versions of inxi even exist, they are ancient. Added -U 4 option, and
+explanation of when/why to use it.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1a. FAKE DATA: updated paths for fake data to reflect data reorganization.
+
+1b. FAKE DATA: Added --fake egl,glx,vulkan for GRAPHICS API.
+
+2. GRAPHICS: Fully refactored opengl_output, moved to gl_data/opengl_output.
+Added egl_data, egl_output, and vulkan_data, vulkan_output, and some other
+tools.
+
+3. UPDATE: if downloader is set to 'perl', aka, Tiny::HTTP, and -U 4 is used,
+which is a direct FTP download of the inxi/pinxi files, tiny is disabled, and
+the next available downloader (wget/curl/fetch) is used instead.
+
+4. DEBUGGER: added clinfo, eglinfo, es2_info, vainfo, vdpauinfo, vulkaninfo.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Mon, 25 Sep 2023 15:03:45 -0700
+
+================================================================================
+Version: 3.3.29
+Patch: 00
+Date: 2023-08-15
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+Some significant bugs, 1 showstopper for FreeBSD, and one universal one for USB
+network devices, and possibly some other USB device types. Also some nice new
+features.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. SYSTEM: Github user chromer030 in issue #285 - a very nice small enhancement
+to -Sxxx line, adding kernel clocksource, and with -Sa, adding available
+clocksources. I wish all issues were this clean and easy to implemment, with
+such clear benefit.
+
+2. BLUETOOTH: Github user chromer030, issue #286 - extending and adding
+bluetooth report feature. This required refactors and some cleanup of bad logic
+to make -E more able to handle new data sources, and also made me fix the docs
+and add debugger data files to make testing changes for various bluetooth
+datasources easier. Adding btmgmt turned out to have a lot of long term benefits
+to the bluetooth feature and internal inxi logic, I hadn't realized how hacked
+on bluetooth feature was, but code review showed it clearly.
+
+3. SYSTEM: Github user oleg-indeez found a break in FreeBSD compiler data, 2
+glitches, one made inxi crash due to is array test on undefined reference, the
+other maybe a bad copy paste in the past that assigned compiler data to wrong
+hash. See CODE 3 for details on the ref issue.
+
+4. SWAP: Github user chromer030, again, issue #290 suggested some swap
+zram/zswap data enhancements, seems good, so thanks.
+
+5. UsbData: Slackware/Linuxquestions.org poster J_W for posting on a device
+missing in his output as of 3.3.27 inxi. This exposed bug 3, which usually was
+npt visible since the fallback was catching most of the network matches, but
+since he had a TP-Link, and it went missing, it triggered the issues, and also
+exposed the inconsistent upper/lower case use in device type from kernel.
+
+6. NETWORK: Slackware user babydr on linuxquestions.org tripped a bug in
+network, was not counting correctly to limit IP list. Led to showing limit
+message on 10th row of network report, not 10th IP of a device. See Bug 4.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1. Nothing new.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. BLUETOOTH: with hciconfig, would show wrong LMP/HCI version because either
+the syntax changed for those strings, or it was wrong always. I think it changed
+because this worked correctly at one point. Should now show the right hci/lmp
+versions, and the bluetooth version as expected for hcicconfig/btmgmt.
+
+2. SYSTEM: CPU compiler broke for FreeBSD 13.2, caused by bad test for undefined
+array in CompilerVersion::version_bsd(), and also, assigned kernel compiler data
+to %dboot instead of %sysctl hash. Thanks oleg-indeez for spotting that one and
+figuring it out.
+
+3a. UsbData: Failure to use /i caseinsensitive on regex led to failure to detect
+USB type using standard defaults, but then a further regex error, subtle, missed
+a | between two elements of a pattern, led to the last fallback case for network
+detection failing. This was coupled with a change in the Kernel, which now uses
+Uppercase first sometimes, and sometimes lowercase first. I think that's a
+change anyway. This resulted in some usb type hashes failing to load specific
+devices, network in this case, TP-Link, which was the fallback pattern that
+broke.
+
+3b. UsbData::assign_usb_type() improper nesting of tests led to failures that
+should not have happened, like a bluetooth device cascading down to network.
+
+4. NETWORK: IP limit was limiting based on total row count, not the actual count
+of IPs for that device. Not sure how that slipped up. Now correctly limits the
+IPs, not the previous total rows in Network report. Thanks babydr / Slackware
+forums for finding yet more issues.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1a. BLUETOOTH: added in switches for fake bluetooth data for all bluetooth data
+sources.
+
+1b. BLUETOOTH: made --bt-tool load $force{[tool]} to be consistent with rest of
+logic in inxi for forcing use of specific tools. No idea why I made a standalone
+one only for Bluetooth.
+
+1c. BLUETOOTH: the HCI/LMP version generators were mixing up bluetooth version
+string and LMP, leading to wrong results. See BUGS 1. I think this was a syntax
+change because I would not have generated this originally if the syntax had not
+worked, at least I don't think I would have. See also DOCS DATA item, added in
+samples for dev purposes to avoid this type of issue in future.
+
+2. UsbData: Device type from /sys could be upper/lower case first, but inxi was
+not testing for anything but lower case, which would lead to fallback tests for
+Bluetooth, Network, at least, maybe others. This goes with BUG 3, which exposed
+a small torrent of such potential failure cases. The fallback block of regex is
+really only designed to catch the few that don't get caught by the generic type
+tests.
+
+3. NETWORK: UsbData::set_network_regex(). Bad regex caused bluetooth device:
+"Intel Bluetooth wireless interface" to trip an overly loose regex for wireless.
+See BUG 3b. The real issue was incorrect test nesting which led to a bluetooth
+device falling down to network regex, which it should not have done. It also
+failed test the product name for bluetooth, which led to failure as well.
+
+4. SWAP: Was failing to capture some zram syntaxes, regex was too tight. Failed:
+/run/initramfs/dev/zram0.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1. SYSTEM: added kernel current clocksource for -Sxxx, and alternates for -Sa.
+
+2. BLUETOOTH: added btmgmt as first fallback to hciconfig, that one also
+supplies bt version via lmp version, like hciconfig. Note this tool has very
+little useful information.
+
+3. Added back in discoverable, active discovery, and pairing status with -Ea.
+This data is also crudely available from btmgmt but I would not bet on those
+items actually being right. I'm not totally convinced that's good data, so
+making it admin for now. Put these in a 'status:' parent container.
+
+4a. SWAP: Added zswap enabled, compressor, max_pool_percent for -ja swap general
+features line. If no zswap data and Linux, shows 'N/A'.
+https://www.kernel.org/doc/Documentation/vm/zswap.txt
+
+4b. SWAP: Added zram comp_algorithm max_comp_streams to -j per line report, only
+for zram, of course.
+https://docs.kernel.org/admin-guide/blockdev/zram.html
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1. None that are obvious.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1. DATA: Added new data/bluetooth/, with several sample 'btmgmt info' and
+'hciconfig -a' outputs for debugging and reference purposes. These work with
+the revised debuggers and force/fake data switches for bluetooth. Should add
+some bt-adapter --info samples too to make testing/debugging easier.
+
+2a. DOCS: Made new docs/inxi-bluetooth.txt doc.
+
+2b. DOCS: Moved more data out of inxi-data.txt and inxi-resources.txt, into
+inxi-bluetooth.txt, tips-tricks.txt, man-pages.txt. While I'm not going to do it
+all at once, I am trying to move relevant data into granular doc file as I hit
+that during dev.
+
+2c. DOCS: Updated and organized docs/inxi-tools-mapping.txt more, new mapping
+tools added. inxi has so many manually updated mapping tools that it's going to
+get more and more important that this document is accurate, and is updated when
+required.
+
+3a. MAN/OPTIONS: Added BT tools to --force lists, and updated --bt-tool list.
+Also added -Ea options, the status: stuff.
+
+3b. MAN/OPTIONS: Made consistent, lower case rpm, both PM type rpm and rpm as
+rotation were switching between RPM and rpm randomly.
+
+3b. MAN/OPTIONS: Updated for --force ip/ifconfig, --ifconfig.
+
+3c. MAN/OPTIONS: Updated for zswap, zram extra -ja data.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1. BLUETOOTH: added %force bluetoothctrl, bt-adapter, btmgmt, hciconfig, rfkill,
+and added checks to enable $fake{'bluetooth'} in the main callers for each type.
+This makes debugging and development a lot easier. Also removed the force tool
+block in CheckTools, no idea, again, why I did it that way only for bluetooth.
+
+2. CheckTools: got rid of set_forced_tools(), which was only used for bluetooth
+tools, and didn't fit with the rest of the core logic.
+
+3. SYSTEM: CompilerVersion: used array refs wrong, or rather, used refs wrong,
+which led to various errors that were confusing. Corrected to start out with an
+array ref, then to pass that as is, leaving it the same ref all through, for bsd
+and linux. This is the method inxi should have always used for passing array/
+hash refs around, create as ref, then pass around, and update, without assigning
+a new ref to it.
+
+I had failed to verify that the same ref was being used through the sequence.
+Unfortunately this error is probably very widespread in inxi, because no
+consistent rule was created and enforced from the first lines of Perl.
+
+4. UsbData: added source type to --dbg 6 output, and added --dbg 55 to output
+the per type arrays.
+
+5. NETWORK: IpData:: added --ifconfig/--force [ip|ifconfig], --fake ip-if to
+allow for basic debugging for -n / -i IP data sources. Not super useful since so
+much comes from /sys, but there was nothing there at all, which is weird for
+networking.
+
+6. SWAP: Changed to passing data using scalar references, not returning an
+array of the items, and got rid of the copies in the swap_data_advanced() tool.
+It's less readable, but incurs basically very little overhead, and with the new
+function / method arg lists I'm using more now, it's clear what the references
+are.
+
+7. IpData: got rid of extra array copies for push, pointless.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Tue, 15 Aug 2023 19:45:54 -0700
+
+================================================================================
+Version: 3.3.28
+Patch: 00
+Date: 2023-07-10
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+New version, new man. Continuing the Memory info rollout started in 3.3.27.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. Thanks to linuxquestions.org Slackware forums for poking around a bit at the
+new Memory total logic.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1a. MEMORY: The memory total: has to be synthesized in some cases, based on some
+math and educated guessing. When these guesses fall outside of predetermined
+ranges, inxi will show note: est. to let the user know the total was synthesized
+and possibly incorrect. For detected virtual machines, inxi does not try to
+synthesize the total because a VM can have any amount of RAM assigned.
+
+If superuser, and -m used, shows the real total from dmidecode if any RAM was
+found. Not all systems have DMI RAM data however, or have dmidecode installed.
+Will fallback to sythetic method in that case, which is usually right.
+
+1b. MEMORY: With the superuser /proc/iomem method, if on a VM and not using even
+GiB sized RAM ollocation, and -M is not triggered (which usually lets inxi know
+it's a VM), the total will get rounded up or down based on a set of rules. For
+example, 2.5 GiB real would become 3 GiB. I don't see any solution to this,
+either assume the /proc/iomem is right but needs rounding up, or assume the /sys
+block counts are right, or remove the feature.
+
+Shows note: est. in cases where the rounded total is greater than a dynamic
+factor difference from the internal total amount.
+
+2. GENERAL/GRAPHICS: The problem of users showing up, requesting a feature, then
+not doing any work, research, supplying energy, interest, and dare I say,
+passion - nothing, expecting 'someone else' to do the work for them, continues,
+sadly, with the recent request for vulkan data for Graphics. This appears to be
+a problem more with the modern generation of free software users, I don't
+remember this type of attitude 20 years ago, but I did watch it as it started
+getting more common. Demotivating to be honest, but maybe one day someone will
+show up who actually cares enough to help get the features they want developed.
+
+While I am leaving that up as a low priority feature request, I am not
+personally interested in that feature, nor is anyone else I asked, and given how
+much raw data there is, and how difficult it is to parse, I'll just leave it as
+an existing issue which might get work in a few years time, or not, basically
+will require someone showing up who actually actively cares.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. DISK: total: used: report could have had wrong results for used:, like used
+being > total: because the filter lists were missing some file systems for
+exclusion. More of a fix than a bug, but users might see it as a bug.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. INFO: get_gcc_data(): was showing same GCC version as main and alternate.
+Failed to filter out the discovered primary, that is. This is because usually
+name is gcc-11 but sometimes it's the whole version, like gcc-11.2.0, the full
+version string. This is the case in Slackware for example.
+
+2. SHORT: MEMORY: BSD: did not show '%' for memory used percent, just the
+number.
+
+3. DRIVES/PARTITIONS: PartitionItem::set_filters() added many more exclude
+types, that will help avoid both creating wrong disk used totals, and also not
+show label:/uuid: fields for filesystem types that don't have uuid/labels. There
+were a lot missing: encrypted, distributed, stackable, remote. Should clean up
+wrong disk used values in some cases.
+
+4a. PARTITIONS: PartitionItem::set_filters(). Added a lot of file systems, many
+fuse, distributed, stackable types.
+
+4b. PARTITIONS: Extended remote file system ID by fs, and added fuse fs for
+local mounts, like gvfs, mtp, ptp and many other variants, that's things like
+mounting apple partition, android, iphone, archives, etc. This should correct an
+entire class of source: ERR-102 outputs.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1. BATTERY: Added 'power' to battery report. That's the amount of watts its
+using at that moment, so not super useful since it's running inxi at that
+moment. But the data was there, so might as well show it. Only for -Bxx since it
+will be so variable. Shows after the charge/condition item.
+
+2. SYSTEM: DistroData: added Oracle id and system base. Added Springdale/PUIAS
+system base support. Note, unusually, Eurolinux, ScientificLinux 'just worked'
+re id and system base even though that had never been explicitly added. This is
+because their os-release file contains 'centos' string.
+
+3. SYSTEM: DistroData: Added ubuntu mantic minotaur to ubuntu id matching table.
+This only really is used by Mint, but there you have it. Also added Debian 14
+codename Forky.
+
+4a. MEMORY: Add total RAM from one of following:
+
+* /sys/devices/system/memory (if it's available). This directory has to be
+compiled into kernel, so is not always present. This source has advantage of
+being user readable. If out of set bounds, shows note: est. to let user know
+it's an estimate.
+
+* If superuser and /proc/iomme, gets the total from /proc/iomem using some
+tricks and synthetic methods, which in general is pretty accurate, but when out
+of the bounds set, shows note: est. to let user know results are only estimates.
+This overrides /sys total.
+
+* If -m and dmidecode data found, uses the real RAM module total. For Linux and
+superuser. This overrides iomem and /sys totals.
+
+4b. MEMORY: add iGPU RAM from /proc/iomem when detected. Requires sudo/root.
+
+4c. MEMORY: using the real -m/RAM total for memory total when available, since
+that is the actual value we want, not the estimated stuff from /proc/iomem or
+/sys/devices/system.
+
+5. RAM: added a long time oversight, lack of per array RAM installed size and
+occupied slots (modules). Those are now part of the Array line for each set of
+modules. Since total already shows in System RAM line above, the granular per
+array installed size total only shows if > 1 array is present, ie, almost never.
+
+6. DRIVES: disk vendors, added more matches and vendors. We'll know the world is
+changing in a significant way when no new vendors appear for a while, but that's
+unlikely in the near term.
+
+7. CPU: cpu_arch(), a few new ids added.
+
+8. GRAPHICS: new amd, intel, nvidia ids, updates to driver version etc.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1. SHORT: for Memory:, switched to using MiB/GiB/TiB, these numbers are just
+getting too big to be readable. This is also dynamic, if both used and available
+are the same unit, shows x/y [unit], otherwise shows x [unit]/y [unit].
+
+2. MEMORY: changed gpu: to igpu: to avoid confusing it with standalone gpu.
+Since only raspberry pi had gpu ram data before, almost nobody would have seen
+this in general anyway.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1. MAN/OPTIONS: Updated for -Bxx, battery power now.
+
+2. MAN: updated to better define where the System RAM: total:.. available etc
+come from, and what they refer to. Also added explanation in -m section about
+what the stuff is, and what the field names refer to.
+
+2a. DOCS: docs/inxi-ram.txt added, and more info moved from inxi-data.txt and
+inxi-resources.txt. Goal is to remove both those files and move all their data,
+and any new data, into granular inxi-xxx.txt files. Also moved some RAM data
+from inx-unit-handling.txt to inxi-ram.txt.
+
+2b. DOCS: docs/inxi-unit-handling.txt: updated with more ram / memory units,
+code, etc, to better fit with the concept of the inxi-unit-handling.txt doc.
+
+2c. DOCS: docs/inxi-partitions.txt: updated, added more sources for partition
+file system types, cleaned up, more useful as a reference now.
+
+2d. DOCS: docs/inxi-distros.txt: NEW, merged data from inxi-data.txt,
+inxi-resources.txt. Updated and added more info.
+
+2e. DOCS: docs/inxi-tools-mapping.txt split off from inxi-tools.txt, makes it
+easier to find the mapping functions and features, which are hard to remember.
+Also updated and improved its usability. This is kind of a key document because
+it's hard to remember all the mapping tools internally, and this also connects
+those tools to their relevant granular inxi-xxx.txt docs. Not that it will help
+get helpers for these tedious tasks, but one can always dream, can't one?
+
+3. DATA: data/graphics/ added for first vulkaninfo output file.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1a. RAM: Fixed an irregularity, for RamItem, it used MiB as internal unit, this
+was silly because inxi uses KiB everywhere else. This correction was relatively
+easy to do, and allows the values to be used by other parts of inxi, like
+MemoryData.
+
+1b. RAM: Added return of ram total for memory.
+
+2a. INFO/RAM/PROCESSES: When MEMORY active, now uses row reference to create the
+fields. For INFO, now uses MemoryData::row() to generate the row fields instead
+of doing the logic in the info line generator. This simplifies the processing
+and allows for more granular control of output.
+
+2b. INFO/RAM/PROCESSES: Added debugger switches --dbg 53 (show raw KiB/count
+values for /sys/devices/system/memory and /proc/iomem. Added --dbg 54, which
+shows per line size for iomem, in human readable units, and a final summary
+report of iomem and /sys data, this speeds up debugging.
+
+2c. INFO/RAM/PROCESSES: Added --fake iomem, --fake sys-mem for debugging and
+testing.
+
+3. MEMORY: MemoryData::short_data(): added so one tool generates output for all
+sources for short data. Easier to track and make consistent, and to make more
+granular and robust.
+
+4. DRIVES/PARTITIONS: PartitionItem::partition_filters(),
+PartitionItem::fs_excludes(): refactored into PartitionItem::get_filters(),
+PartitionItem::set_filters(). Cleaned up, organized better, made comments much
+more useful. Goes with DOCS 2c updates. Now there's just one sub that does this
+filter/exclude work, which makes it easier to maintain long term.
+
+5. GLOBAL: Used a trick I just learned, declaring variables in the bracket scope
+of a class, but not inside the package/class declaration. This makes it work
+like a static variable, which Perl 5.008 doesn't support. You have to use a sub
+inside the bracket scope to return the data outside that scope, but that is easy
+to do.
+
+6. MACHINE: Added return of b_vm for VM detection in MEMORY.
+
+7. SYSTEM: CompilerVersion: Failed to properly use references when passing
+$compiler around, not actually sure why it worked, but now is consistent.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Mon, 10 July 2023 14:00:04 -0700
+
+================================================================================
+Version: 3.3.27
+Patch: 00
+Date: 2023-05-07
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+Completion of the audio fixes and improvements of 3.3.26. Added less common
+sound servers like EsounD and aRts, and made state reports more accurate for
+ALSA.
+
+Major USB code and data upgrades/refactors. The USB changes prepare inxi for USB
+4, and adds lanes and Si/IEC speeds to the report. It is important to determine
+what USB mode you are running in with 3.x and 4. These changes conform more
+closely to how the USB consortium wants USB speeds refered to.
+
+With more robust USB data, this data now appears in a similar form as pcie: data
+for Devices, -A, -E, -G, -N, and for -D drives, as usb: plus rev, speed, lanes,
+mode, with the -xx/-a options, like pcie. This has been a long standing
+oversight and weakness of inxi USB and Device data, but now the two are fully
+integrated, including for drives, which was quite tricky to get working.
+
+Added netpkg and Zenwalk support to packages and repos. Also added repos support
+for sbopkg and slpkg, and updated package tools for Slackware.
+
+And more distros added to system base feature, and a few more for main ID.
+
+Improved --recommends report quite a bit, now it's more granular for missing
+packages and package manager reports, and also fixed a long standing missing
+current shell + version issue. Added the final package manager type, pkgtool
+(Slackware), that will be supported, which makes for 4, which is enough. Note
+that other package managers can be added following the documentation
+instructions for packagers, but this is enough for out of the box pm handling.
+
+Fixed a long standing oddity with how free / /proc/meminfo report MemTotal vs
+the actual physical RAM. I believe this issue also showed with GPU assigned RAM,
+but now for all but short form, shows Memory/RAM: available: ... used: ...
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. To the Slackware people at linuxquestions.org forums, who helped, again, on
+this audio feature, even finding current or not too old systems that use some of
+the new / old audio servers (EsoundD) running in the wild, which I never
+expected to see. And also for exposing some weak spots in the USB advanced
+logic, and helping with the sbopkg and slpkg repo logic and tools reports.
+
+2. To the Manjaro forum users, for providing cases that show where inxi can be
+improved. The audio server/api issue, the current USB 3/4 upgrade, were
+initiated by threads pointing to things that could be improved in inxi. So I
+guess the real thanks are for using inxi enough to trigger cases that show where
+it's weak or can be better. Note that this requires that I follow roughly their
+forums, however I only look at threads that seem like they might be of general
+interest, or which suggest a possible weak spot in inxi, and I don't follow them
+consistently. More reliable is to file github issues, since I will always see
+those.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1. DesktopData: at one point, BunsenLabs Debian OpenBox had XDG_CURRENT_DESKTOP
+set to XFCE, which it isn't, but inxi can't work around such hacks, plus I don't
+even know if Bunsen is around anymore anyway.
+
+2. DesktopData: CODE 1 reminds us that the time to depend on x tools like xprop
+for anything re desktop/wm detections is fast drawing to a close, true Wayland
+will not have xprop, unless it's running on xwayland, which is not something
+that should be relied on. Maybe recheck Moksha/Enlightenment which depend on
+xprop for version detection.
+
+The list of xprop detected wm/desktops in get_env_xprop_misc_data() is almost
+all X only wm/desktops, so those should be safe unless one of them decides to
+work on a wayland comositor.
+
+3. BSD: ongoing weaknesses in BSD data sources make maintaining feature parity
+impossible, but I am trying to get the BSD data as clean and consistent as
+possible. I wish this were not the case, but the fact is, /sys is expanding and
+creating excellent and reliable data sources with every major Linux kernel
+update, and so far nothing comparable has appeared in the BSDs. This is just
+reality, it's not a condemnation, but something like the /proc then /sys file
+systems are an excellent idea, well worth emulating.
+
+4. For the RAM available/total clarification, there's a slight issue because
+free/meminfo show MemAvailable as Free for use RAM, but dmesg shows available
+meaning what was available to the system during boot, minus the reserved
+percentage. Since we needed one term, available to System offers the closest
+in terms of technical precision without being too verbose. Technically available
+in this context means: total physical minus 'kernel code' minus 'reserved'.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. CheckRecommends: See Fix 6b, more or less a bug, but really just a fix.
+
+2. AUDIO: for USB devices, put extra data into row 0, no matter which row the
+USB device is. This led to the extra data for USB being assigned to the wrong
+row. Sigh.
+
+3. OptionsHandler: When show{'ram'} was set, for bsd, set use{'bsd-raid'}, which
+makes both show raid and ram fail for BSD. Oops. User mode RAM data only seen in
+OpenBSD so far. This made loading $dboot{'ram'} fail, and any raid as well,
+sigh, unless -m was also tripped.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. DistroData: typo for Arch base: was ctios, was supposed to be ctlos.
+
+2a. DesktopData: found case where xprop -root not present (Void Linux), so xfce
+test failed. Split to new function dedicated to xfce detection that doesn't use
+xprop data. Also, XFCE is working on their Wayland version, which would in
+theory not even have xprop by default.
+
+Also, the base version number test for xfce depended on xprop, but
+xprop doesn't even have that xfce version data anymore, so just checking if
+xfce(4|5|)-panel exist and assigning primary version based on that test.
+
+2b. DesktopData: Also see See CODE 1a,1b for further xprop and test fixes that
+could have led to false positive or negative test conditions for the items that
+used xprop tests. These tests are all xprop agnostic now, if it's there, they
+will use it, if not, do the best they can.
+
+3. PackageData: fixed legacy dpkg-query, old version did not support -f shortcut
+for --showformat. This made dpkg package listing fail.
+
+4a. GRAPHICS: Added legacy XFree86.0.log to X log path detection, that was an
+oversight. Also added legacy module syntax _drv.o (not _drv.so). This gets X
+driver data now for very old systems.
+
+4b. GRAPHICS: fixed corner case where no x driver data, running as root, was not
+supposed to show 'note: X driver n/a' message, that was a holdover from before
+driver output was cleaned up and driver: N/A shows when no drivers at all found.
+Just forgot to remove it when doing recent updates in the driver section, maybe?
+
+5. REPOS/PackageData: For netpkg Zenwalk Slackware systems, showed only slackpkg
+repo data, empty, and showed the Slackware pm, not netpkg for pm. See
+Enhancements 5, 6.
+
+6. REPOS: removed slapt_get file /etc/slapt-get/pubring.kbx, that's not a repo
+file. Thanks chrisreturn for pointing that out.
+
+7a. CheckRecommends: See also CODE 6. Fixed case where > 1 package manager is
+detected on system, now lists them one by one for detected, and shows package
+install options as well. Before only picked first detected, which could lead
+to wrong results for Missing Package lists.
+
+7b. CheckRecommends: Fixed glitch, forgot to update the current shell/version
+when ShellData was refactored, this led to no current shell + version showing
+up in recommends core tools report.
+
+8. RAM: fixed speed_mapper string match to allow for older syntaxes. This is as
+far as known OpenBSD only, from dboot data. Matches then converts PC2700 to
+PC-2700 which then allows for mapping.
+
+9. RAM/PROCESSES/INFO/SHORT: Finally tracked down a long time oddity, where for
+example:
+ RAM: total: 31.28 GiB
+does not match 32 GiB physical installed. This is because that is the total
+available after kernel and system reserved RAM is deducted, and in some cases,
+GPU allocated RAM. There are also corner cases where the listed amount can be
+less due to physical RAM damage, but that's uncommon.
+
+Added explanation of why it's different, and what available is referring to in
+man -m/--memory.
+
+Changed -m, -tm to show:
+
+System RAM: available: 31.28 GiB used 26.23 GiB (83.9%)
+
+and -I to show:
+
+Memory: available: 31.28 GiB used 26.23 GiB (83.9%)
+
+You can get the 'reserved' and 'kernel code' data from dmesg, but since Debian
+made that root/sudo tool, can't count on being able to parse that out of dmesg,
+plus you can never count no dmesg anyway since it can get overwritten by kernel
+oops or wonky device etc. inxi doesn't use dmesg data for Linux for this reason.
+
+... [ 0.000000] Memory: 32784756K/33435864K available (10252K kernel code,
+1243K rwdata, 3324K rodata, 1584K init, 2280K bss, 651108K reserved, 0K
+cma-reserved)
+
+Also removed Raspberry Pi video RAM added back in to total now that it's clear
+it's what is available. This may also make systems with GPU using system RAM
+more correct.
+
+9. SENSORS: sensors /sys tried to create concatenated string with $unit $value
+but these are not necessarily defined, that needed to be protected with defined
+tests.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1a. AUDIO: JACK: added helper nsmd (new session manager), and its recommended
+gui agordejo. That's the drop in replacement for non-session-manager, the dev of
+which apparently lost interest in that project. But the ID method will work fine
+for for either, since both ran as nsmd.
+
+1b. AUDIO: PULSE: added pulseaudio-alsa plugin support for helpers. This is like
+pipewire-alsa plugin, just alsa config file. Only seen in Arch Linux so far, but
+if others use similar paths for the glob pattern, they will also work fine.
+
+Also added pulseaudio-esound-compat plugin, which is easier to detect with
+/usr/bin/esdcompat.
+
+Also added paman, pulseaudio manager.
+
+1c. AUDIO: ESOUND,ARTS: added legacy esd (EsounD aka: Enlightened Sound Daemon)
+and aRts sound server support, with basic help/tools. These are quite old, but
+are still occasionally seen in the wild on newer systems, surprisingly enough.
+
+1d. AUDIO: ALSA: added alsactl to alsa tools. Missed that one, it's an /sbin
+type utility.
+
+1e. AUDIO: ALSA: First try at ALSA compiled in but inactive report, previously
+depended on active only state of the API. Now uses compiled in SND_ kernel
+switch using the /boot/config-[kernel] file, which is a big expensive parse but
+only will activate on Linux kernels with no /proc/asound present. This fallback
+fails if kernel config file not present: /boot/config-$(uname -r).
+
+1f. AUDIO: OSS: added tool ossctl.
+
+1g. AUDIO: NAS: added helper: audiooss which is an OSS compat layer.
+
+2a. DistroData: added Arch base distros: ArchEX, Bridge Linux, Condres OS,
+Feliz, LiriOS, Magpie, Namib, Porteus, RevengeOS, SalientOS, VeltOS.
+
+None of these are verified. Some don't exist anymore.
+Source: https://www.slant.co/topics/7603/~arch-linux-based-distributions
+
+2b. DistroData: added ubuntu lunar 23-4 release id.
+
+2c. DistroData: added porteux, added porteux, zenwalk to slackware systembase
+
+3. DesktopData/GRAPHICS: added Smithay Wayland compositor. Not verified.
+
+4a. UsbData/UsbItem: added USB lanes (-Jxx) and mode (-Ja), to add more useful
+data about USB revision and mode names the USB group has created. Otherwise it's
+too difficult to try to explain it. Note that -Jxx lanes follows other inxi
+items that show PCIe lanes as an -xx item to try to keep it consistent.
+
+This also consolidates the bsd and linux data sources, see CODE 5.
+
+Note modes and lanes are Linux only because the revision number, lanes, and
+speed used to determine mode are only natively available in Linux as actual
+internal data values. If this changes BSD support will be added in the future.
+
+The BSD rev and speed data is synthesized completely by inxi using some string
+values, and thus is not reliable, which means that pretending inxi can get this
+granular with data that is not coming directly from the system itself is
+probably not a good idea.
+
+Following wikipedia mode names: https://en.wikipedia.org/wiki/USB4
+
+These are the known possible combinations:
+rev: 1.0 mode: 1.0 lanes: 1 speed: 1.5 Mbps
+rev: 1.1 mode: 1.0 lanes: 1 speed: 1.5 Mbps
+rev: 1.1 mode: 1.1 lanes: 1 speed: 12 Mbps
+rev: 2.0 mode: 1.0 lanes: 1 speed: 1.5 Mbps
+rev: 2.0 mode: 1.1 lanes: 1 speed: 12 Mbps
+rev: 2.0 mode: 2.0 lanes: 1 speed: 480 Mbps
+rev: 2.1 mode: 2.0 lanes: 1 speed: 480 Mbps
+rev: 3.0 mode: 3.2 gen-1x1 lanes: 1 speed: 5 Gbps
+rev: 3.0 mode: 3.2 gen-1x2 lanes: 2 speed: 10 Gbps
+rev: 3.1 mode: 3.2 gen-1x1 lanes: 1 speed: 5 Gbps
+rev: 3.1 mode: 3.2 gen-1x2 lanes: 2 speed: 10 Gbps
+rev: 3.1 mode: 3.2 gen-2x2 lanes: 2 speed: 20 Gbps [seen this case]
+rev: 3.2 mode: 3.2 gen-1x1 lanes: 1 speed: 5 Gbps [wrong rev: seen this case]
+rev: 3.2 mode: 3.2 gen-1x2 lanes: 2 speed: 10 Gbps [wrong rev: possible case]
+rev: 3.2 mode: 3.2 gen-2x1 lanes: 1 speed: 10 Gbps
+rev: 3.2 mode: 3.2 gen-2x2 lanes: 2 speed: 20 Gbps
+rev: 3.2 mode: 4-v1 gen-3x2 lanes: 2 speed: 40 Gbps [not seen, but possible]
+rev: 4 mode: 4-v1 gen-2x1 lanes; 1 speed: 10 Gbps
+rev: 4 mode: 4-v1 gen-2x2 lanes: 2 speed: 20 Gbps
+rev: 4 mode: 4-v1 gen-3x1 lanes: 1 speed: 20 Gbps
+rev: 4 mode: 4-v2 gen-3x2 lanes: 2 speed: 40 Gbps
+rev: 4 mode: 4-v2 gen-4x1 lanes: 1 speed: 40 Gbps
+rev: 4 mode: 4-v2 gen-4x2 lanes: 2 speed: 80 Gbps
+rev: 4 mode: 4-v2 gen-4x3-asymmetric lanes: 3 up, 1 down speed:120 Gbps
+
+I believe 120Gbps takes the 2 lanes of tx/rx and converts 2 rx lanes to tx so
+the entire lane is dedicated to transmit. and the third lane is dedicated to rx.
+
+Includes error message for unknown usb 3/4 rev/speed match combos. These can be
+bad hardware self reporting or unknown other issues.
+
+4b. USB: Added Si/IEC speeds (base 2, base 10). -Ja triggers extra IEC, base 2
+Bytes (xxx [MG]iB/s). -Jx triggers basic standard Si xxx [MG]b/s base 10 bits.
+
+5a. PackageData: added netpkg as package tool. This stores data in same location
+as slackpkg, but assume if exists directory /var/netpkg, then the system is
+using netpkg as pm, not slackpkg.
+
+5b. PackageData: added Slackware sbopkg, sboui as tools for pkgtool and netpkg.
+
+6a. REPOS: added netpkg (Zenwalk Slackware based pm) repo report.
+
+6b. REPOS: added sbopkg basic repo report. This handles both value syntax types,
+as well as the ability of /root config file to overwrite /etc config repo.
+
+6c. REPOS: added slpkg repo report. This handles their old and newer syntax.
+
+7a. CheckRecommends: For Slackware users, added pkgtool missing package name,
+also will use netpkg so hopefully Zenwalk uses same package names.
+
+7b. CheckRecommends: Added radeon to kernel modules checks.
+
+8. AUDIO/BLUETOOTH/DRIVES/GRAPHICS/NETWORK: For USB, -[ADEGN]xx adds rev, speed,
+lanes. -[ADEGN]a adds mode.
+
+9. RAM: Updated RAM PC DDR in speed_mapper(), which is as far as I know only
+used by OpenBSD, which allows for MT/s speeds as non-root user, which is nice.
+That list hadn't been updated in a long time, so filled out DDR 1-5 PCx-yyyy
+ids.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1a. USB: For -Jxy1, speed is now a child of rev: parent. This goes along with
+mode: and lanes: being children of rev:. This follows how USB consortium wants
+to refer to USB revisions now: by speed, lanes, and modes, the latter being the
+technical term, the speed being the marketing term.
+
+1b. USB: If no speed data found, show N/A. This should almost never happen
+except for very old Linux and rarely with BSD.
+
+1c. USB: Device type is lower cased except for abbreviations (type-C, HID). This
+makes it more consistent as a value.
+
+1d. USB: Show basic Si speed with -Jx, and adds new IEC speed with -Ja.
+
+2. CheckRecommends: See ENHANCEMENT, CODE 6. Now showing row by row package
+managers and missing packages, by package manager(s).
+
+3. DRIVES: Changed long standing redundant use of 'type':
+type: USB ... type: HDD
+to:
+type: USB ... tech: HDD
+'tech:' means the technology used, HDD, SDD, and if we can ever figure out how
+to detect it, Hybrid Hard Drive (HHD),
+
+4. AUDIO/BLUETOOTH/DRIVES/GRAPHIC/NETWORK: moved 'type: USB' pair to after
+driver for -A/-E/-G/-N, which allows it to be the parent of the new USB data
+block. Negative is it moves it a bit further back in the line.
+
+For Drives, it moves it from after /dev.. maj-min to after block-size, However,
+with -D/-Dx, it's last in the line, which is nice. This is the only way I could
+find to make it more consistent across all possible USB device/drive type
+reports.
+
+5. INFO/RAM/PROCESSES: Changed -I:
+
+Memory: [total] used:
+to:
+Memory: available: [total] used:
+
+Changed -tm/-m to be consistent:
+
+Memory: RAM: total: .. used..
+to:
+Memory: System RAM: available: ... used:..
+
+This corrects a long standing inaccuracy where MemTotal is not actually the full
+system RAM, but is the RAM minus reserved stuff for system and kernel, and GPU
+memory in some cases.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1a. DOCS: docs/inxi-audio.txt: ongoing updates, adding more information, more
+on helpers, detection methods, etc.
+
+1b. DOCS: New: docs/inxi-usb.txt: USB info, update, added more, a work in
+progress.
+
+1c. DOCS: docs/inxi-custom-recommends.txt: name in inxi comment did not match,
+and updated to new comment cleaned up syntax in example. Fixed inxi comment file
+name.
+
+1d. DOCS: New: docs/inxi-unit-handling.txt: To document how inxi handles
+size/speed data internally, and ideally, to help integrate all those methods
+into one big tool one day, not spread across many area.
+
+1e. DOCS: New: docs/inxi-repo-package-manager.txt: To start to document arcana
+and methods and commands and outputs for package managers. Since this is a late
+start, will take time to complete, but better late than never.
+
+2a. MAN/OPTIONS: updated for USB -Jx, -Jxx, -Ja, adding lanes, mode, iec speed
+items.
+
+2b. MAN/OPTIONS: fixed error which had USB speed as -Jxxx instead of -Jxx. Also
+then changed speed to be -Jx.
+
+2c. MAN/OPTIONS: updated for repos for SBOPKG, SBOUI, SLPKG, and added
+SLAPT_GET, I'd forgotten that one.
+
+2d. MAN/OPTIONS: updated for -xx[ADEGN] USB rev, speed, lanes; for -a[ADEGN]
+updated for USB mode.
+
+2e. MAN/OPTIONS: updated for memory available/used changed.
+
+3. MAN: fixed some inconsistent use of short/long form display in extra data
+options.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1a. DesktopData: New function for xfce only detections, turns out xprop is not
+necessarily installed, Void Linux for example had failed ID. Old version
+required xprop to do the tests, which was not robust and failed in this case.
+Function: get_env_xfce_data(). Also made xprop data optional for all the
+xxx_xprop_data desktop tests, not just some of them. This will forward proof
+the desktops
+
+1b. DesktopData: Fixed bad parens in test cases, was not correctly organized.
+if (a || b || (c || d) && e)
+was supposed to be:
+if (a || b || ((c || d) && e))
+Odd how those types of glitches creep in, one fix is also to just make the lines
+break more reasonably so the conditions are easier to parse visually.
+
+2a. DEBUGGER: Added /etc/X11/XF86Config-4 xorg conf file to debugger.
+
+2b. DEBUGGER: audio_data(): added audio server versions to cover all known ones.
+
+3. MemoryData: changed all $memory to array references, got rid of split :
+separators, which were clearly legacy items leftover from bash/gawk days. Also
+changed MemoryData::get('splits') to get('full') to reflect this change.
+
+This change should be transparent though it may introduce corner case undefined
+value situation but that should not happen since array values are defined first.
+
+4. UsbData: Refactor of usb speed, rev, added lanes, mode. Refactored most of
+the bsd/linux rev/speed logic, merged some of bsd speed/rev into the new
+version_data() function, which loads all the data based on what is calling it.
+This helps consolidate the logic across usb data sources.
+
+5a. GLOBAL: made functions/methods use same comment syntax for args:
+ args: 0:...; 1:...
+always starting with 0, to match array index. Same syntax for return array index
+values. In some cases simply note a variable is passed by ref:
+ args: $value passed by reference.
+
+5b. GLOBAL: made all sub/functions/methods follow the same spacing syntax. This
+seems to be a good compromise for space/readability. Note that adding in these
+new lines added about 400 lines to the total length, plus the line breaks that
+were already there. Yes, inxi has a lot of sub routines! aka functions and
+sometimes aka methods.
+
+[empty line]
+[comments]
+sub [name] {
+
+Packages/classes now also all follow the same spacing rules:
+
+[empty line]
+[comments]
+# Package Name
+{
+package [name];
+[empty line]
+[comments]
+sub [name] {
+...
+}
+}
+
+Internally, subs generally do not use any empty lines unless it makes sense to
+do so for some specific reason.
+
+5c: GLOBAL: made start of sub comments be upper case, I have a bad habit of
+typing comments in lower case, easier to read if it's reads like a normal
+sentence.
+
+6. CheckRecommends: refactored entire items logic, set global hash for test
+items. Made support > 1 detected package manager.
+
+7. REPOS: cleaned up comments for package manager/repo blocks.
+
+8. SENSORS: sensors_sys failed to reset to undefined $unit and $value, and also
+failed to test if they were defined before using them in concatenation.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Sun, 7 May 2023 14:00:00 -0700
+
+================================================================================
+Version: 3.3.26
+Patch: 00
+Date: 2023-03-28
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+Significant upgrade to sound server running detections, much more granular and
+hopefully more accurate, with more useful reporting values. Also added some nice
+useful audio api/server tool and info items.
+
+Packagers: this corrects possibly wrong or misleading audio server reports,
+particularly related to PulseAudio/PipeWire, which can lead to support issues
+and lack of clarity due to ambiguous or wrong reports about sound Servers
+present, active, or off. Upgrading your package is highly recommended.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. Thanks to people like Chimera dev Daniel "q66" Kolesa for experimenting with
+non systemd (uses dinit/dinitctl), non GCC, non GNU linux, and for making early
+pre-alpha versions run in vm, and for being easy to test!
+
+Not so much because I personally want or care about or view as a positive
+skipping GNU tools or GCC in favor of clang and BSD tools, but more because
+these experiments help make the general overall Linux ecosystem more robust.
+Including inxi.
+
+2. Thanks for the Manjaro people for noting this issue on their forums.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1a. AUDIO: jack_control and pw-cli won't run as root, exit with error. This
+forces back to fallback process present tests for active running state.
+
+1b. AUDIO: pactl will start pipewire/pipewire-pulse/pulseaudio if stopped and
+not masked, so not using since that would make inxi alter the state of the
+system.
+
+1c. AUDIO: pipewire-alsa, pulseaudio-jack depend on file exist globs, tested on
+Arch Linux, Debian base, but unknown if paths exist on other Linux pimary
+distros. Easy to add to globbing tests, but no going to check them all!
+
+2. SERVICES: systemctl status [service] can fail if service loaded using --user
+which is a new one on me, not sure how to handle that.
+
+3. It would be nice to get inxi issues like the sound server/api glitches
+handled by filing an issue on inxi github, and not to rely on my seeing a random
+distro forum post, which I only found by pure coincidence.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. AUDIO: See Fixes 3a,b,c. In some cases false report of pulseaudio and
+pipewire running: yes create unclear output and results, or misleading. Thanks
+to manjaro users to noticing this and mentioning it in a forum post.
+
+Note: it's much more effective to file issues on inxi github than to hope I will
+see a random forum post one day.
+
+2. DEBUGGER: Bug in debugger, somewhere introduced '-- list' (instead of
+'--list') for bluetoothctl which made older systems hang when running the
+debugger. No idea when or how that space got introduced.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. INFO: Compilers showed Compilers: gcc: N/A when clang/gcc not installed, this
+was not intended, but was a small glitch in main::get_gcc_data(), where it
+assigned undef as array contents when gcc not defined. This was exposed by
+Chimera, which uses clang, but would have happened any time gcc not installed on
+system.
+
+2. SYSTEM: tiny fix, was getting ',' at end of kernel compiler version.
+
+3a. AUDIO: For pipewire, made process detection test more robust, now excludes
+pipewire-pulse in case where that might be running without pipewire on/enabled.
+
+3b. AUDIO: bigger fix, more robust tests for audio servers running for jack,
+pipewire, pulseaudio, these look for more explicit server tool reports. Certain
+not to be reliable always, and fail for superuser, will probably need more
+tweaking. Also notes for jack, pulse, pipewire if only positive detection found
+via ps aux: active (process) to avoid incorrect data, and root specific messages
+depending on situation.
+
+3c. AUDIO: was testing for pactl to determine if pulseaudio installed, but found
+case where pactl could be installed without pulseaudio. Now tests for pulseaudio
+installed.
+
+3d. AUDIO: weak fix for Linux OSS4 version, using /etc/oss4/version.dat file,
+which may or may not exist on all distros.
+
+3e. AUDIO: alsa-oss compat can create /dev/sndstat file, which would then lead
+to positive OSS detection even if it's not present. This is corrected, and will
+not show if asound/version exists and no ossinfo. For linux, relying on ossinfo
+presence, which comes from oss4-base.
+
+3f. AUDIO: Older ALSA /proc/asound/version had a date string in parentheses
+after the Driver Version, so now explicitly get the string after Version.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1. REPOS: added support for /etc/apk/repositories.d/*.list, which works pretty
+much the same as /etc/apt/sources.list.d/*.list. This is to make Chimera apk
+repos show up, previously only supported /etc/apk/repositories file read.
+
+2a. DistroData: Added Feren to distro system base. This was much trickier than
+it should be due to inconsistent use of os-release field names, but that's how
+it goes.
+
+2b. DistroData: new Arch derived distro XeroLinux added to system base. I know,
+I know, it's a never-ending endeavor (get it?) since these pop up all the time,
+but might as well add them now and then as they appear.
+
+3a. AUDIO: inxi now handles pipewire-pulse as top layer audio daemon, along with
+several other server/api helpers. Note that pw-jack does not appear to be a
+daemon, just a plugin, so shows 'plugin'. Extra sound server helpers added when
+discovered or requested.
+
+ API: ALSA
+ v: k5.19.0-16.2-liquorix-amd64
+ status: kernel-api
+ Server-1: PulseAudio
+ v: 16.1
+ status: off (on pipewire-pulse)
+ Server-2: PipeWire
+ v: 0.3.65
+ status: active
+ with:
+ 1: pipewire-pulse
+ status: active
+ 2: pw-jack
+ type: plugin
+
+3b. AUDIO: For -Aa, added tools: report. Currently supports these basic tools:
+
+alsa: alsamixer alsamixergui amixer
+jack: cadence jack_control jack_mixer qjackctl
+oss: dsbmixer mixer ossinfo ossmix ossxmix vmixctl
+nas: auctl auinfo
+pipewire: pw-cat pw-cli wpctl) [+pactl if pipewire-pulse and no pulseaudio
+pulse: pacat pactl pamix pamixer pavucontrol pulsemixer
+roar: roarcat roarctl
+sndiod: aucat midicat mixerctl sndioctl
+
+Note that inxi-perl/docs/inxi-audio.txt has lists of alternates or rejected
+helpers and tools, but we want to keep that output short and sane.
+
+3c. AUDIO: For BSDs, if sndiod is detected, adds an API line for sndio. Note
+this may create 2 API lines for FreeBSD using OSS.
+
+3d. AUDIO: Added basic support for roar sound server, NAS (Network Audio
+System).
+
+4. CPU: new Intel and AMD cpu model matches for latest and future, Luna Lake,
+Zen 4c.
+
+5. GRAPHICS: new nvidia current, AMD, and Intel GPU ids.
+
+6. DRIVES: more disk vendors, ids! The list never stops, but sadly, so many are
+not identifiable. Check: inxi-perl/tools/lists/disks_unhandled to see if you
+can positively identify any of those.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1a. AUDIO: Changed main API/Server running: to status: [status], that syntax is
+more able to handle different circumstances.
+
+1b. AUDIO: With change to status:, now uses granular fixes above, and adds root
+notes if no active detections.
+
+1c. AUDIO: Changed 'Sound API', 'Sound Server' to 'API', 'Server'. This avoids
+ambiguity with some types, it's the Audio section, and those are the APIs and
+Servers for that Audio section. Makes it match Graphics as well. and is shorter.
+
+1d. AUDIO: Changed 'Sound Interface' for sndiod to 'Server', which is how it's
+listed, and for BSD, added API: sndio item. Also changed 'sndio' to 'sndiod' for
+the Server: item.
+
+1e. AUDIO: Changed ALSA/BSD sndio to show: status: api since saying an api
+is running makes little sense, it's there or it's not there. OSS can be enabled
+or disabled so shows status: active/off for Linux, but kernel-api for BSDs.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1a. MAN: Added note for helpers item: with: pipewire-pulse/pw-jack etc to -Axx.
+
+1b. MAN: Added -Aa item for audio server tools.
+
+2. OPTIONS: Updated for -Axx helpers, -Aa tools.
+
+3. DOCS: Created inxi-perl/docs/inxi-audio.txt doc file. Too many odd factoids
+to forget about during this upgrade!
+
+--------------------------------------------------------------------------------
+CODE:
+
+1. REPOS: Moved %keys to %repo_keys and set it only once with set_repo_keys(),
+those big hash assigns per iteration are really expensive, now stores it
+globally in RepoItem and sets only once.
+
+2. INFO: main::get_gcc_data() failed to handle case where there is no gcc at all
+installed, resulted in returning an array with content of 'undef', not an empty
+array as intended. This made the array not set test fail for Compilers, so gcc
+showed as N/A, which was not intended.
+
+3. DistroData: changed internal lsb/osr $distro to $distro_lsb/$distro_osr,
+which lets inxi update the distro name during system base processing in cases
+where the data is redundant. Stupid hack, sigh, should not be necessary, but
+that's life, /etc/os-release was poorly designed so it leads to such confusions.
+
+4a. AUDIO: Added --dbg 52 to output results of pw-cli.
+
+4b. AUDIO: refactored sound_data, renamed, added {jack,pipewire,pulse}_status(),
+sound_helpers(), sound_tools() utilities.
+
+5. DEBUGGER: added more pactl and pw-cli outputs, and pipewire-pulse,
+pipewire-jack --version.
+
+6. main::get_driver_modules(): add space after ',' if total string > 40
+characters to allow splitting very long unbroken strings of modules that
+otherwise would not break as expected.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Tues, 28 Mar 2023 16:30:00 -0800
+
+================================================================================
+Version: 3.3.25
+Patch: 00
+Date: 2023-02-07
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+A small point release, various smaller items, ongoing updates to matching table
+features, bug fixes, but nothing major.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. Thanks Umio-Yasuno in github issue #281 for actually being proactive and
+finding some Intel/AMD gpu device id lists. I wish more issues would be like
+that.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1. DEBUG: --debug-arg and --debug-arg-use must use the full format:
+--debug-arg="-GS", or else the command line eats the args, even if in quotes.
+The error handlers will then complain about no data supplied, and it will exit.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. GRAPHICS: An accidental 'and' instead of 'or' test (see Code 1) led to
+systems without gpu or dri graphics drivers not showing their xorg driver even
+when present. This was due to a mistake, and also due to how Perl handles || and
+&& in sequence, which made this bug not show up until I tested on a system with
+xorg graphics driver, but without dri or gpu drivers. Virtually no modern
+hardware or operating systems would trip this condition, but older hardware and
+operating systems, which may not have gpu or dri drivers, might. And did, in my
+case. This is by the way why I try to test on old hardware at least now and
+then.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. CODE: A poorly done attempt at optimization would have broken case
+insensitive pre-compiled regex with $pattern = qr/../ because you can't add
+/$pattern/i to precompiled pattern, but qr/.../i support only added perl 5.014.
+This should impact almost nobody, but it is/was a glitch. Basically qr/../ can
+only be used when no /i type modifier is required if supporting Perl less than
+5.014.
+
+See inxi-perl/docs/optimization.txt section REGEX for more on this.
+
+Note that Perl already compares the values in the variable each iteration via a
+simple equality test, so the only real gain from using qr// is not having to do
+that equality test each iteration of a loop.
+
+2. OUTPUT: Fixed a few small inner key name failures to use '-' instead of ' '
+to separate key terms:
+
+3. REPOS: Called urpm urpmq, which is the query tool, not the actual type.
+
+4. GRAPHICS: Fixed some gpu_id.pl matching rules. Thanks Umio-Yasuno in github
+issue #281 for noticing that some of the matching rules were either wrong or not
+loose enough.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1a. OPTIONS: Long time oversight, no option to test or do one time change of key:
+value separator string ':'. This goes along with existing config option
+SEP2_CONSOLE. Added --separator/--sep {character}.
+
+1b. OPTIONS: Added synonym for --output: --export, and for --output-file:
+--export-file.
+
+2a. GRAPHICS: New Intel gpu data source, from intel, finally. This let us add a
+lot more gpu ids. Thanks Umio-Yasuno in github issue #281 for finding these.
+
+2b. GRAPHICS: New AMD data source, from github. This let me fill in some more,
+albeit not as accurately as previous sources, but added more so fine. Thanks
+Umio-Yasuno in github issue #281 for finding these.
+
+3. CONFIG: In a first, took a feature from acxi, --config, and imported it into
+inxi! This shows active current configuration, by file.
+
+4. CPU: updated, fine tuned amd cpu microarch ids.
+
+5. DISKS: More disk vendors added. Not as many as usual, I think the high tech
+sanctions against China may be slowing the rate of new Chinese SSD/USB vendors.
+But still some new ones, as always. Not many new IDs for existing ones though,
+that is noteworthy. A few new data sources to help pinpoint vendor names found
+too, though those won't in general impact users, but can be used to determine if
+a string is in fact a company name.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1. OUTPUT: Fix 2, -t 'started by:' key name changed to: started-by:
+-G 'direct render:' changed to 'direct-render:'.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1a. MAN: there were a few <...> instead of [...] for required option arguments.
+Fixed those.
+
+1b. MAN: also added --debug-id [string] since that is in general useful info.
+
+1c. MAN: Added qualifiers about when xwayland: and compositor: items appear for
+default -Ga output.
+
+1d. MAN: Typo in config path in man page, .conf/ should be .config/.
+
+1e. MAN: for --output json/xml, added pointer to doc page on smxi.org, people
+being unable to grasp the output is getting tiresome.
+
+1f. MAN: Added synonym for --output, --export.
+
+2a. SMXI.ORG DOCS: added --output json/xml documentation page:
+https://smxi.org/docs/inxi-json-xml-output.htm - this is also linked to from the
+github wiki page, though of course nobody is going to read it, as well as from
+a few pages in smxi.org.
+
+2b. Updated inxi-man,options,changelog.htm files.
+
+3. CHANGELOG: Changed to use same format as acxi.changelog, leading topic id's
+in upper case, makes it easier to scan read and organize.
+
+4a. DOCS: docs/inxi-cpu.txt - cleaned up, re-arranged a bit, added cpuid data
+explanation, and updated header on inxi-perl/data/cpu/microarch to better
+explain the way amd does ext fam / ext model, which are not the same,
+bizarrrely, very confusing.
+
+4b. DOCS: New: docs/inxi-disks.txt. Split out from inxi-resources.txt, part of
+the ongoing to documentation modularization, slowly splitting out sub topics
+from inxi-data.txt and inxi-resources.txt. Note this is in general only done
+when I'm working on that specific feature. But slowly, surely.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1a. GRAPHICS: Test when no gpu drivers and no dri drivers but x drivers never
+showed x driver. Was supposed to be all || for tests:
+
+if (@$gpu_drivers || $graphics{'dri-drivers'} && @$x_drivers){
+
+https://perldoc.perl.org/perlop. I believe this led to test 1 being false, test
+2 being false, and since that left tests 2 and 3 needing to be true for the &&
+logical and to be true. Since only one of the two was true, the last bit was
+seen as false.
+
+1b. GRAPHICS: Connected with 1, noticed that for some weird reason, I'd decided
+to assign the array ref for drivers like this:
+
+@$x_drivers = (a, b, c);
+when it was supposed to be:
+$x_drivers = [a,b,c];
+
+This did not cause any issues, since they mean the same thing, but it was silly
+to write it that way.
+
+2a. DEBUG: Added --debug-arg-use which allows testers to run a specific argument
+combination that may be causing issues.
+
+2b. DEBUG: Also added more validation, to make sure arg for --debug-arg /
+--debug-arg-use start with - or -- followed by a letter.
+
+3. START: Removed this code block from set_konvi_data. I had left this in place
+for a release or two to make sure no need for it was found, but it will never be
+used since it never worked in the first place.
+ # my $config_cmd = '';
+ # there's no current kde 5 konvi config tool that we're aware of. Correct if changes.
+ # This part may never have worked, but I don't have legacy data to determine.
+ # The idea was to get inxi.conf files from konvi data stores, but that was never right.
+ # if (main::check_program('kde4-config')){
+ # $config_cmd = 'kde4-config --path data';
+ # }
+ # kde5-coinfig never existed, was replaced by $XDG_DATA_HOME in KDE
+ # elsif (main::check_program('kde-config')){
+ # $config_cmd = 'kde-config --path data';
+ # }
+ # elsif (main::check_program('qtpaths')){
+ # $config_cmd = 'qtpaths --paths GenericDataLocation';
+ # }
+ # The section below is on request of Argonel from the Konversation developer team:
+ # it sources config files like $HOME/.kde/share/apps/konversation/scripts/inxi.conf
+ # if ($config_cmd){
+ # my @data = main::grabber("$config_cmd 2>/dev/null",':');
+ # Configs::set(\@data) if @data;
+ # main::log_data('dump',"kde config \@data",\@data) if $b_log;
+ # }
+
+4. OPTIONS: in OptionsHandler::post_process(), reorganized the various run and
+exit triggers, help, configs, recommends, version, etc. All on top now.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Tue, 7 Feb 2023 18:00:00 -0800
+
+================================================================================
+Version: 3.3.24
+Patch: 00
+Date: 2022-12-10
+--------------------------------------------------------------------------------
+RELEASE NOTES:
+--------------------------------------------------------------------------------
+
+A small point release, mainly to get some bug fixes, and a few minor issues, and
+some ongoing updates to various matching rule features like CPU, Disk Vendors,
+etc.
+
+--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. mrmazda, for continuing to poke around and finding oddities on occasion.
+
+2. The various packagers, for continuing to package inxi.
+
+3. Nothing else really comes to mind, so I'm thankful that no real issues popped
+up, and the ongoing attempt to stabilize and clean up the several year
+aggressive development cycle of code is proceeding quite well.
+
+--------------------------------------------------------------------------------
+KNOWN ISSUES:
+
+1. I'm currently getting no data samples from new server type CPU systems,
+Nvidia Grace, Ampere, both ARM V2 based. The ARM cpu arch logic hasn't been
+updated in many years since I have gotten no meaningful data, currently
+Raspberry Pi 4 is the latest ARM generation I've seen data for, and no ARM
+server type for many years. So support there is really not happening, and won't
+be until I start getting real datasets on those server systems.
+
+Nvidia uses Neoverse V2 ARM core, but I have no information on that yet. Also
+nothing from the Amazon CPU, new Marvell datacenter type CPUs. But that's not
+surprising.Also, nothing from the N1 (2019) or V1 Neoverse (2021) ARM CPU family
+even though those have now been out a while.
+
+A lot of the advanced CPU data should 'just work' because of the huge CPU
+refactor done recently, but some of the more advanced data, particularly
+cpu_arch type data, isn't going to be available until I get real data sets so I
+can see what's going on. No idea how CPUID might work for ARM cpus, for example.
+
+Objectively many of these datacenter/machine learning focused CPUs will never
+see a system inxi will run on, though most I suspect will be running GNU/Linux
+in some form, so inxi can in theory run on them, but those people all know what
+their systems are doing, so the need isn't particularly pressing of course.
+
+With this said, I did used to have more access to cutting edge server stuff, but
+that has largely dried up, particularly ARM based chips.
+
+--------------------------------------------------------------------------------
+BUGS:
+
+1. Found while resolving Fix 2, it turns out > 1 X Screens would not have shown
+correctly due to failing to pass $j row counter by reference. This bug was
+introduced when the big Monitor updates were done, since you almost never see
+> 1 X Screens now, I never saw it until testing something for another reason.
+
+This led to > 1 Screen showing on the same line as the last monitor of the
+previous Screen.
+
+See also Fixes 2, 3, 4, and Code 1, 2, 3.
+
+--------------------------------------------------------------------------------
+FIXES:
+
+1. Changed Intel Saphire Rapids release data from 2021+ (what Intel had
+initially announced) to 2023+ (the actual release date). Not my fault!! They
+were too optimistic, inxi merely repeated their claims.
+
+2. While trying to figure out extra Screen showing up, found a series of subtle
+issues with how X Screens are handled. Added in more robust test for if Screen
+ID has been added by xdpyinfo_data, and other weird corner cases that might
+cause strange results in Display Screen-x.
+
+Created check_screen() to allow for more granular and debugable testing.
+
+This forum post helped focus attention on this issue:
+
+https://forum.endeavouros.com/t/\
+my-second-screen-is-not-working-after-installing-nvidia/33388
+
+3. %monitors was not correctly assigned in xrandr screen fallback.
+
+4. Set number of Screens found if no xdpyinfo or if xrandr found > xdpyinfo
+number of screens.
+
+5. Added Zhaoxin match to Centaur match, might show up on cpu string.
+
+6. OpenBSD's package manager was listed as pkg_info, but it's slightly more
+accurate to call it pkg_add. As far as I understand it, OpenBSD doesn't really
+have a 'package manager' per se, it has a suite of tools to manage packages.
+
+--------------------------------------------------------------------------------
+ENHANCEMENTS:
+
+1. Added some Zhaoxin/Centaur IDs, unlikely to show up, but you never know.
+
+2. Added m68k to X display driver list. This was just added to kernel as a full
+drm driver! Very legacy, but has users in vm, qemu, etc.
+
+3. More disk vendors! I skipped updating this last time because, well,
+collecting the data is really boring, and slightly tedious, and really serves to
+simply remind that this is not the way towards a better world. Or are cheap SSDs
+the true path after all? I doubt it, but you never know.
+
+4. New AMD, Nvidia gpu ids.
+
+5. New Intel Cpu Microarch IDs.
+
+--------------------------------------------------------------------------------
+CHANGES:
+
+1. No changes to speak of, so I won't.
+
+--------------------------------------------------------------------------------
+DOCUMENTATION:
+
+1. Various ongoing updates to inxi-perl/docs. These are very slowly being pulled
+into a more useful form. Emphasis on slowly.
+
+--------------------------------------------------------------------------------
+CODE:
+
+1. In Graphics::xdpyinfo_data() and Graphics::xrandr_data() got rid of extra
+step, now just assign hash reference directly to push anonymous hash reference
+into array. Had used intermidiate variable assignement of hash ref, but that is
+pointless.
+
+2. Added $fake{'xdpyinfo'}, hoping to get some debugger data to test weird
+extra 'Screen' seen with Endeavor user (see Fix 2, 3, Bug 1).
+
+3. Also, instead of using \%monitors, which creates a reference to the last
+value of %monitors, used the correct and safer {%monitors}, which creates an
+anonymous reference of the value %monitors had at that moment. This is a subtle
+Perl error which is easy to make in cases where the hash or array reference is
+almsot never > 1 instance, such as > 1 X Screens.
+
+This should at least help resolve the repeated 'monitors' rows in the output
+in Fixes 2, 3, 4.
+
+4. Added 'source' to $graphics{'screens'} to log where each detected screen came
+from, xdpyinfo or xrandr.
+
+--------------------------------------------------------------------------------
+-- Harald Hope - Sat, 12 Dec 2022 13:28:23 -0700
+
+================================================================================
Version: 3.3.23
Patch: 00
Date: 2022-10-31
@@ -7,11 +2804,9 @@ RELEASE NOTES:
--------------------------------------------------------------------------------
This release fixes another very long standing bug, which I was not sure was an
-inxi or a Konversation bug, which made tracking it down very difficult. Special
-thanks to argonel of Konversation for helping solve this problem, or at least,
-for directing my attention towards the likely cause area, and away from wrong
-ideas. The bug was that inxi simply did not run in Konversation, it would exit
-with error when run with /cmd or /inxi via symbolic links.
+inxi or a Konversation bug, which made tracking it down very difficult. The bug
+was that inxi simply did not run in Konversation, it would exit with error when
+run with /cmd or /inxi via symbolic links.
This may not seem like a huge deal to many of you, but the actual history of
inxi was directly linked to user support in mainly Konversation, so this feature
@@ -41,6 +2836,21 @@ deserved, breather, to recover after huge increases in the overall LOC and
feature sets.
--------------------------------------------------------------------------------
+SPECIAL THANKS:
+
+1. MrMazda, for finding even more failure and corner case issues. See Bug 1.
+
+2. Github Issue #275, for finding and reporting and testing some WSL failures.
+
+3. argonel of Konversation, for helping me finally track down the inxi / pinxi
+failing to run in Konversation issue. Done, appropriately, on IRC channel
+#Konversation. And in particular, for directing my attention towards the likely
+cause area, and away from wrong ideas.
+
+4. Thanks delanym, who filed Gitbub issue #276 for reporting a ZFS problem,
+which also exposed some harder to trigger bugs in ZFS (Bug 3).
+
+--------------------------------------------------------------------------------
KNOWN ISSUES:
1. No known way to detect that the system might be Wayland for the Graphics:..
@@ -123,8 +2933,7 @@ PYTHONPATH is not present with konversation string present as well.
5. Fix for ZFS using /dev/disk/by-partuuid for partition id in zfs,
which can lead to wrong usable disk total size report, along with failure
-to show components. Thanks delanym, issue #276 for reporting this problem, which
-also exposed some harder to trigger bugs in ZFS (Bug 3).
+to show components.
6. Exposed by issue #276, case where line was wrapping value when value was too
short visually to value: used: 34.4 GiB (4.5%) due to the 3 or more words
@@ -4698,7 +7507,7 @@ Includes a fallback report Report-ID: case where for some reason, inxi could not
match the HCI ID with the device. That's similar to IF-ID in -n, which does the
same when some of the IFs could not be matched to a specific device.
-3. For -A, -G, -N, and -E, new item for -xxx, classID, I realized this is
+3. For -A, -G, -N, and -E, new item for -xxx, class-ID, I realized this is
actually useful for many cases of trying to figure out what devices are, though
most users would not know what to do with that information, but that's why it's
an -xxx option!