diff options
| author | 2024-01-31 01:38:22 -0500 | |
|---|---|---|
| committer | 2024-01-31 01:38:22 -0500 | |
| commit | 30a050b995480aeeb8feeb1a43a0e3600f21f452 (patch) | |
| tree | b90d177c983486b923f357af6b4066ea65887d35 /inxi | |
| parent | 430dbb23a91d6a1374a28ba399d05ba8316ab121 (diff) | |
| parent | e09bcc3824ae2b8891f00085157f49e0f2245e6e (diff) | |
Update upstream source from tag 'upstream/3.3.32-1'
Update to upstream version '3.3.32-1'
with Debian dir 28a3946091c2d40f4423ccf4a1f306e996ee7a4b
Diffstat (limited to 'inxi')
| -rwxr-xr-x | inxi | 5771 |
1 files changed, 3636 insertions, 2135 deletions
@@ -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'){ |
