diff options
| author | 2024-01-31 01:38:18 -0500 | |
|---|---|---|
| committer | 2024-01-31 01:38:18 -0500 | |
| commit | e09bcc3824ae2b8891f00085157f49e0f2245e6e (patch) | |
| tree | 7d5a53c03d8aeb07dfce533d74c3f62065e23cf5 | |
| parent | 9ccb47729cfed157d0b94c1c9ddbd07a0fb179af (diff) | |
New upstream version 3.3.32-1.upstream/3.3.32-1
| -rw-r--r-- | .gitattributes | 1 | ||||
| -rw-r--r-- | README.txt | 39 | ||||
| -rwxr-xr-x | inxi | 5771 | ||||
| -rw-r--r-- | inxi.1 | 291 | ||||
| -rw-r--r-- | inxi.changelog | 797 |
5 files changed, 4628 insertions, 2271 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 @@ -1,12 +1,16 @@ +================================================================================ 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 @@ -22,13 +26,14 @@ 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 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-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 and inxi-perl/pinxi will be mirrored until late 2023, then they will -no longer get updates. +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. @@ -56,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 @@ -113,7 +118,7 @@ REPO: https://codeberg.org/smxi/inxi MAIN BRANCH: master DEVELOPMENT BRANCHES [not used]: one, two -pinxi [development version for inxi]: +pinxi [development version of inxi]: REPO: https://codeberg.org/smxi/pinxi MAIN BRANCH: master @@ -142,7 +147,7 @@ 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 tagged version in the master branch (plus pinxi repo, of course, but pinxi should in -general not be packaged). +general not be packaged). No non-current versions of inxi are supported. -------------------------------------------------------------------------------- MASTER BRANCH @@ -229,7 +234,8 @@ 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. @@ -241,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 @@ -452,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 @@ -1,6 +1,6 @@ #!/usr/bin/env perl ## infobash: Copyright (C) 2005-2007 Michiel de Boer aka locsmif -## inxi: Copyright (C) 2008-2023 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> @@ -49,8 +49,8 @@ use POSIX qw(ceil uname strftime ttyname); ## INXI INFO ## my $self_name='inxi'; -my $self_version='3.3.31'; -my $self_date='2023-11-02'; +my $self_version='3.3.32'; +my $self_date='2024-01-30'; my $self_patch='00'; ## END INXI INFO ## @@ -73,12 +73,13 @@ 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 @@ -103,13 +104,13 @@ 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 ($weather_source,$weather_unit) = (100,'mi'); @@ -120,6 +121,7 @@ my ($display_opt,$sudoas) = ('',''); ## Output my $extra = 0;# supported values: 0-3 my $filter_string = '<filter>'; +my $join_sep_max = 30; # max join length of array+separator, used in set_join_sep my $line1 = "----------------------------------------------------------------------\n"; my $line2 = "======================================================================\n"; my $line3 = "----------------------------------------\n"; @@ -321,6 +323,9 @@ sub set_commands { if ($use{'logical'}){ $commands{'lvs'} = ['exec-sys','','']; } + if ($use{'udevadm'}){ + $commands{'udevadm'} = ['missing','','']; + } } else { if ($use{'pci'}){ @@ -440,6 +445,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 { @@ -593,7 +610,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; @@ -630,7 +647,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; } @@ -641,7 +659,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; } @@ -1170,13 +1188,18 @@ sub set { # removed legacy kde @$configs test which never worked @config_files = ( qq(/etc/$self_name.conf), - qq(/etc/$self_name.d/$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; @@ -1186,11 +1209,11 @@ sub set { 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); + $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); } @@ -1366,11 +1389,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 $@; @@ -1995,16 +2018,19 @@ sub display_data { ['vulkaninfo',''], ['vulkaninfo','--summary'], # ['vulkaninfo','--json'], # outputs to file, not sure how to output to stdout - ['wayland-info',''], # not packaged as far as I know yet + ['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'], @@ -2136,6 +2162,7 @@ sub system_data { ['dmidecode','--version'], ['dmidecode',''], ['dmesg',''], + ['fruid_print',''], # elbrus ['gcc','--version'], ['getconf','-a'], ['getconf','-l'], # openbsd @@ -2166,7 +2193,9 @@ sub system_data { ['lsusb',''], ['lsusb','-t'], ['lsusb','-v'], + ['ps',''], ['ps','aux'], + ['ps','auxww'], ['ps','-e'], ['ps','-p 1'], ['runlevel',''], @@ -2188,6 +2217,9 @@ sub system_data { ['systemctl','list-units'], ['systemctl','list-units --type=target'], ['systemd-detect-virt',''], + ['udevadm','info -e'], + ['udevadm','info -p /devices/virtual/dmi/id'], + ['udevadm','--version'], ['uname','-a'], ['upower','-e'], ['uptime',''], @@ -2223,6 +2255,7 @@ sub system_files { @files = ( '/etc/systemd/system/default.target', '/proc/1/comm', + '/proc/bootdata', # elbrus '/proc/cmdline', '/proc/cpuinfo', '/proc/iomem', @@ -2864,6 +2897,11 @@ sub error_handler { $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" } @@ -2924,7 +2962,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"); @@ -3043,8 +3081,8 @@ sub check_items { else { @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 upower - uptime); + lsusb lvs mdadm modinfo runlevel sensors smartctl strings sudo tree + udevadm upower uptime); } $b_program = 1; $item = 'Program'; @@ -3053,13 +3091,13 @@ sub check_items { } elsif ($type eq 'recommended display information programs'){ if ($bsd_type){ - @data = qw(eglinfo glxinfo vulkaninfo wmctrl xdpyinfo xprop xdriinfo - xrandr); + @data = qw(eglinfo glxinfo vulkaninfo wayland-info wmctrl xdpyinfo xprop + xdriinfo xrandr); $info_os = 'info-bsd'; } else { - @data = qw(eglinfo glxinfo vulkaninfo wmctrl xdpyinfo xprop xdriinfo - xrandr); + @data = qw(eglinfo glxinfo vulkaninfo wayland-info wmctrl xdpyinfo xprop + xdriinfo xrandr); } $b_program = 1; $item = 'Program'; @@ -3543,6 +3581,13 @@ sub set_item_data { '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', @@ -3580,7 +3625,7 @@ sub set_item_data { 'info' => '-G X11/Wayland EGL info', 'info-bsd' => '-G X11/Wayland EGL info', 'apt' => 'mesa-utils (or: mesa-utils-extra)', - 'pacman' => 'mesa-demos', + 'pacman' => 'mesa-utils', 'pkgtool' => 'mesa', 'rpm' => 'egl-utils (SUSE: Mesa-demo-egl)', }, @@ -3588,7 +3633,7 @@ sub set_item_data { 'info' => '-G X11 GLX info', 'info-bsd' => '-G X11 GLX info', 'apt' => 'mesa-utils', - 'pacman' => 'mesa-demos', + 'pacman' => 'mesa-utils', 'pkgtool' => 'mesa', 'rpm' => 'glx-utils (Fedora: glx-utils; SUSE: Mesa-demo-x)', }, @@ -3600,6 +3645,14 @@ sub set_item_data { '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 manager (fallback)', @@ -3884,7 +3937,7 @@ sub get_piece { } # args: 0: command to turn into an array; 1: optional: splitter; -# 2: optionsl, strip and clean data +# 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 { @@ -3993,504 +4046,6 @@ sub load_json { eval $end if $b_log; } -# returns array of: 0: program print name 1: program version -# args: 0: program values id; 1: program version string; -# 2: $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,'',''], - '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 - '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 - '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.*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 - '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[[: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 -# args: 0: 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: 0: desktop/app command for --version; 1: search string; -# 2: space print number; 3: [optional] version arg: -v, version, etc; -# 4: [optional] exit first find 0/1; 5: [optional] 0/1 stderr output; -# 6: replace regex; 7: 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; -} - # 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 @@ -4870,10 +4425,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; @@ -4886,7 +4438,7 @@ 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');}, 'I|info' => sub { $show{'short'} = 0; $show{'info'} = 1;}, @@ -5081,38 +4633,32 @@ 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 @@ -5123,7 +4669,7 @@ sub get { 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; @@ -5373,8 +4919,9 @@ sub get { 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|uptime|usbconfig|'; - $wl .= 'usbdevs|vmstat|vulkan|wl-info|wlr-randr|xdpyinfo|xorg-log|xrandr'; + $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; @@ -5401,7 +4948,7 @@ sub get { 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 .= 'usb-sys|vmstat|wayland|wmctrl'; + $wl .= 'udevadm|usb-sys|vmstat|wayland|wmctrl'; for (split(',',$arg)){ if ($_ =~ /\b($wl)\b/){ $force{lc($1)} = 1; @@ -5666,6 +5213,9 @@ sub post_process { (($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'}){ $use{'pci'} = 1; @@ -5777,10 +5327,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"], @@ -5812,7 +5362,6 @@ 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, basic EGL, OpenGL, Vulkan API data; Xvesa API: VBE info."], @@ -5827,10 +5376,10 @@ sub show_options { ['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. Also shows - System RAM report, and removes Memory report from -I or -tm."], + ['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."], @@ -5856,7 +5405,7 @@ sub show_options { ['1', '-r', '--repos', "Distro repository data. Supported repo types: APK, APT, CARDS, EOPKG, NETPKG, NIX, PACMAN, PACMAN-G2, PISI, PKG (BSDs), PORTAGE, PORTS (BSDs), SBOPKG, SBOUI, SCRATCHPKG, SLACKPKG, SLAPT_GET, SLPKG, TCE, - URPMQ, XBPS, YUM/ZYPP."], + 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."], @@ -5898,18 +5447,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, @@ -5925,7 +5475,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 @@ -5998,14 +5548,14 @@ sub show_options { 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; 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)."], @@ -6024,8 +5574,8 @@ 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', '', '', ''], @@ -6048,34 +5598,36 @@ sub show_options { 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', '', "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 + ['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; 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', '-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, @@ -6093,26 +5645,29 @@ sub show_options { ['2', '-G', '', "Device serial number, class ID; Xorg Screen size, diag; Monitors: hz, size, modes, serial, scale, modes (max/min); APIs: EGL: hardware driver info; Vulkan: layer count, device hardware vendor."], - ['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', '-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,--memory-modules', '', "Width of memory bus, data and total (if + ['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', '', "Kernel clocksource; 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, @@ -6140,8 +5695,10 @@ sub show_options { 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 Packages total number of lib files found for each - package manager and pm tools (if not -r); adds init service tool."], + ['2', '-I', '', "Adds to Power suspend/hibernate available non active states, + hibernate image size, suspend failed totals (if not 0), active power daemons; + 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 @@ -6150,7 +5707,7 @@ sub show_options { ['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."], + identical; show firmware version (if available)."], ['2', '-n,-N', '', "If available: list of alternate kernel modules/drivers for device(s); PCIe lanes-max: gen, speed, lanes (if relevant); USB mode (if found)."], @@ -6159,9 +5716,10 @@ sub show_options { 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 alternate clocksources, 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"], @@ -6180,16 +5738,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"], - ['3', '3', '', "Get the dev server (smxi.org) version."], - ['3', '4', '', "Get the dev server (smxi.org) FTP version. Use if SSL issues + ['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 + ['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"], + ^$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"], @@ -6384,7 +5942,7 @@ my $pppid = ''; 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 @@ -6407,7 +5965,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 @@ -6446,7 +6004,8 @@ 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; @@ -6454,11 +6013,11 @@ sub get_client_name { 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]; } @@ -6467,7 +6026,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; @@ -6529,9 +6088,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; @@ -6597,13 +6155,14 @@ sub get_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]; @@ -6614,8 +6173,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'; @@ -6640,15 +6199,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 +# 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'}; @@ -6672,8 +6233,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'; @@ -6832,9 +6393,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; } } @@ -6994,21 +6556,22 @@ sub message { 'edid-revision' => "invalid EDID revision: $id", 'edid-sync' => "bad sync value: $id", 'edid-version' => "invalid EDID version: $id", - 'egl-null' => 'No EGL data available.', '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-glxinfo-missing' => 'GL data unavailable in console, glxinfo missing.', '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?', - 'glxinfo-missing' => 'Unable to show GL data. glxinfo is missing.', '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", @@ -7042,12 +6605,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?", @@ -7057,7 +6624,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.', @@ -7096,6 +6663,7 @@ sub message { '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?", @@ -7133,6 +6701,13 @@ sub remove_duplicates { return $string; } +# args: 0: array ref; 1: separator by ref +sub set_join_sep { + # note: printer only wraps if value 'word' count > 2, so make this match + return if !defined $_[0] || !@{$_[0]} || scalar @{$_[0]} < 3; + ${$_[1]} = ${$_[1]} . ' ' if length(join(${$_[1]},@{$_[0]})) > $join_sep_max; +} + # 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 @@ -7398,7 +6973,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); @@ -7990,10 +7565,9 @@ sub sound_data { } ## Servers ## if ($program = main::check_program('artsd')){ - $name = 'aRts'; + ($name,$version) = ProgramData::full('arts',$program); $status = (grep {/artsd/} @ps_cmd) ? 'active': 'off'; $type = 'Server'; - $version = main::program_version($program,'^artsd',2,'-v',1); if ($extra > 1){ $test = [['artswrapper','daemon'],]; $helpers = sound_helpers($test); @@ -8008,10 +7582,9 @@ sub sound_data { # pulseaudio-esound-compat has esd pointing to esdcompat if (($program = main::check_program('esd')) && !main::check_program('esdcompat')){ - $name = 'EsounD'; + ($name,$version) = ProgramData::full('esound',$program); $status = (grep {/\besd\b/} @ps_cmd) ? 'active': 'off'; $type = 'Server'; - $version = main::program_version($program,'^Esound',3,'--version',1,1); # if ($extra > 1){ # $test = [['','daemon'],]; # $helpers = sound_helpers($test); @@ -8024,10 +7597,9 @@ sub sound_data { ($status,$version,$helpers,$tools) = ('','',undef,undef); } if ($program = main::check_program('jackd')){ - $name = 'JACK'; + ($name,$version) = ProgramData::full('jack',$program); $status = jack_status(); $type = 'Server'; - $version = main::program_version($program,'^jackd',3,'--version',1); if ($extra > 1){ $test = [['a2jmidid','daemon'],['nsmd','daemon']]; $helpers = sound_helpers($test); @@ -8040,10 +7612,9 @@ sub sound_data { ($status,$version,$helpers,$tools) = ('','',undef,undef); } if ($program = main::check_program('nasd')){ - $name = 'NAS'; + ($name,$version) = ProgramData::full('nas',$program); $status = (grep {/(^|\/)nasd/} @ps_cmd) ? 'active': 'off'; $type = 'Server'; - $version = main::program_version($program,'^Network Audio',5,'-V',1); if ($extra > 1){ $test = [['audiooss','oss-compat'],]; $helpers = sound_helpers($test); @@ -8056,10 +7627,9 @@ sub sound_data { ($status,$version,$helpers,$tools) = ('','',undef,undef); } if ($program = main::check_program('pipewire')){ - $name = 'PipeWire'; + ($name,$version) = ProgramData::full('pipewire',$program); $status = pipewire_status(); $type = 'Server'; - $version = main::program_version($program,'^Compiled with libpipe',4,'--version',1); if ($extra > 1){ # pipewire-alsa is a plugin, but is just some config files $test = [['pipewire-pulse','daemon'],['pipewire-media-session','daemon'], @@ -8082,10 +7652,9 @@ sub sound_data { } # note: pactl info/list/stat could be used if ($program = main::check_program('pulseaudio')){ - $name = 'PulseAudio'; + ($name,$version) = ProgramData::full('pulseaudio',$program); $status = pulse_status($program); $type = 'Server'; - $version = main::program_version($program,'^pulseaudio',2,'--version',1); if ($extra > 1){ $test = [['pulseaudio-dlna','daemon'], ['pulseaudio-alsa','plugin','/etc/alsa/conf.d/*-pulseaudio-default.conf'], @@ -8101,10 +7670,9 @@ sub sound_data { ($status,$version,$helpers,$tools) = ('','',undef,undef); } if ($program = main::check_program('roard')){ - $name = 'RoarAudio'; + ($name,$version) = ProgramData::full('roaraudio',$program);# no version so far $status = (grep {/roard/} @ps_cmd) ? 'active': 'off'; $type = 'Server'; - # no version so far if ($extra > 1){ $test = [['roarplaylistd','daemon'],['roarify','pulse/viff-emulation']]; $helpers = sound_helpers($test); @@ -8766,13 +8334,13 @@ sub upower_data { 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'){ @@ -9193,7 +8761,7 @@ sub btmgmt_data { my (@data,$id); if ($fake{'bluetooth'}){ my $file; - $file = "$ENV{'HOME'}/bin/scripts/inxi/data/bluetooth/btmgmt-2.txt"; + $file = "$fake_data_dir/bluetooth/btmgmt-2.txt"; @data = main::reader($file,'strip'); } else { @@ -9236,7 +8804,7 @@ sub hciconfig_data { my (@data,$id); if ($fake{'bluetooth'}){ my $file; - $file = "$ENV{'HOME'}/bin/scripts/inxi/data/bluetooth/hciconfig-a-2.txt"; + $file = "$fake_data_dir/bluetooth/hciconfig-a-2.txt"; @data = main::reader($file,'strip'); } else { @@ -9364,7 +8932,7 @@ sub bluetooth_version { ## CpuItem { package CpuItem; -my ($type); +my (%fake_data,$type); sub get { eval $start if $b_log; @@ -9818,6 +9386,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){ @@ -9826,48 +9395,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); @@ -10058,65 +9587,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; @@ -10186,8 +9747,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'); } } @@ -10283,7 +9846,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'}}){ @@ -10292,7 +9855,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'; } @@ -10323,14 +9886,14 @@ 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; } @@ -10338,20 +9901,13 @@ sub cpu_sys_data { 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. @@ -10375,6 +9931,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; @@ -10483,6 +10040,79 @@ sub sys_data_grabber { 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); @@ -12235,7 +11865,7 @@ 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 = '2023+';} # server @@ -12288,13 +11918,17 @@ sub cp_cpu_arch { elsif ($model =~ /^(BC|BD)$/){ $arch = 'Lunar Lake'; # 15 gn $process = 'Intel 18a (1.8nm)'; - $year = '2024+';} # check when actually in production + $year = '2024+';} # seen APU IDs, so out there # Meteor Lake-S maybe cancelled, replaced by arrow elsif ($model =~ /^(C5|C6)$/){ - $arch = 'Arrow Lake'; # 14 gn + $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)'; @@ -12306,11 +11940,12 @@ sub cp_cpu_arch { # Diamond Rapids: Intel 3 (7nm+), 2025 # Raptor Lake: 13 gen, Intel 7 (10nm), 2022 # Meteor Lake: 14 gen, Intel 4 (7nm+) - # Arrow Lake - 14 gen, TSMC 3nm (corei3-5)/Intel 20A 2nm (core i5-9), 2024 - # Lunar Lake - 15 gen, Intel 18A (1.8nm), 2024-5 - # Panther Lake - 15 gen, ?, late 2025, cougar cove Xe3 Celestial GPU architecture - # Beast Lake - 16 gen, ?, 2026? - # Nova Lake - 16 gen, Intel 18A (1.8nm), 2026 + # 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'){ @@ -13638,7 +13273,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]; @@ -14189,15 +13824,16 @@ 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|CJ[NT]|CKT|CUT|[DG]3 Station|DUO\b|DUT|EB\dMW|GE4S5|[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|\sUltra)|SDW[1-9]|SE\d{2}|SEM[1-9]|\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',''], + ['(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 @@ -14208,12 +13844,14 @@ sub set_disk_vendors { ['(\bWDC\b|1002FAEX)','','Western Digital',''], ## 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|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[RTVWYZ]\d|MP|MAP\d|F\d00s?-)','^FUJITSU','Fujitsu',''], @@ -14267,8 +13905,9 @@ sub set_disk_vendors { ['^(Alcor(\s?Micro)?|058F)','^(Alcor(\s?Micro)?|058F)','Alcor Micro',''], ['^Alfawise','^Alfawise','Alfawise',''], ['(^ALKETRON|FireWizard)','^ALKETRON','ALKETRON',''], - ['^Android','^Android','Android',''], ['^ANACOMDA','^ANACOMDA','ANACOMDA',''], + ['^Android','^Android','Android',''], + ['^ANK','^Anker','Anker',''], ['^Ant[\s_-]?Esports','^Ant[\s_-]?Esports','Ant Esports',''], ['^Anucell','^Anucell','Anucell',''], ['^Apotop','^Apotop','Apotop',''], @@ -14280,6 +13919,8 @@ 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) @@ -14290,6 +13931,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',''], @@ -14342,6 +13984,7 @@ sub set_disk_vendors { ['^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',''], @@ -14354,6 +13997,7 @@ sub set_disk_vendors { ['^(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',''], @@ -14380,17 +14024,19 @@ 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',''], @@ -14413,14 +14059,14 @@ sub set_disk_vendors { ['^(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',''], - ['^(Gudga|GIM\d+|GVR\d)','^Gudga','Gudga',''], + ['^(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',''], @@ -14433,11 +14079,12 @@ sub set_disk_vendors { ['^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',''], ['^(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',''], @@ -14454,7 +14101,8 @@ sub set_disk_vendors { ['(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',''], @@ -14483,14 +14131,14 @@ sub set_disk_vendors { ['^Kingbank','^Kingbank','Kingbank',''], ['^(KingCell|KC\b)','^KingCell','KingCell',''], ['^Kingchux[\s-]?ing','^Kingchux[\s-]?ing','Kingchuxing',''], - ['^KINGCOMP','^KINGCOMP','KingComp',''], + ['^(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]|MSH|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',''], @@ -14506,6 +14154,7 @@ sub set_disk_vendors { ['^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',''], @@ -14517,13 +14166,15 @@ sub set_disk_vendors { ['^(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 @@ -14532,6 +14183,7 @@ sub set_disk_vendors { ['^Maxell','^Maxell','Maxell',''], ['^Maximus','^Maximus','Maximus',''], ['^MAXIO','^MAXIO','Maxio',''], + ['^Maxmem','^Maxmem','Maxmem',''], ['^Maxone','^Maxone','Maxone',''], ['^MARVELL','^MARVELL','Marvell',''], ['^Maxsun','^Maxsun','Maxsun',''], @@ -14563,13 +14215,14 @@ sub set_disk_vendors { ['^(Motile|SSM\d)','^Motile','Motile',''], ['^(Motorola|XT\d{4}|Moto[\s-]?[EG])','^Motorola','Motorola',''], ['^Moweek','^Moweek','Moweek',''], - ['^Move[\s-]?Speed','^Move[\s-]?Speed','Move Speed',''], + ['^(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',''], @@ -14580,6 +14233,7 @@ sub set_disk_vendors { ['^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',''], @@ -14593,7 +14247,7 @@ 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',''], @@ -14613,6 +14267,7 @@ sub set_disk_vendors { ['^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',''], @@ -14636,6 +14291,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 @@ -14648,7 +14304,7 @@ sub set_disk_vendors { ['^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',''], @@ -14657,6 +14313,7 @@ sub set_disk_vendors { ['^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 @@ -14697,17 +14354,20 @@ sub set_disk_vendors { ['^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',''], @@ -14716,9 +14376,11 @@ sub set_disk_vendors { ['^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',''], @@ -14728,7 +14390,7 @@ sub set_disk_vendors { ['^Walton','^Walton','Walton',''], ['^(Wearable|Air-?Stash)','^Wearable','Wearable',''], ['^Wellcomm','^Wellcomm','Wellcomm',''], - ['^(wicgtyp|N[V]?900)','^wicgtyp','wicgtyp',''], + ['^(wicgtyp|[MN][V]?900)','^wicgtyp','wicgtyp',''], ['^Wilk','^Wilk','Wilk',''], ['^(WinMemory|SWG\d)','^WinMemory','WinMemory',''], ['^(Winton|WT\d{2})','^Winton','Winton',''], @@ -14747,6 +14409,7 @@ sub set_disk_vendors { ['^(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 @@ -14758,6 +14421,7 @@ sub set_disk_vendors { ['^ZEUSS','^ZEUSS','Zeuss',''], ['^(Zheino|CHN|CNM)','^Zheino','Zheino',''], ['^(Zotac|ZTSSD)','^Zotac','Zotac',''], + ['^ZOZT','^ZOZT','ZOZT',''], ['^ZSPEED','^ZSPEED','ZSpeed',''], ['^ZTC','^ZTC','ZTC',''], ['^ZTE','^ZTE','ZTE',''], @@ -15309,8 +14973,8 @@ 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'}){ @@ -15318,7 +14982,7 @@ sub display_output(){ # 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') => '', @@ -15378,8 +15042,8 @@ sub display_output(){ } } } - # 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 { @@ -15440,8 +15104,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'}){ @@ -15754,7 +15419,7 @@ sub display_api { # first do positive tests, won't be set for sudo/root if (!$b_glx && $graphics{'protocol'} eq 'x11'){ $api = 'OpenGL'; - $type = 'glxinfo-missing'; + $type = 'glx-missing'; } elsif (!$b_egl && $graphics{'protocol'} eq 'wayland'){ $api = 'EGL'; # /GBM @@ -15763,7 +15428,7 @@ sub display_api { elsif (!$b_glx && (main::check_program('X') || main::check_program('Xorg'))){ $api = 'OpenGL'; - $type = 'glxinfo-missing'; + $type = 'glx-missing'; } elsif (!$b_egl && main::check_program('Xwayland')){ $api = 'EGL'; @@ -15778,11 +15443,11 @@ sub display_api { if (!$b_glx && (main::check_program('X') || main::check_program('Xorg'))){ $api = 'OpenGL'; - $type = 'glx-console-glxinfo-missing'; + $type = 'glx-missing-console'; } elsif (!$b_egl && main::check_program('Xwayland')){ $api = 'EGL'; - $type = 'egl-console-missing'; + $type = 'egl-missing-console'; } # we don't know what it is, headless system, non xwayland wayland elsif (!$b_egl && !$b_glx && !$b_vulkan) { @@ -16129,7 +15794,7 @@ sub gl_data { # $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-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"; @@ -16143,12 +15808,14 @@ sub gl_data { } else { my $file; - $file = "$fake_data_dir/graphics/egl-es/eglinfo-x11-3.txt"; + # $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-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'); } } @@ -16216,6 +15883,8 @@ sub gl_data { } } 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]; } @@ -16251,13 +15920,13 @@ sub gl_data { } } push(@{$gl->{'egl'}{'data'}{'vendors'}},$working[1]); - if ($working[1] eq 'nvidia'){ + 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 ($working[0] eq 'EGL driver name'){ + elsif ($platform && $working[0] eq 'EGL driver name'){ if (!defined $device){ $gl->{'egl'}{'platforms'}{$platform}{'egl'}{'driver'} = $working[1]; if ($mesa_drivers{$working[1]}){ @@ -16276,7 +15945,7 @@ sub gl_data { $gl->{'egl'}{'data'}{'hw'}{$working[1]} = $mesa_drivers{$working[1]}; } } - if ($working[0] eq 'EGL client APIs'){ + if ($platform && $working[0] eq 'EGL client APIs'){ if (defined $device){ $gl->{'egl'}{'platforms'}{$platform}{$device}{'egl'}{'client-apis'} = [split(/\s+/,$working[1])]; } @@ -16917,6 +16586,7 @@ sub wlinfo_data { } else { $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]; @@ -17282,7 +16952,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+)/){ @@ -17320,7 +16990,7 @@ sub xdpyinfo_data { } else { # my $file; - # $file = "$ENV{HOME}/bin/scripts/inxi/data/xdpyinfo/xdpyinfo-1-screen-2-in-inxi.txt"; + # $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; @@ -17415,24 +17085,36 @@ sub xrandr_data { 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); - my (@ids,%monitors,@xrandr_screens,$xrandr); + 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 { # my $file; - # $file = ""$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-4-displays-1.txt"; - # $file = "$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-3-display-primary-issue.txt"; - # $file = "$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-1.txt"; - # $file = "$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-test-2.txt"; - # $file = "$ENV{HOME}/bin/scripts/inxi/data/xrandr/xrandr-1-screen-2-in-inxi.txt"; - # $xrandr = main::reader($file,'strip','ref'); + # $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 # $graphics{'screens'} = undef; - foreach (@$xrandr){ + 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]+):/){ @@ -17467,7 +17149,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)?/){ @@ -17491,7 +17173,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$//; @@ -17517,17 +17199,31 @@ 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 - # 5120x1440 59.98* 29.98 - 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){ @@ -17617,14 +17313,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; @@ -17639,10 +17329,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; } @@ -17663,6 +17349,57 @@ sub display_server_data { 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'} = ''; @@ -17757,10 +17494,10 @@ sub display_drivers_x { 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 m68k 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; # qr/../i only added perl 5.14, fails on older perls my ($b_use_dri,$dri,$driver,%drivers); @@ -17852,6 +17589,7 @@ sub display_drivers_x { # print 'source: ', Data::Dumper::Dumper $driver_data; return $driver_data; } + sub set_mesa_drivers { %mesa_drivers = ( 'anv' => 'intel', @@ -18069,9 +17807,9 @@ sub set_amd_data { 'years' => '2019-20', }, {'arch' => 'RDNA-2', - 'ids' => '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', + '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', @@ -18084,7 +17822,7 @@ sub set_amd_data { }, {'arch' => 'RDNA-3', 'ids' => '73f0|7480|7481|7483|7487|7489|748b|749f', - 'code' => 'Navi-33', + 'code' => 'Navi-33',- 'process' => 'TSMC n6 (6nm)', 'years' => '2023+', }, @@ -18107,9 +17845,8 @@ sub set_amd_data { 'years' => '2021-22+', }, {'arch' => 'CDNA-3', - 'ids' => '', + 'ids' => '74a0|74a1', 'code' => 'Instinct-MI3xx', - 'pattern' => 'Instinct MI3\d{2}X?', 'process' => 'TSMC n5 (5nm)', 'years' => '2023+', }, @@ -18267,8 +18004,9 @@ sub set_intel_data { }, # Jupiter Sound cancelled? {'arch' => 'Gen-12.7', - 'ids' => '5690|5691|5692|5693|5694|5695|5696|5697|5698|56a0|56a1|56a3|56a4|' . - '56a5|56a6|56a7|56a8|56a9|56b0|56b1|56b2|56b3', + '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', 'process' => 'TSMC n6 (7nm)', 'years' => '2022+', @@ -18292,7 +18030,12 @@ sub set_intel_data { 'process' => 'Intel 4 (7nm+)', 'years' => '2023+', }, - + {'arch' => 'Gen-15', + 'ids' => '7d51|7d67|7dd1', + 'code' => '', + 'process' => 'TSMC 3nm', + 'years' => '2024+', + }, ]; } @@ -18565,12 +18308,13 @@ sub set_nv_data { 'years' => '2018-2022', }, {'arch' => 'Ampere', - 'ids' => '20b0|20b2|20b3|20b5|20b6|20b7|20bd|20f1|20f3|20f5|20f6|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', + '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, @@ -18594,9 +18338,9 @@ sub set_nv_data { 'years' => '2022+', }, {'arch' => 'Lovelace', - 'ids' => '2684|26b1|26b2|26b5|26b9|2704|2717|2730|2757|2770|2782|2786|27a0|' . - '27b0|27b1|27b2|27b8|27ba|27bb|27e0|27fb|2803|2805|2820|2860|2882|28a0|28a1|' . - '28e0|28e1', + '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', 'kernel' => '', 'legacy' => 0, @@ -18607,7 +18351,6 @@ sub set_nv_data { 'xorg' => '', 'years' => '2022+', }, - ], } @@ -18673,7 +18416,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; @@ -18707,6 +18450,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'); @@ -18774,8 +18520,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'}; @@ -18962,15 +18712,20 @@ sub set_monitor_layouts { # 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'); @@ -18979,7 +18734,6 @@ 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 @@ -18992,16 +18746,30 @@ sub map_monitor_ids { 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+)?$/; @@ -19009,21 +18777,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'); } } } @@ -19033,7 +18801,7 @@ sub map_monitor_ids { # obviously, if one of the matches was wrong, this will also be wrong, but # thats' life when dealing with irrational data. DP is a particular problem. if (scalar @unmatched_sys == 1){ - $monitor_map->{$unmatched_display[0]} = $unmatched_sys[0]; + $monitor_map->{$unmatched_display[0]} = $unmatched_sys[0]->[0]; } main::log_data('dump','$monitor_map ref',$monitor_map) if $b_log; print Data::Dumper::Dumper $monitor_map if $dbg[45]; @@ -19059,17 +18827,30 @@ 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]]); } } } @@ -19078,28 +18859,15 @@ sub set_compositor_data { 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 cosmic-comp 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 ## @@ -19400,10 +19168,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]; } @@ -19496,7 +19263,7 @@ sub component_recursive_data { } ## MachineItem -# Public: get(), is_vm() +# public methods: get(), is_vm() { my $b_vm; package MachineItem; @@ -19533,7 +19300,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); @@ -19584,12 +19351,13 @@ sub is_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) = @_; @@ -19703,8 +19471,13 @@ 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 ($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'}; @@ -19761,18 +19534,16 @@ sub machine_soc_output { 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/machine/fruid/fruid-e904-1_full.txt"; - # $file = "$fake_data_dir/machine/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; @@ -19785,10 +19556,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]; @@ -19797,11 +19574,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); @@ -19810,7 +19671,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)); @@ -19950,15 +19812,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; @@ -20008,8 +19872,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; @@ -20040,6 +19906,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'){ @@ -20125,7 +19994,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 @@ -20897,7 +20766,7 @@ 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){ @@ -20922,7 +20791,7 @@ 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; @@ -21445,7 +21314,8 @@ sub set_partitions { 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|s3fs|smb|ssh'; + 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'); @@ -21928,7 +21798,8 @@ sub set_filters { # 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, vdfs, vmfs, wekafs, xtreemfs + # 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, @@ -21938,11 +21809,11 @@ sub set_filters { # 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/loop[0-9]+, /run(/.*)?, /sys/.* + # 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 xbfuse%; + 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 @@ -21955,12 +21826,12 @@ sub set_filters { 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 $start = '(fuse(blk)?[\._-]?)?('; + my $begin = '(fuse(blk)?[\._-]?)?('; my $end = ')([\._-]?fuse)?(fs)?\d{0,2}'; - $fs_exclude = $start . join('|',@exclude) . $end; - $fs_skip = $start . join('|',@exclude,'f') . $end; # apfs?; BSD ffs has no u/l + $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\/loop[0-9]+|\/run(\/.*)?|\/sys\/.*)'; + $part_filter .= '\/dev|\/dev\/(block\/)?loop[0-9]+|\/run(\/.*)?|\/sys\/.*)'; # print "$part_filter\n"; } @@ -22111,12 +21982,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); } @@ -22138,26 +22017,22 @@ 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 }); @@ -22166,8 +22041,12 @@ 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, @@ -22176,12 +22055,12 @@ sub cpu_processes { if ($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 "; @@ -22193,19 +22072,17 @@ 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; @@ -22216,10 +22093,7 @@ sub mem_processes { $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 }); @@ -22228,15 +22102,16 @@ 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, @@ -22245,10 +22120,10 @@ sub mem_processes { if ($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 "; @@ -22260,7 +22135,8 @@ 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/^\/.*\///; @@ -22274,16 +22150,9 @@ 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])" : ''; } } @@ -23537,14 +23406,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; if ($bsd_type && !$force{'dmidecode'} && ($dboot{'ram'} || $fake{'dboot'})){ - $ram = dboot_data(); + dboot_data($ram); if (@$ram){ ram_output($rows,$ram,'dboot'); } @@ -23557,21 +23426,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, { @@ -23601,52 +23492,72 @@ sub ram_output { 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'}; - } - # 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'}; - } - } - 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'; @@ -23656,11 +23567,6 @@ sub ram_output { $j = scalar @$rows; # 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, { @@ -23722,6 +23628,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'}; } @@ -23734,62 +23643,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 ($derived_module_size,$max_cap_5,$max_cap_16,$max_module_size, - $slots_active) = (0,0,0,0,0); + 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 # ($derived_module_size,$max_cap_5,$max_cap_16,$max_module_size) = (0,0,0,0); if ($entry->[0] == 5){ - $slots_active = 0; + $slots_active[$k] = 0; foreach my $item (@$entry){ @temp = split(/:\s*/, $item, 2); next if !$temp[1]; @@ -23810,7 +23854,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'} = []; @@ -23835,7 +23879,7 @@ sub dmidecode_data { $temp[1] =~ s/ Connection\)?//; $temp[1] =~ s/^[0-9]+\s*[KkMGTP]B\s*\(?//; $type = lc($temp[1]); - $slots_active++; + $slots_active[$k]++; } elsif ($temp[0] eq 'Current Speed'){ $speed = main::clean_dmi($temp[1]); @@ -23862,12 +23906,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++; } @@ -23875,7 +23923,7 @@ sub dmidecode_data { $handle = $entry->[1]; $ram->[$handle] = $ram->[$k] if $ram->[$k]; $ram->[$k] = undef; - $slots_active = 0; + $slots_active[$handle] = 0; # ($derived_module_size,$max_cap_16) = (0,0); foreach my $item (@$entry){ @temp = split(/:\s*/, $item, 2); @@ -23895,8 +23943,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]; @@ -23911,8 +23965,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); @@ -23940,10 +23994,10 @@ sub dmidecode_data { $derived_module_size = calculate_size($temp[1],$derived_module_size); $working_size = calculate_size($temp[1],0); $device_size = $working_size; - $slots_active++; + $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'){ @@ -23964,15 +24018,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 # 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; + 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]); @@ -24000,16 +24076,8 @@ 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 @@ -24029,28 +24097,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; + $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; @@ -24073,103 +24133,313 @@ sub dmidecode_data { } } print 'dmidecode pre process_data: ', Data::Dumper::Dumper $ram if $dbg[36]; - main::log_data('dump','@$ram',$ram) if $b_log; + main::log_data('dump','pre @$ram',$ram) if $b_log; process_data($ram) if @$ram; - main::log_data('dump','@$ram',$ram) if $b_log; + 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,$slots_active,$subtract) = (0,0,0,0); - my ($holder); - 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'}; + 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++; - $slots_active = 0; } - 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; + } } - # 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; + 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); # mbfix: /1024 - $type = $2; - $slots_active++; - 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; } - $derived_module_size = $size if $size > $derived_module_size; - $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; - $ram->[$arr]{'slots-active'} = $slots_active; - $ram->[$arr]{'slots-qualifier'} = $est; - $ram->[$arr]{'eec'} = $ecc; - $ram->[$arr]{'derived-module-size'} = $derived_module_size; - $ram->[$arr]{'used-capacity'} += $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 '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]; + 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; +} + +# 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; - return $ram; } sub process_data { @@ -24346,6 +24616,7 @@ sub process_data { 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'}, @@ -24365,24 +24636,96 @@ sub process_data { 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; +} + +# 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"; @@ -24396,35 +24739,37 @@ sub process_size { $size = sprintf("%.2f",$size) if $b_trim; $size =~ s/\.[0]+$//; $size = "$size $unit"; + eval $end if $b_log; return $size; } -# arg: 0: size string; 1: working size. If calculated result > $size, uses new -# value. If $data not valid, returns 0. -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); - # 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]; } # BSD: Map string to speed, in MT/s -sub speed_mapper { - my ($type) = @_; - my %speeds = ( +sub set_speed_maps { + $speed_maps = { # DDR1 'PC-1600' => 200, 'PC-2100' => 266, @@ -24450,7 +24795,9 @@ sub speed_mapper { '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, @@ -24471,10 +24818,18 @@ sub speed_mapper { '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 { @@ -24558,6 +24913,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 @@ -24567,7 +24923,7 @@ 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); @@ -24610,7 +24966,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); @@ -24625,7 +24981,7 @@ sub get { 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]); @@ -24668,6 +25024,8 @@ sub get_repos_linux { 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'; @@ -24838,14 +25196,14 @@ sub get_repos_linux { } } ## sbopkg, sboui, slackpkg, slackpkg+, slapt_get, slpkg: Slackware + derived - # $slpkg = "$ENV{'HOME'}/bin/scripts/inxi/data/repo/slackware/slpkg-2.toml"; - # $sbopkg = "$ENV{HOME}/bin/scripts/inxi/data/repo/slackware/sbopkg-2.conf"; - # $sboui_backend = "$ENV{HOME}/bin/scripts/inxi/data/repo/slackware/sboui-backend-1.conf"; + # $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 = "$ENV{HOME}/bin/scripts/inxi/data/repo/slackware/sbopkg-root-1.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; @@ -25186,7 +25544,7 @@ sub get_repos_linux { push(@content, "$1 ~ $type"); } } - if (! @content){ + if (!@content){ $key = repo_data('missing','cards'); } else { @@ -25199,6 +25557,11 @@ sub get_repos_linux { ); @content = (); } + ## 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){ @@ -25224,7 +25587,7 @@ sub get_repos_linux { } ## 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 @@ -25531,6 +25894,8 @@ sub set_repo_keys { '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', @@ -28664,87 +29029,38 @@ sub set_build_prop { eval $end if $b_log; } -## CompilerVersion -{ -package CompilerVersion; - -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 { +# Return all detected compiler versions +# args: 0: compiler +sub get_compiler_data { 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] =~ /.*(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 (ref $compiler ne 'ARRAY' || !@$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; -} - -# 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'; - } - 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 { @@ -28926,265 +29242,172 @@ 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 +# 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(); - } - if (!@$desktop){ - get_env_xfce_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){ - get_env_xprop_misc_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'}) : ''; -} +## DE SPECIFIC IDS ## -# 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*//i; - return $_[0]; -} - -sub get_kde_trinity_data { +# 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; + # 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); } - if ($extra > 1 && @version_data){ - $desktop->[2] = 'Qt'; - $desktop->[3] = main::awk(\@version_data,'^Qt:',2,'\s+') if @version_data; + # 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'; } - # 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 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'; + 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]; } } - # 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 ($desktop->[0]){ + if ($extra > 1 && ($program = main::check_program('efl-version'))){ + ($desktop->[2],$desktop->[3]) = ProgramData::full('efl-version',$program); } - if ($extra > 1 && @version_data){ - $desktop->[2] = 'Qt'; - $desktop->[3] = main::awk(\@version_data,'^Qt:',2,'\s+') if @version_data; + $desktop->[2] ||= 'EFL' if $extra > 1; + if ($b_dbg_de){ + de_wm_debugger('de ' . $desktop->[0] . ' v_src,program,desktop', + [$v_src,$program,$desktop]); } } eval $end if $b_log; } -sub get_env_de_data { +# GNOME/CINNAMON/MATE # +sub de_gnome_based_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; - } - } - } - eval $end if $b_log; -} - -sub get_env_xprop_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' || ($b_xprop && - (main::check_program('muffin') || main::check_program('cinnamon-session')) && - main::awk(\@xprop,'_muffin'))){ - ($desktop->[0],$desktop->[1]) = main::program_data('cinnamon','cinnamon',0); - $b_gtk = 1; + if ($xdg_desktop eq 'cinnamon' || $gdmsession eq 'cinnamon' || + (($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'; + de_wm_debugger('gnome test 1 $desktop',$desktop) 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'; + de_wm_debugger('gnome test 2 $desktop',$desktop) 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'; + de_wm_debugger('gnome test 3 $desktop $desktop',$desktop) if $b_dbg_de; } eval $end if $b_log; } @@ -29202,7 +29425,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'; } @@ -29225,21 +29448,147 @@ 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){ + de_wm_debugger('gnome $detection','detect-type: ' . $detection); + } main::log_data('data','$detection:$b_gnome>>' . $detection . ":$b_gnome") if $b_log; eval $end if $b_log; return $b_gnome; } +# 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; + if ($b_dbg_de){ + de_wm_debugger('kde trinity $program,$v_data,$desktop', + [$program,$v_data,$desktop]); + } + } + # 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; + if ($b_dbg_de){ + de_wm_debugger('kde 4 program,v_data,$desktop', + [$program,$v_data,$desktop]); + } + } + # 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); + } + } + } + if ($b_dbg_de){ + de_wm_debugger('kde >= 5 v_src,tk_src,fw_src,v_data,$desktop', + [$v_src,$tk_src,$fw_src,$v_data,$desktop]); + } + } + } + # 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; + de_wm_debugger('kde 3.5 de+qt $desktop',$desktop) if $b_dbg_de; + } + eval $end if $b_log; +} + +# XFCE # # Not strictly dependent on xprop data, which is not necessarily always present -sub get_env_xfce_data { +sub de_xfce_data { eval $start if $b_log; - my (@version_data); - # 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_desktop to xfce to solve some @@ -29247,98 +29596,118 @@ sub get_env_xfce_data { # $xdg_desktop can be /usr/bin/startxfce4 # print "xdg_d: $xdg_desktop gdms: $gdmsession\n"; if ($xdg_desktop eq 'xfce' || $gdmsession eq 'xfce' || - ($b_xprop && main::check_program('xfdesktop')) && - main::awk(\@xprop,'^(xfdesktop|xfce)')){ - @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]){ my $version = '4'; # just assume it's 4, we tried - if (main::check_program('xfce4-panel')){ + if ($program = main::check_program('xfce4-panel')){ $version = '4'; } # talk to xfce to see what id they will be using for xfce 5 - elsif (main::check_program('xfce5-panel')){ + elsif ($program = main::check_program('xfce5-panel')){ $version = '5'; } # they might get rid of number, we'll see - elsif (main::check_program('xfce-panel')){ + elsif ($program = main::check_program('xfce-panel')){ $version = ''; } - @data = main::program_values("xfce${version}-panel"); - # print Data::Dumper::Dumper \@data; + # 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']); } + de_wm_debugger('xfce $program,$desktop',[$program,$desktop]) if $b_dbg_de; } eval $end if $b_log; } -# These require data from xprop, at least partially -sub get_env_xprop_misc_data { +## GENERAL DE TESTS ## +sub de_env_data { eval $start if $b_log; - # print join("\n", @xprop), "\n"; - if ($xdg_desktop eq 'moksha' || $gdmsession eq 'moksha' || ($b_xprop && - (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'; - if ($b_xprop){ - $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' || - ($b_xprop && 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'; - if ($b_xprop){ - $desktop->[1] = main::awk(\@xprop,'(enlightenment|moksha)_version',2,'\s+=\s+'); - $desktop->[1] =~ s/"?(Moksha|Enlightenment)\s([^"]+)"?/$2/i if $desktop->[1]; + if (!$desktop->[0]){ + 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 =( + [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){ + # 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]; + } + de_wm_debugger('env de-wm',$desktop) if $b_dbg_de; + last; + } } } + eval $end if $b_log; +} + +# These require data from xprop. +sub de_misc_data { + eval $start if $b_log; + # 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. get_ps_de_data() and get_wm() will handle alternate wm detections. - # I believe all these will be X only wm, so xprop tests fine here. - if ($b_xprop && !$desktop->[0]){ - # 0 check program; 1 xprop search; 2: data; 3 - optional: ps_gui search - 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'], - ); - 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]); + # 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); + de_wm_debugger('de misc $program,$desktop',[$program,$desktop]) if $b_dbg_de; last; } } @@ -29347,201 +29716,231 @@ sub get_env_xprop_misc_data { eval $end if $b_log; } -sub get_ps_de_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){ +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]); + } + de_wm_debugger('ps de test 1 $desktop',$desktop) 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); + de_wm_debugger('ps de test 2 $desktop',$desktop) 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'); + de_wm_debugger('gtk $desktop 2,3',[$desktop->[2],$desktop->[3]]) 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])){ + de_wm_debugger('qt $program,qt,v $desktop 2,3', + [$program,$desktop->[2],$desktop->[3]]); } 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]){ + de_wm_debugger('ps wm,v $desktop 5,6',[$desktop->[5],$desktop->[6]]) 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); + if ($b_dbg_de){ + de_wm_debugger('xprop wm,v $desktop 5,6', [$desktop->[5],$desktop->[6]]); + } 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]); + de_wm_debugger('wmctrl wm,v $desktop 5,6',[$desktop->[5],$desktop->[6]]) 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'; @@ -29550,56 +29949,181 @@ 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'}}){ + my $sep = ','; + main::set_join_sep($ps_data{'components-active'},\$sep); + $desktop->[4] = join($sep, @{$ps_data{'components-active'}}); + } + eval $end if $b_log; +} + +sub tools_data { + eval $start if $b_log; + # these are running/active + if (@{$ps_data{'tools-active'}}){ + my $sep = ','; + main::set_join_sep($ps_data{'tools-active'},\$sep); + $desktop->[7] = join($sep, @{$ps_data{'tools-active'}}); + } + # 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){ + my $sep = ','; + main::set_join_sep($installed,\$sep); + $desktop->[8] = join($sep, @$installed); + } } - if (@info){ - main::uniq(\@info); - $desktop->[4] = join(', ', @info); + eval $end if $b_log; +} + +## UTILITIES ## +# args: 0: $type; 1: data +sub de_wm_debugger { + my ($type,$data) = @_; + 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 --dbg 63 used, we want this to print out + if (!$b_log || ($dbg[63] && $debugger{'level'} < 10)){ + unshift(@result,'------------------'); + push(@result,"------------------\n") if $b_log; + print join("\n",@result); } + else { + main::log_data('dump','de dbg @result',\@result); + } +} + +# 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'}) : ''; + de_wm_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]) 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"; + de_wm_debugger('xprop data: working, results',[$data,\%xprop]) if $b_dbg_de; eval $end if $b_log; } } @@ -30711,22 +31235,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'; @@ -30741,9 +31277,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 @@ -30751,58 +31310,50 @@ 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 @@ -30886,10 +31437,12 @@ sub get_linux_distro { $os_release_good_s .= '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 = 'antergos|chakra|guix|mageia|manjaro|oracle|pclinuxos|porteux|'; - $osr_good .= 'raspberry pi os|slint|zorin'; + 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 - my $osr_pretty = 'zinc'; + # devuan should catch many devuans spins, which often put their names in pretty + my $osr_pretty = 'devuan|slackel|zinc'; + my $distro_file_name = 'slitaz'; # these may not have the distro name in the file my ($b_issue,$b_lsb,$b_osr_pretty,$b_skip_issue,$b_skip_osr); my ($issue,$lsb_release) = ('/etc/issue','/etc/lsb-release'); # Note: OpenSuse Tumbleweed 2018-05 has made /etc/issue created by sym link to /run/issue @@ -30940,6 +31493,7 @@ sub get_linux_distro { } elsif (grep {/($osr_pretty)/i} @osr){ $b_osr_pretty = 1; + $distro_file = $os_release; } } if (grep {/armbian/} @distro_files){ @@ -31046,9 +31600,8 @@ sub get_linux_distro { } 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); + # No standard paths or files for os data, use pm version + ($distro,my $version) = ProgramData::full('guix'); $distro .= " $version" if $version; $b_skip_issue = 1; } @@ -31110,9 +31663,22 @@ sub get_linux_distro { if ($extra == 0){$distro =~ s/Debian\s*GNU\/Linux/Raspberry Pi OS/;} else {$distro = 'Raspberry Pi OS';} } + # check for spins, relies on xdg directory name + elsif ($distro =~ /^(Ubuntu)/i){ + my $base = $1; + my $temp = distro_spin($distro); + if ($temp ne $distro){ + $system_base = $base if !$system_base && $extra > 0; + $distro = $temp; + } + } elsif (-d '/etc/salixtools/' && $distro =~ /Slackware/i){ $distro =~ s/Slackware/Salix/; } + elsif ($distro_file =~ /($distro_file_name)/ && $distro =~ /^[\d\.]+$/){ + $distro_file =~ s/\/etc\/|[-_]|release|version//g; + $distro = ucfirst($distro_file) . ' ' . $distro; + } } else { # android fallback, sometimes requires root, sometimes doesn't @@ -31176,6 +31742,8 @@ sub system_base { # detect debian steamos before arch steamos 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|bodhi|mx-version'; # base only found in issue @@ -31186,7 +31754,11 @@ sub system_base { 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 + # 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 @@ -31195,7 +31767,7 @@ sub system_base { my $base_upstream_osr = '/etc/upstream-release/os-release'; # These id as themselves, but system base is version file. Slackware mostly. my %base_version = ( - 'porteux|salix|slint' => '/etc/slackware-version', + 'porteux|salix|slackel|slint' => '/etc/slackware-version', ); # First: try, some distros have upstream-release, elementary, new mint # and anyone else who uses this method for fallback ID @@ -31210,6 +31782,7 @@ sub system_base { (@osr_temp,@osr_working) = (); } } + # 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); } @@ -31225,7 +31798,13 @@ sub system_base { } # 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(); + $system_base = debian_id('debian'); + } + elsif (grep {/($base_osr_devuan_version)/i} @osr){ + $system_base = debian_id('devuan'); + } + elsif (grep {/($base_osr_fedora)/i} @osr){ + $base_type = 'fedora'; } elsif (grep {/($base_osr_redhat)/i} @osr){ $base_type = 'rhel'; @@ -31244,7 +31823,7 @@ sub system_base { } if (!$system_base && @distro_files && (grep {/($base_file_debian_version)/i} @distro_files)){ - $system_base = debian_id(); + $system_base = debian_id('debian'); } if (!$system_base && $lc_issue && $lc_issue =~ /($base_manual)/){ my $id = $1; @@ -31255,8 +31834,14 @@ sub system_base { ); $system_base = $manual{$id}; } - if (!$system_base && $distro && $distro =~ /^($base_distro_arch)/i){ - $system_base = 'Arch Linux'; + if (!$system_base && $distro){ + if ($distro =~ /^($base_distro_arch)/i){ + $system_base = 'Arch Linux'; + } + elsif ($distro =~ /^peppermint/i){ + my $type = (-f '/etc/devuan_version') ? 'devuan': 'debian'; + $system_base = debian_id($type); + } } if (!$system_base && $distro){ foreach my $key (keys %base_version){ @@ -31374,8 +31959,12 @@ sub get_os_release { $working[1] =~ s/^(debian|ubuntu\sdebian|debian\subuntu)/ubuntu/; $base_name = $working[1]; } + elsif ($base_type eq 'fedora' && $working[1] =~ /fedora/i){ + $base_name = 'Fedora'; + $base_version = $version_id if $version_id; + } # oracle ID_LIKE="fedora". Why? who knows. - if ($base_type eq 'rhel' && $working[1] =~ /rhel|fedora/i){ + elsif ($base_type eq 'rhel' && $working[1] =~ /rhel|fedora/i){ $base_name = 'RHEL'; $base_version = $version_id if $version_id; } @@ -31416,7 +32005,12 @@ sub get_os_release { } } if ($version_codename && $distro_osr !~ /$version_codename/i){ - $distro_osr .= " $version_codename"; + my @temp = split(/\s*[\/\s]\s*/, $version_codename); + foreach (@temp){ + if ($distro_osr !~ /\b$_\b/i){ + $distro_osr .= " $_"; + } + } } } # note: mint has varying formats here, some have ubuntu as name, 17 and earlier @@ -31428,7 +32022,7 @@ sub get_os_release { $distro =~ s/ $version_codename//; } # mint 17 used ubuntu os-release, so won't have $base_version, steamos holo - if ($base_name && $base_type eq 'rhel'){ + if ($base_name && ($base_type eq 'fedora' || $base_type eq 'rhel')){ $distro_osr = $base_name; $distro_osr .= ' ' . $version_id if $version_id; } @@ -31450,48 +32044,118 @@ sub get_os_release { $distro_osr = ($name && $version_name) ? "$name $version_name": $name_pretty; } elsif ($base_type eq 'debian' && $base_version){ - $distro_osr = debian_id($base_version); + $distro_osr = debian_id('debian',$base_version); + } + # not used yet + elsif ($base_type eq 'devuan' && $base_version){ + $distro_osr = debian_id('devuan',$base_version); } } eval $end if $b_log; return $distro_osr; } -# args: 0: optional: debian codename +# 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 $name; +} + +# args: 0: $type [debian|devuan]; 1: optional: debian codename sub debian_id { eval $start if $b_log; - my ($codename) = @_; - my ($debian_version,$id); - if (-r '/etc/debian_version'){ - $debian_version = main::reader('/etc/debian_version','strip',0); - } - $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', - '14' => 'forky', - ); - 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 + ); } - elsif ($codename){ - my %by_value = reverse %debians; - my $version = (main::is_numeric($debian_version)) ? "$debian_version $codename": $debian_version; - $id .= " $version"; + # 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)}; } - # like buster/sid - elsif ($debian_version){ - $id .= " $debian_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; + } + } + if ($version){ + my @temp = split(/\s*[\/\s]\s*/, $version); + foreach (@temp){ + if ($distro !~ /\b$_\b/i){ + $id .= " $_"; + } + } } eval $end if $b_log; return $id; @@ -31659,40 +32323,7 @@ sub get_driver_modules { return $modules; } -# Return all detected gcc versions -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-*'); - # usually like gcc-11 but sometimes gcc-11.2.0 - foreach (@temp){ - if (/\/gcc-([0-9.]+)$/){ - push(@$gccs, $1) if !$gcc || $1 ne $gcc; - } - } - } - unshift(@$gccs, $gcc) if $gcc; - log_data('dump','@gccs',$gccs) if $b_log; - eval $end if $b_log; - return $gccs; -} - -## GlabelData - set/get +## GlabelData: public methods: set(), get() # Used only to get RAID ZFS gptid path standard name, like ada0p1 { package GlabelData; @@ -31766,6 +32397,7 @@ sub get { 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. @@ -31773,10 +32405,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 = ''; @@ -31795,20 +32427,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/){ @@ -31832,28 +32459,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'; } @@ -31861,7 +32491,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); } } @@ -31894,30 +32524,20 @@ sub get { }; } -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? @@ -32192,6 +32812,95 @@ sub get_kernel_clocksource { 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) = (''); @@ -32251,7 +32960,7 @@ sub parameters_bsd { } } -## LsblkData - set/get +## LsblkData: public methods: set(), get() { package LsblkData; @@ -32491,18 +33200,18 @@ sub proc_iomem { my $b_reserved; no warnings 'portable'; if ($fake{'iomem'}){ - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-128gb-1.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-544mb-igpu.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-64mb-vram-stolen.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-rh-1-matrox.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-2-vram.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-512mb-1.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-518mb-reserved-1.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-512mb-2-onboardgpu-active.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-512mb-system-1.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-257.18gb-system-1.txt"; - # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-192gb-system-1.txt"; - $file = "$ENV{'HOME'}/bin/scripts/inxi/data/memory/proc-iomem-1012mb-igpu.txt"; + # $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]){ @@ -33020,7 +33729,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 { @@ -33031,7 +33740,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; @@ -33041,23 +33750,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'}){ @@ -33081,8 +33790,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 = ( @@ -33093,7 +33802,7 @@ sub package_counts { ['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 --showformat=\'${Package}\n\'',1,0,'','', - ['apt','apt-get','aptitude','deb-get','nala','synaptic']], + ['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,''], @@ -33111,8 +33820,8 @@ 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_add','pkg_info','p','',1,0,''], # OpenBSD has set of tools, not 1 pm @@ -33129,8 +33838,13 @@ sub package_counts { # 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\''], @@ -33138,6 +33852,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,''], @@ -33150,26 +33865,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]){ @@ -33186,19 +33901,23 @@ sub package_counts { $gs = ''; } } - $pmts = join(',',sort @tools) if @tools; + if (@tools){ + my $sep = ','; + main::set_join_sep(\@tools,\$sep); + $pmts = join($sep,sort @tools); + } } $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; } @@ -33956,7 +34675,7 @@ sub _round { } } -## PartitionData - set/get +## PartitionData: public methods: set(), get() # for /proc/partitions only, see DiskDataBSD for BSD partition data. { package PartitionData; @@ -34103,132 +34822,856 @@ 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; + # 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; + } + if ($power->{$_}){ + $power->{$_} =~ s/\s+/,/g; + $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 ($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'); + 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-daemons'} +{ +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 = 'apache|brave|chrom(e|ium)|falkon|(fire|water)fox|gvfs|http|'; + $pattern .= 'konqueror|mariadb|midori|mysql|nfsd|nginx|openvpn|opera|'; + $pattern .= 'pale|postgre|php|qtwebengine|smbd|smtp|sssd|vivald'; for (@$ps){ next if !$_; next if $self_name eq 'inxi' && /\/$self_name\b/; $_ = 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; } -sub set_ps_gui { +# 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_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 WindowMaker 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 cosmic-comp 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 smithay 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/; # remember qr/../i only added perl 5.014 + # 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]){ + DesktopData::de_wm_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'}]); + } + 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_power { + eval $start if $b_log; + process_items(\@{$ps_data{'power-daemons'}},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-daemons'} if $dbg[5]; + main::log_data('dump','$ps_data{power-daemons}',$ps_data{'power-daemons'}) 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 { @@ -34462,7 +35905,7 @@ my $b_debug = 0; # disable all debugger output in case forget to comment out! # 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); @@ -34514,7 +35957,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; @@ -34533,7 +35976,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]; } @@ -34552,7 +35995,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'}; @@ -34660,6 +36103,7 @@ sub parent_name { 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'); @@ -36072,21 +37516,6 @@ sub process_power { } } -# note: seen android instance where reading file wakeup_count hangs endlessly. -# 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. -sub get_wakeups { - eval $start if $b_log; - return if %risc; - my ($path,$wakeups); - # this increments on suspend, but you can't see it until wake, numbers work. - $path = '/sys/power/suspend_stats/success'; - $wakeups = reader($path,'strip',0) if -r $path; - eval $end if $b_log; - return $wakeups; -} - ######################################################################## #### GENERATE OUTPUT ######################################################################## @@ -36100,15 +37529,16 @@ 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); @@ -36323,37 +37753,69 @@ sub short_output { 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 ($index); my ($available,$gpu_ram,$parent,$percent,$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'; # should not be needed after fix but leave in case undef - } 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 $row = {}; 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; + } + $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-daemons'}}){ + my $sep = ','; + main::set_join_sep($ps_data{'power-daemons'},\$sep); + $data->{$data_name}[$index]{main::key($num++,0,2,'daemons')} = join($sep,@{$ps_data{'power-daemons'}}); + } + } + } + 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(); @@ -36383,32 +37845,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(); } @@ -36465,21 +37933,24 @@ sub system_item { 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,$cs_curr,$cs_avail,$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', ''); } @@ -36495,11 +37966,10 @@ sub system_item { $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,'available')} = $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'); @@ -36508,20 +37978,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] && @@ -36530,12 +38006,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'}){ @@ -36553,43 +38038,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]){ @@ -36601,13 +38103,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'){ @@ -1,5 +1,5 @@ .\" inxi.1 - manpage for inxi system information tool -.\" Copyright (C) 2023 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 "2023\-10\-31" "inxi" "inxi manual" +.TH INXI 1 "2024\-01\-30" "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. @@ -147,7 +147,7 @@ see API/sound server tools. 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 -.if +.fi .TP .B \-b \fR, \fB\-\-basic\fR @@ -327,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 @@ -511,16 +506,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 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 @@ -528,11 +537,11 @@ 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 @@ -645,11 +654,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 @@ -735,6 +739,8 @@ apt distros like PCLinuxOS or Alt\-Linux) \fBTCE\fR (TinyCore) +\fBTAZPKG\fR (Slitaz) + \fBURPMI\fR (Mandriva, Mageia + derived versions) \fBXBPS\fR (Void) @@ -866,7 +872,7 @@ 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 +\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. @@ -877,16 +883,6 @@ more verbose failure reports. 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. @@ -944,49 +940,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 @@ -995,7 +995,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. @@ -1053,8 +1053,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 @@ -1074,7 +1075,7 @@ 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. @@ -1435,8 +1436,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). @@ -1512,7 +1513,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 @@ -1531,7 +1532,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. @@ -1692,9 +1693,15 @@ did not find an X11 display ID, the ID (e.g. \fB:0.0\fR) will show here instead. .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. @@ -1751,6 +1758,9 @@ 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. @@ -1776,17 +1786,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 desktop toolkit (\fBtk\fR), if available (Xfce/KDE/Trinity). +\- 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 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 @@ -1795,7 +1807,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 @@ -1886,9 +1898,10 @@ 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. @@ -1930,6 +1943,10 @@ 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, + +.TP .B \-xxx \-N\fR \- Adds, if present, serial number. @@ -1949,21 +1966,25 @@ RAID events) .B \-xxx \-S\fR \- Adds current kernel clock source, if available (Linux only). -\- 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 (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, power daemons. 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). @@ -2325,24 +2346,34 @@ Graphics: .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 (\fBdaemons:\fR) running. + \- 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 + daemons: 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\-\-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 @@ -2408,6 +2439,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 @@ -2462,6 +2495,12 @@ Component report to 1 component per line. \- 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, @@ -2602,6 +2641,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). @@ -2668,10 +2710,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 @@ -2964,12 +3006,16 @@ 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 global 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 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 @@ -2979,8 +3025,11 @@ if \fB$XDG_CONFIG_HOME\fR is not empty, it will go there, else if \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/.config/inxi.conf\fR > -\fB$HOME/.inxi/inxi.conf\fR > \fB/etc/inxi.d/inxi.conf\fR > \fB/etc/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 @@ -3137,12 +3186,14 @@ You can also visit \fRchannel:\fI #smxi\fR to post issues on either network. .SH HOMEPAGE .I https://codeberg.org/smxi/inxi -\fR \- Home of the source code, and tech docs -(\fIinxi\-perl/docs\fR). +\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 -\fIinxi\-perl/docs\fR for more technical docs. +\fR \- The main docs for inxi. See pinxi repository for more technical +resources. .I https://fosstodon.org/@smxi \fR \- Follow @smxi on Mastodon! diff --git a/inxi.changelog b/inxi.changelog index 57f7612..08f21c4 100644 --- a/inxi.changelog +++ b/inxi.changelog @@ -1,4 +1,801 @@ ================================================================================ +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. + +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_gui 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_gui, 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 |
