diff options
Diffstat (limited to 'inxi')
| -rwxr-xr-x | inxi | 4079 |
1 files changed, 3057 insertions, 1022 deletions
@@ -2,6 +2,7 @@ ## infobash: Copyright (C) 2005-2007 Michiel de Boer aka locsmif ## inxi: Copyright (C) 2008-2021 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> ## Steven Barrett (aka: damentz) - usb audio patch; swap percent used patch ## Jarett.Stevens - dmidecode -M patch for older systems without /sys machine @@ -47,8 +48,8 @@ use POSIX qw(ceil uname strftime ttyname); ## INXI INFO ## my $self_name='inxi'; -my $self_version='3.3.12'; -my $self_date='2022-01-18'; +my $self_version='3.3.13'; +my $self_date='2022-02-22'; my $self_patch='00'; ## END INXI INFO ## my ($b_pledge,@pledges); @@ -103,7 +104,8 @@ if (eval {require Time::HiRes}){ my ($b_admin,$b_android,$b_busybox_ps,$b_cygwin,$b_display,$b_irc,$b_root); ## System -my ($bsd_type,$device_vm,$language,$os,$pci_tool,$wan_url) = ('','','','','',''); +my ($bsd_type,$device_vm,$language,$os,$pci_tool) = ('','','','',''); +my ($wan_url,$wl_compositors) = ('',''); my ($bits_sys,$cpu_arch,$ppid); my ($cpu_sleep,$dl_timeout,$limit,$ps_cols,$ps_count) = (0.35,4,10,0,5); my $sensors_cpu_nu = 0; @@ -514,6 +516,8 @@ sub set_os { } elsif ($cpu_arch =~ /(alpha|64|e2k|sparc_v9|sun4[uv]|ultrasparc)/){ $bits_sys = 64; + # force to string e2k, and also in case we need that ID changed + $cpu_arch = 'elbrus' if $cpu_arch =~ /e2k|elbrus/; } $b_cygwin = 1 if $os =~ /cygwin/; $b_android = 1 if -e '/system/build.prop'; @@ -1845,7 +1849,7 @@ sub display_data { push(@files, $system_files{'xorg-log'}) if $system_files{'xorg-log'}; push(@files, '/etc/X11/xorg.conf'); copy_files(\@files,'display-xorg'); - print "Collecting X, xprop, glxinfo, xrandr, xdpyinfo data, wayland, weston...\n"; + print "Collecting X, xprop, glxinfo, xrandr, xdpyinfo data, Wayland info...\n"; %data = ( 'desktop-session' => $ENV{'DESKTOP_SESSION'}, 'gdmsession' => $ENV{'GDMSESSION'}, @@ -1892,21 +1896,34 @@ sub display_data { ['kwin_x11','--version'], # ['locate','/Xorg'], # for Xorg.wrap problem ['loginctl','--no-pager list-sessions'], + ['ls','/sys/class/drm'], ['nvidia-settings','-q screens'], ['nvidia-settings','-c :0.0 -q all'], ['nvidia-smi','-q'], ['nvidia-smi','-q -x'], ['plasmashell','--version'], + ['swaymsg','-t get_inputs -p'], + ['swaymsg','-t get_inputs -r'], + ['swaymsg','-t get_outputs -p'], + ['swaymsg','-t get_outputs -r'], + ['swaymsg','-t get_tree'], + ['swaymsg','-t get_workspaces -p'], + ['swaymsg','-t get_workspaces -r'], ['vainfo',''], ['vdpauinfo',''], ['vulkaninfo',''], + ['wayland-info',''], # not packaged as far as I know yet ['weston-info',''], ['wmctrl','-m'], ['weston','--version'], + ['wlr-randr',''], ['xdpyinfo',''], ['Xorg','-version'], ['xprop','-root'], ['xrandr',''], + ['Xvesa','-version'], + ['Xvesa','-listmodes'], + ['Xwayland','-version'], ); run_commands(\@cmds,'display'); } @@ -2143,13 +2160,14 @@ sub system_files { sub run_self { print "Creating $self_name output file now. This can take a few seconds...\n"; print "Starting $self_name from: $self_path\n"; + my $a = ($debugger{'arg'}) ? ' ' . $debugger{'arg'} : ''; my $i = ($option eq 'main-full')? ' -i' : ''; my $z = ($debugger{'filter'}) ? ' -z' : ''; my $w = ($debugger{'width'}) ? $debugger{'width'} : 120; - my $iz = "$i$z"; - $iz =~ s/[\s-]//g; - my $self_file = "$data_dir/$self_name-FERfJLrploudma$iz-slots-y$w.txt"; - my $cmd = "$self_path/$self_name -FERfJLrploudma$i$z --slots --debug 10 -y $w > $self_file 2>&1"; + my $aiz = "$i$z"; + $aiz =~ s/[\s-]//g; + my $self_file = "$data_dir/$self_name-FERfJLrploudma$aiz-slots-y$w.txt"; + my $cmd = "$self_path/$self_name -FERfJLrploudma$i$z$a --slots --debug 10 -y $w > $self_file 2>&1"; system($cmd); copy($log_file, "$data_dir") or main::error_handler('copy-failed', "$log_file", "$!"); system("$self_path/$self_name --recommends -y 120 > $data_dir/$self_name-recommends-120.txt 2>&1"); @@ -2229,7 +2247,7 @@ sub get_glob { else { $item = main::message('root-required'); } - $item = main::message('undefined') if ! defined $item; + $item = main::message('undefined') if !defined $item; push(@result,$_ . '::' . $item); } # print Data::Dumper::Dumper \@result; @@ -2899,9 +2917,9 @@ sub check_items { $info_os = 'info-bsd'; } else { - @data = qw(blockdev bt-adapter dig dmidecode doas fdisk file hciconfig - hddtemp ifconfig ip ipmitool ipmi-sensors lsblk lsusb lvs mdadm modinfo - runlevel sensors smartctl strings sudo tree upower uptime); + @data = qw(blockdev bt-adapter 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); } $b_program = 1; $item = 'Program'; @@ -2939,16 +2957,20 @@ sub check_items { } elsif ($type eq 'recommended Perl modules'){ @data = qw(File::Copy File::Find File::Spec::Functions HTTP::Tiny IO::Socket::SSL - Time::HiRes Cpanel::JSON::XS JSON::XS XML::Dumper Net::FTP); - push(@data, qw(OpenBSD::Pledge OpenBSD::Unveil)) if $bsd_type && $bsd_type eq 'openbsd'; + Time::HiRes JSON::PP Cpanel::JSON::XS JSON::XS XML::Dumper Net::FTP); + if ($bsd_type && $bsd_type eq 'openbsd'){ + push(@data, qw(OpenBSD::Pledge OpenBSD::Unveil)); + } $b_perl_module = 1; $item = 'Perl Module'; $extra = ' (Optional)'; - $extra2 = "None of these are strictly required, but if you have them all, you can - eliminate some recommended non Perl programs from the install. "; - $extra3 = "HTTP::Tiny and IO::Socket::SSL must both be present to use as a downloader option. - For json export Cpanel::JSON::XS is preferred over JSON::XS. To run --debug 20-22 File::Copy, - File::Find, and File::Spec::Functions must be present (most distros have these in Core Modules). + $extra2 = "None of these are strictly required, but if you have them all, + you can eliminate some recommended non Perl programs from the install. "; + $extra3 = "HTTP::Tiny and IO::Socket::SSL must both be present to use as a + downloader option. For json export Cpanel::JSON::XS is preferred over + JSON::XS, but JSON::PP is in core modules. To run --debug 20-22 File::Copy, + File::Find, and File::Spec::Functions must be present (most distros have + these in Core Modules). "; } elsif ($type eq 'recommended kernel modules'){ @@ -3006,9 +3028,9 @@ sub check_items { %info = item_data($item); $about = $info{$info_os}; if (($b_dir && -d $item) || ($b_file && -r $item) || - ($b_program && main::check_program($item)) || - ($b_perl_module && main::check_perl_module($item)) || - ($b_kernel_module && @modules && (grep {/^$item$/} @modules))){ + ($b_program && main::check_program($item)) || + ($b_perl_module && main::check_perl_module($item)) || + ($b_kernel_module && @modules && (grep {/^$item$/} @modules))){ $result = 'Present'; } elsif ($b_file && -f $item){ @@ -3210,6 +3232,13 @@ sub item_data { 'pacman' => '', 'rpm' => '', }, + 'fruid_print' => { + 'info' => '-M machine data, Elbrus only', + 'info-bsd' => '', + 'apt' => '', + 'pacman' => '', + 'rpm' => '', + }, 'glabel' => { 'info' => '', 'info-bsd' => '-R; -D; -P. Get actual gptid /dev path', @@ -3408,8 +3437,8 @@ sub item_data { }, # Display Tools 'glxinfo' => { - 'info' => '-G glx info', - 'info-bsd' => '-G glx info', + 'info' => '-G (X) glx info', + 'info-bsd' => '-G (X) glx info', 'apt' => 'mesa-utils', 'pacman' => 'mesa-demos', 'rpm' => 'glx-utils (SUSE: Mesa-demo-x)', @@ -3422,30 +3451,30 @@ sub item_data { 'rpm' => 'wmctrl', }, 'xdpyinfo' => { - 'info' => '-G multi screen resolution', - 'info-bsd' => '-G multi screen resolution', + 'info' => '-G (X) Screen resolution, dpi; -Ga Screen size', + 'info-bsd' => '-G (X) Screen resolution, dpi; -Ga Screen size', 'apt' => 'X11-utils', 'pacman' => 'xorg-xdpyinfo', 'rpm' => 'xorg-x11-utils (SUSE/Fedora?: xdpyinfo)', }, 'xprop' => { - 'info' => '-S desktop data', - 'info-bsd' => '-S desktop data', + 'info' => '-S (X) desktop data', + 'info-bsd' => '-S (X) desktop data', 'apt' => 'X11-utils', 'pacman' => 'xorg-xprop', 'rpm' => 'x11-utils', }, 'xrandr' => { - 'info' => '-G single screen resolution', - 'info-bsd' => '-G single screen resolution', + 'info' => '-G (X) monitors(s) resolution; -Ga monitor data', + 'info-bsd' => '-G (X) monitors(s) resolution; -Ga monitor data', 'apt' => 'x11-xserver-utils', 'pacman' => 'xrandr', 'rpm' => 'x11-server-utils (Fedora: xrandr)', }, # Perl Modules 'Cpanel::JSON::XS' => { - 'info' => '--output json - required for export.', - 'info-bsd' => '--output json - required for export.', + 'info' => '--output json (faster than JSON::PP).', + 'info-bsd' => '--output json (faster than JSON::PP).', 'apt' => 'libcpanel-json-xs-perl', 'pacman' => 'perl-cpanel-json-xs', 'rpm' => 'perl-Cpanel-JSON-XS', @@ -3485,9 +3514,16 @@ sub item_data { 'pacman' => 'perl-io-socket-ssl', 'rpm' => 'perl-IO-Socket-SSL', }, + 'JSON::PP' => { + 'info' => '--output json (in CoreModules, but slower).', + 'info-bsd' => '--output json (in CoreModules, but slower).', + 'apt' => 'libcpanel-json-xs-perl', + 'pacman' => 'perl-cpanel-json-xs', + 'rpm' => 'perl-Cpanel-JSON-XS', + }, 'JSON::XS' => { - 'info' => '--output json - required for export (legacy).', - 'info-bsd' => '--output json - required for export (legacy).', + 'info' => '--output json (legacy).', + 'info-bsd' => '--output json (legacy).', 'apt' => 'libjson-xs-perl', 'pacman' => 'perl-json-xs', 'rpm' => 'perl-JSON-XS', @@ -3751,6 +3787,34 @@ sub lister { closedir $dir; return @list; } +# checks for 1 of 3 perl json modules. All three have same encode_json, +# decode_json() methods. +sub load_json { + eval $start if $b_log; + $loaded{'json'} = 1; + # recommended, but not in core modules + if (check_perl_module('Cpanel::JSON::XS')){ + Cpanel::JSON::XS->import; + $use{'json'} = {'type' => 'cpanel-json-xs', + 'encode' => \&Cpanel::JSON::XS::encode_json, + 'decode' => \&Cpanel::JSON::XS::decode_json}; + } + # somewhat legacy, not in perl modules + elsif (check_perl_module('JSON::XS')){ + JSON::XS->import; + $use{'json'} = {'type' => 'json-xs', + 'encode' => \&JSON::XS::encode_json, + 'decode' => \&JSON::XS::decode_json}; + } + # perl, in core modules as of 5.14 + elsif (check_perl_module('JSON::PP')){ + JSON::PP->import; + $use{'json'} = {'type' => 'json-pp', + 'encode' => \&JSON::PP::encode_json, + 'decode' => \&JSON::PP::decode_json}; + } + eval $end if $b_log; +} # returns array of: 0: program print name 1: program version # args: 1: program values id 2: program version string @@ -3813,17 +3877,22 @@ sub set_program_values { '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 + 'chameleonwm' => ['^chameleon',0,'0','ChameleonWM',0,1,0,'',''], # unverified 'cinnamon' => ['^cinnamon',2,'--version','Cinnamon',0,1,0,'',''], 'clfswm' => ['^clsfwm',0,'0','clfswm',0,1,0,'',''], # no version + 'comfc' => ['^comfc',0,'0','comfc',0,1,0,'',''], # unverified 'compiz' => ['^compiz',2,'--version','Compiz',0,1,0,'',''], 'compton' => ['^\d',1,'--version','Compton',0,1,0,'',''], 'ctwm' => ['^\S',1,'-version','ctwm',0,1,0,'',''], @@ -3834,11 +3903,15 @@ sub set_program_values { '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 @@ -3850,18 +3923,24 @@ sub set_program_values { '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,'',''], - 'grefson' => ['^grefson',0,'0','grefson',0,1,0,'',''], # unverified + '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 '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',''], @@ -3869,13 +3948,19 @@ sub set_program_values { '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,'',''], @@ -3883,13 +3968,16 @@ sub set_program_values { '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,'',''], @@ -3903,23 +3991,31 @@ sub set_program_values { '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,'',''], + '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 + 'orbital' => ['^orbital',0,'0','Orbital',0,1,0,'',''],# unverified 'pantheon' => ['^pantheon',0,'0','Pantheon',0,1,0,'',''],# no version 'papyros' => ['^papyros',0,'0','papyros',0,1,0,'',''],# no version 'pekwm' => ['^pekwm',3,'--version','PekWM',0,1,0,'',''], 'penrose' => ['^penrose',0,'0','Penrose',0,1,0,'',''],# no version? 'perceptia' => ['^perceptia',0,'0','perceptia',0,1,0,'',''], + 'phoc' => ['^phoc',0,'0','phoc',0,1,0,'',''], # unverified 'picom' => ['^\S',1,'--version','Picom',0,1,0,'^v',''], 'plasmashell' => ['^plasmashell',2,'--version','KDE Plasma',0,1,0,'',''], + 'pywm' => ['^pywm',0,'0','pywm',0,1,0,'',''], # unverified 'qtile' => ['^',1,'--version','Qtile',0,1,0,'',''], 'qvwm' => ['^qvwm',0,'0','qvwm',0,1,0,'',''], # unverified 'razor-session' => ['^razor',0,'0','Razor-Qt',0,1,0,'',''], 'ratpoison' => ['^ratpoison',2,'--version','Ratpoison',0,1,0,'',''], + 'river' => ['^river',0,'0','River',0,1,0,'',''], # unverified + 'rootston' => ['^rootston',0,'0','rootston',0,1,0,'',''], # unverified, wlroot ref 'rustland' => ['^rustland',0,'0','rustland',0,1,0,'',''], # unverified 'sawfish' => ['^sawfish',3,'--version','Sawfish',0,1,0,'',''], 'scrotwm' => ['^scrotwm.*welcome.*',5,'-v','scrotwm',0,1,1,'',''], + 'simulavr' => ['simulavr^',0,'0','SimulaVR',0,1,0,'',''], # unverified + 'skylight' => ['^skylight',0,'0','Skylight',0,1,0,'',''], # unverified 'sommelier' => ['^sommelier',0,'0','sommelier',0,1,0,'',''], # unverified 'snapwm' => ['^snapwm',0,'0','snapwm',0,1,0,'',''], # unverified 'spectrwm' => ['^spectrwm.*welcome.*wm',5,'-v','spectrwm',0,1,1,'',''], @@ -3927,7 +4023,13 @@ sub set_program_values { '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 @@ -3938,15 +4040,23 @@ sub set_program_values { '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' => ['^way',0,'0','wayfire',0,1,0,'',''], # unverified + '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 + '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 @@ -3954,6 +4064,8 @@ sub set_program_values { 'wmii' => ['^wmii',1,'-v','wmii',0,1,0,'^wmii[234]?-',''], # wmii is wmii3 'wmii2' => ['^wmii2',1,'--version','wmii2',0,1,0,'^wmii[234]?-',''], 'wmx' => ['^wmx',0,'0','wmx',0,1,0,'',''], # no version + 'wxrc' => ['^wx',0,'0','',0,1,0,'WXRC',''], # unverified + 'wxrd' => ['^wx',0,'0','',0,1,0,'WXRD',''], # unverified 'xcompmgr' => ['^xcompmgr',0,'0','xcompmgr',0,1,0,'',''], # no version 'xfce4-panel' => ['^xfce4-panel',2,'--version','Xfce',0,1,0,'',''], 'xfce5-panel' => ['^xfce5-panel',2,'--version','Xfce',0,1,0,'',''], @@ -3965,6 +4077,7 @@ sub set_program_values { '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,'',''], @@ -3972,9 +4085,11 @@ sub set_program_values { 'qtdiag' => ['^qt',2,'--version','Qt',0,1,0,'',''], ## Display Managers (dm) ## 'cdm' => ['^cdm',0,'0','CDM',0,1,0,'',''], + '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,'',''], 'ldm' => ['^ldm',0,'0','LDM',0,1,0,'',''], @@ -3984,8 +4099,10 @@ sub set_program_values { 'mdm' => ['^mdm',0,'0','MDM',0,1,0,'',''], '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,'',''], + '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,'',''], @@ -4521,7 +4638,7 @@ sub get { } else { main::error_handler('bad-arg', $opt, $arg); - } }, + }}, 'C|cpu' => sub { $show{'short'} = 0; $show{'cpu'} = 1;}, @@ -4549,6 +4666,7 @@ sub get { $show{'disk'} = 1; $show{'graphic'} = 1; $show{'graphic-basic'} = 1; + $show{'graphic-full'} = 1; $show{'info'} = 1; $show{'machine'} = 1; $show{'network'} = 1; @@ -4561,7 +4679,8 @@ sub get { 'G|graphics|graphic' => sub { $show{'short'} = 0; $show{'graphic'} = 1; - $show{'graphic-basic'} = 1;}, + $show{'graphic-basic'} = 1; + $show{'graphic-full'} = 1;}, 'h|help|?' => sub { $show{'help'} = 1;}, 'i|ip' => sub { @@ -4588,7 +4707,7 @@ sub get { } else { main::error_handler('bad-arg',$opt,$arg); - } }, + }}, 'L|logical|lvm' => sub { $show{'short'} = 0; $show{'logical'} = 1;}, @@ -4630,7 +4749,7 @@ sub get { } else { main::error_handler('bad-arg',$opt,$arg); - } }, + }}, 'r|repos|repo' => sub { $show{'short'} = 0; $show{'repo'} = 1;}, @@ -4649,7 +4768,7 @@ sub get { } else { main::error_handler('bad-arg',$opt,$arg); - } }, + }}, 'slots|slot' => sub { $show{'short'} = 0; $show{'slot'} = 1;}, @@ -4674,7 +4793,7 @@ sub get { } else { main::error_handler('bad-arg',$opt,$arg); - } }, + }}, 'u|uuid' => sub { $show{'uuid'} = 1;}, 'v|verbosity:i' => sub { @@ -4711,11 +4830,11 @@ sub get { if ($arg >= 5){ $show{'audio'} = 1; $show{'bluetooth'} = 1; - $show{'ram'} = 1; + $show{'graphic-full'} = 1; $show{'label'} = 1; $show{'optical-basic'} = 1; - $show{'ram'} = 1; $show{'raid'} = 1; + $show{'ram'} = 1; $show{'sensor'} = 1; $show{'swap'} = 1; $show{'uuid'} = 1; @@ -4750,7 +4869,7 @@ sub get { } else { main::error_handler('bad-arg',$opt,$arg); - } }, + }}, 'V|version' => sub { $show{'version'} = 1 }, 'w|weather' => sub { @@ -4762,7 +4881,7 @@ sub get { } else { main::error_handler('distro-block', $opt); - } }, + }}, 'W|weather-location:s' => sub { my ($opt,$arg) = @_; $arg ||= ''; @@ -4780,7 +4899,7 @@ sub get { } else { main::error_handler('distro-block', $opt); - } }, + }}, 'ws|weather-source:s' => sub { my ($opt,$arg) = @_; # let api processor handle checks if valid, this @@ -4790,7 +4909,7 @@ sub get { } else { main::error_handler('bad-arg',$opt,$arg); - } }, + }}, 'weather-unit:s' => sub { my ($opt,$arg) = @_; $arg ||= ''; @@ -4803,7 +4922,7 @@ sub get { } else { main::error_handler('bad-arg',$opt,$arg); - } }, + }}, 'x|extra:i' => sub { my ($opt,$arg) = @_; if ($arg > 0){ @@ -4811,7 +4930,7 @@ sub get { } else { $extra++; - } }, + }}, 'y|width:i' => sub { my ($opt, $arg) = @_; if (defined $arg && $arg == -1){ @@ -4908,7 +5027,7 @@ sub get { } }, 'cygwin' => sub { - $b_cygwin = 1 }, + $b_cygwin = 1;}, 'dbg:i' => sub { my ($opt,$arg) = @_; if ($arg > 0){ @@ -4924,7 +5043,15 @@ sub get { } else { main::error_handler('bad-arg', $opt, $arg); - } }, + }}, + 'debug-arg:s' => sub { + my ($opt,$arg) = @_; + if ($arg){ + $debugger{'arg'} = $arg; + } + else { + main::error_handler('bad-arg', $opt, $arg); + }}, 'debug-filter|debug-z|debug-zy' => sub { $debugger{'filter'} = 1 }, 'debug-id:s' => sub { @@ -4934,7 +5061,7 @@ sub get { } else { main::error_handler('bad-arg', $opt, $arg); - } }, + }}, 'debug-no-eps' => sub { $debugger{'no-exit'} = 1; $debugger{'no-proc'} = 1; @@ -4962,7 +5089,7 @@ sub get { } else { main::error_handler('bad-arg', $opt, $arg); - } }, + }}, 'dig' => sub { $force{'no-dig'} = 0;}, 'display:s' => sub { @@ -4977,9 +5104,9 @@ sub get { } else { main::error_handler('bad-arg', $opt, $arg); - } }, + }}, 'dmi|dmidecode' => sub { - $force{'dmidecode'} = 1 }, + $force{'dmidecode'} = 1;}, 'downloader:s' => sub { my ($opt,$arg) = @_; $arg = lc($arg); @@ -5001,14 +5128,14 @@ sub get { } else { main::error_handler('bad-arg', $opt, $arg); - } }, + }}, 'fake:s' => sub { my ($opt,$arg) = @_; if ($arg){ - my $wl = 'bluetooth|compiler|cpu|dboot|dmidecode|ipmi|logical|lspci|'; + my $wl = 'bluetooth|compiler|cpu|dboot|dmidecode|elbrus|ipmi|logical|lspci|'; $wl .= 'partitions|pciconf|pcictl|pcidump|raid-btrfs|raid-hw|raid-lvm|'; - $wl .= 'raid-md|raid-soft|raid-zfs|sensors|sysctl|uptime|usbconfig|'; - $wl .= 'usbdevs|vmstat|xorg-log'; + $wl .= 'raid-md|raid-soft|raid-zfs|sensors|swaymsg|sysctl|'; + $wl .= 'uptime|usbconfig|usbdevs|vmstat|wl-info|wlr-randr|xorg-log|xrandr'; for (split(',',$arg)){ if ($_ =~ /\b($wl)\b/){ $fake{lc($1)} = 1; @@ -5025,7 +5152,7 @@ sub get { my ($opt,$arg) = @_; if ($arg){ my $wl = 'colors|cpuinfo|display|dmidecode|hddtemp|lsusb|man|meminfo|'; - $wl .= 'no-dig|no-doas|no-html-wan|no-sudo|pkg|usb-sys|vmstat|wmctrl'; + $wl .= 'no-dig|no-doas|no-html-wan|no-sudo|pkg|usb-sys|vmstat|wayland|wmctrl'; for (split(',',$arg)){ if ($_ =~ /\b($wl)\b/){ $force{lc($1)} = 1; @@ -5048,10 +5175,10 @@ sub get { main::error_handler('bad-arg', $opt, $arg); }}, 'hddtemp' => sub { - $force{'hddtemp'} = 1 }, + $force{'hddtemp'} = 1;}, 'host|hostname' => sub { $show{'host'} = 1; - $show{'no-host'} = 0}, + $show{'no-host'} = 0;}, 'html-wan' => sub { $force{'no-html-wan'} = 0;}, 'indent:i' => sub { @@ -5099,14 +5226,14 @@ sub get { 'no-doas' => sub { $force{'no-doas'} = 1;}, 'no-host|no-hostname' => sub { - $show{'host'} = 0 ; - $show{'no-host'} = 1}, + $show{'host'} = 0; + $show{'no-host'} = 1;}, 'no-html-wan' => sub { $force{'no-html-wan'}= 1;}, 'no-man' => sub { $use{'no-man'} = 0;}, 'no-ssl' => sub { - $dl{'no-ssl-opt'}=1 }, + $dl{'no-ssl-opt'} = 1;}, 'no-sudo' => sub { $force{'no-sudo'} = 1;}, 'output-file:s' => sub { @@ -5123,7 +5250,7 @@ sub get { main::error_handler('bad-arg', $opt, $arg); }}, 'pkg' => sub { - $force{'pkg'} = 1 }, + $force{'pkg'} = 1;}, 'ppc' => sub { undef %risc; $risc{'id'} = 'ppc'; @@ -5164,9 +5291,9 @@ sub get { my ($opt,$arg) = @_; process_updater($opt,$arg);}, 'usb-sys' => sub { - $force{'usb-sys'} = 1 }, + $force{'usb-sys'} = 1;}, 'usb-tool' => sub { - $force{'lsusb'} = 1 }, + $force{'lsusb'} = 1;}, 'wan-ip-url:s' => sub { my ($opt,$arg) = @_; if ($arg && $arg =~ /^(f|ht)tp[s]?:\/\//){ @@ -5176,8 +5303,10 @@ sub get { else { main::error_handler('bad-arg', $opt, $arg); }}, - 'wm' => sub { - $force{'wmctrl'} = 1 }, + 'wayland|wl' => sub { + $force{'wayland'} = 1;}, + 'wm|wmctrl' => sub { + $force{'wmctrl'} = 1;}, '<>' => sub { my ($opt) = @_; main::error_handler('unknown-option', "$opt", "");} @@ -5226,14 +5355,15 @@ sub post_process { !$show{'partition-full'} && !$show{'swap'} && !$show{'unmounted'}){ main::error_handler('bad-arg', '-l/-u', 'missing required option(s) -j, -o, -p, -P'); } - $show{'graphic-basic'} = 0 if $b_admin; + $extra = 3 if $b_admin; + $show{'graphic-basic'} = 0 if $show{'graphic-full'} && $extra > 1; if ($use{'sensors-default'}){ @sensors_exclude = (); @sensors_use = (); } if ($show{'short'} || $show{'disk'} || $show{'disk-basic'} || $show{'disk-total'} || - $show{'logical'} || $show{'partition'} || $show{'partition-full'} || $show{'raid'} || - $show{'unmounted'}){ + $show{'logical'} || $show{'partition'} || $show{'partition-full'} || $show{'raid'} || + $show{'unmounted'}){ $use{'block-tool'} = 1; } if ($show{'short'} || $show{'raid'} || $show{'disk'} || $show{'disk-total'} || @@ -5246,11 +5376,10 @@ sub post_process { } # triggers may extend to -D, -pP if ($show{'short'} || $show{'logical'} || $show{'raid'} || $show{'disk'} || - $show{'disk-total'} || $show{'disk-basic'} || $show{'unmounted'}){ + $show{'disk-total'} || $show{'disk-basic'} || $show{'unmounted'}){ $use{'logical'} = 1; } main::set_sudo() if ($show{'unmounted'} || ($extra > 0 && $show{'disk'})); - $extra = 3 if $b_admin; $use{'filter'} = 0 if $use{'filter-override'}; # override for things like -b or -v2 to -v3 $show{'cpu-basic'} = 0 if $show{'cpu'}; @@ -5404,8 +5533,8 @@ sub show_options { (except -J, -W) plus --swap, -s and -n. Does not show extra verbose options such as -d -f -i -J -l -m -o -p -r -t -u -x, unless specified."], ['1', '-G', '--graphics', "Graphics info (devices(s), drivers, display - protocol (if available), display server/Wayland compositor, resolution, - renderer, OpenGL version)."], + protocol (if available), display server/Wayland compositor, resolution, X.org: + renderer, OpenGL version; Xvesa: VBE info."], ['1', '-i', '--ip', "WAN IP address and local interfaces (requires ifconfig or ip network tool). Triggers -n. Not shown with -F for user security reasons. You shouldn't paste your local/WAN IP."], @@ -5560,7 +5689,7 @@ sub show_options { verbose or line output, not short form); check man page for explanations!; also sets --extra=3:"], ['2', '-A', '', "If available: list of alternate kernel modules/drivers - for device(s)."], + for device(s); PCIe lanes-max: gen, speed, lanes (if relevant)."], ['2', '-C', '', "If available: CPU socket type, base/boost speeds (dmidecode+root/sudo/doas required); Full topology line, with cores, threads, threads per core, granular cache data, smt status; CPU vulnerabilities (bugs); @@ -5570,10 +5699,9 @@ sub show_options { family; maj:min, USB drive specifics; SMART report."], ['2', '-E', '', "If available: in Report:, adds Info: line: acl-mtu, sco-mtu, link-policy, link-mode, service-classes."], - ['2', '-G', '', "If available: Xorg Display ID, Screens total, default Screen, - current Screen; per X Screen: resolution, dpi, size, diagonal; per Monitor: - resolution; hz; dpi; size; diagonal; list of alternate kernel modules/drivers - for device(s)."], + ['2', '-G', '', "PCIe lanes-max: gen, speed, lanes (if relevant); list of + alternate kernel modules/drivers for device(s) (if available); Monitor built + year, gamma, screen ratio (if available)."], ['2', '-I', '', "As well as per package manager counts, also adds total number of lib files found for each package manager if not -r; adds init service tool."], @@ -5582,7 +5710,7 @@ sub show_options { ['2', '-L', '', "LV, Crypto, devices, components: add maj:min; show full device/components report (speed, mapped names)."], ['2', '-n,-N', '', "If available: list of alternate kernel modules/drivers - for device(s)."], + for device(s); PCIe lanes-max: gen, speed, lanes (if relevant)."], ['2', '-o', '', "If available: maj:min of device."], ['2', '-p,-P', '', "If available: raw size of ${partition_string}s, maj:min, percent available for user, block size of file system (root required)."], @@ -5611,9 +5739,9 @@ sub show_options { Example:^<username>^ALL^=^NOPASSWD:^/usr/sbin/hddtemp"], ['2', '-E', '', "PCI/USB Bus ID of device, driver version, LMP version."], - ['2', '-G', '', "Specific vendor/product information (if relevant); - PCI/USB ID of device; Direct rendering status (in X); Screen - number GPU is running on (Nvidia only)."], + ['2', '-G', '', "Specific vendor/product information (if relevant); PCI/USB ID + of device; Direct rendering status (in X); Screen number GPU is running on + (Nvidia only)."], ['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 @@ -5648,16 +5776,20 @@ sub show_options { ['0', '', '', ''], ['1', '-xx', '--extra 2', "Show extra, extra data (only works with verbose or line output, not short form):"], - ['2', '-A', '', "Chip vendor:product ID for each audio device."], + ['2', '-A', '', "Chip vendor:product ID for each audio device; PCIe speed, + lanes (if found)."], ['2', '-B', '', "Serial number."], ['2', '-D', '', "Disk transfer speed; NVMe lanes; Disk serial number; LVM volume group free space (if available); disk duid (some BSDs)."], - ['2', '-E', '', "Chip vendor:product ID, LMP subversion."], - ['2', '-G', '', "Chip vendor:product ID for each video device; OpenGL - compatibility version, if free drivers and available; Xorg compositor; - alternate Xorg drivers (if available). Alternate means driver is on automatic - driver check list of Xorg for the device vendor, but is not installed on - system; Xorg dpi."], + ['2', '-E', '', "Chip vendor:product ID, LMP subversion; PCIe speed, lanes + (if found)."], + ['2', '-G', '', "Chip vendor:product ID for each video device; Output ports, + used and empty; PCIe speed, lanes (if found); Xorg: OpenGL compatibility + version, if free drivers and available; Xorg compositor; alternate Xorg + drivers (if available. Alternate means driver is on automatic driver check + list of Xorg for the device vendor, but is not installed on system); Xorg + Screen data: ID, s-res, dpi; Monitors: ID, position (if > 1), resolution, + dpi, model, diagonal."], ['2', '-I', '', "Other detected installed gcc versions (if present). System default 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 @@ -5670,7 +5802,7 @@ sub show_options { ['2', '-m,--memory-modules', '', "Manufacturer, part number; single/double bank (if found)."], ['2', '-M', '', "Chassis info, BIOS ROM size (dmidecode only), if available."], - ['2', '-N', '', "Chip vendor:product ID."], + ['2', '-N', '', "Chip vendor:product ID; PCIe 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."], @@ -5697,7 +5829,8 @@ sub show_options { ['2', '-D', '', "Firmware rev. if available; partition scheme, in some cases; disk type, rotation rpm (if available)."], ['2', '-E', '', "Serial number, class ID, HCI version and revision."], - ['2', '-G', '', "Serial number, class ID."], + ['2', '-G', '', "Device serial number, class ID; Xorg Screen size, diag; + Monitors: hz, size, modes, serial, scale, modes (max/min)."], ['2', '-I', '', "For 'Shell:' adds ([doas|su|sudo|login]) to shell name if present; adds default shell+version if different; for 'running in:' adds (SSH) if SSH session; adds wakeups: (from suspend) to Uptime."], @@ -6088,10 +6221,10 @@ sub get_client_version { # NOTE: these must be empirically determined, not all events that # show no tty are actually IRC. tmux is not a vt, but runs inside one if (!$client{'name-print'}){ - my $wl_terms = 'alacritty|altyo|black-screen|conhost|doas|evilvte|'; - $wl_terms .= 'germinal|guake|havoc|hyper|kate|kitty|kmscon|konsole|login|'; - $wl_terms .= 'macwise|minicom|putty|rxvt|sakura|securecrt|shellinabox|'; - $wl_terms .= '^st$|sudo|term|tilda|tilix|tmux|tym|wayst|xiki|'; + my $wl_terms = 'alacritty|altyo|\bate\b|black-screen|conhost|doas|evilvte|'; + $wl_terms .= 'foot|germinal|guake|havoc|hyper|kate|kitty|kmscon|konsole|'; + $wl_terms .= 'login|macwise|minicom|putty|rxvt|sakura|securecrt|'; + $wl_terms .= 'shellinabox|^st$|sudo|term|tilda|tilix|tmux|tym|wayst|xiki|'; $wl_terms .= 'yaft|yakuake|\bzoc\b'; my $wl_clients = 'ansible|chef|run-parts|sshd'; my $whitelist = "$wl_terms|$wl_clients"; @@ -6121,7 +6254,7 @@ sub get_cmdline { } local $\ = ''; open(my $fh, '<', "/proc/$ppid/cmdline") or - print_line("Open /proc/$ppid/cmdline failed: $!"); + print_line("Open /proc/$ppid/cmdline failed: $!"); my @rows = <$fh>; close $fh; foreach (@rows){ @@ -6282,7 +6415,7 @@ sub clean { my ($item) = @_; return $item if !$item;# handle cases where it was 0 or '' or undefined # note: |nee trips engineering, but I don't know why nee was filtered - $item =~ s/chipset|company|components|computing|computer|corporation|communications|electronics|electrical|electric|gmbh|group|incorporation|industrial|international|\bnee\b|no\sstring|revision|semiconductor|software|technologies|technology|ltd\.|<ltd>|\bltd\b|inc\.|<inc>|\binc\b|intl\.|co\.|<co>|corp\.|<corp>|\(tm\)|\(r\)|®|\(rev ..\)|\'|\"|\sinc\s*$|\?//gi; + $item =~ s/chipset|company|components|computing|computer|corporation|communications|electronics?|electric(al)?|group|incorporation|industrial|international|limited|\bnee\b|<?no\sstring>?|revision|semiconductor|software|technolog(ies|y)|<?unknown>?|ltd\.|<ltd>|\bltd\b|inc\.|<inc>|\binc\b|intl\.|co\.|<co>|corp\.|<corp>|\(tm\)|\(r\)|®|\(rev ..\)|\'|\"|\?//gi; $item =~ s/,|\*/ /g; $item =~ s/^\s+|\s+$//g; $item =~ s/\s\s+/ /g; @@ -6515,24 +6648,25 @@ sub message { 'cpu-speeds' => 'No per core speed data found.', 'cpu-speeds-bsd' => 'No OS support for core speeds.', 'darwin-feature' => 'Feature not supported iu Darwin/OSX.', + 'dev' => 'Feature under development', 'disk-data' => 'No disk data found.', 'disk-data-bsd' => 'No disk data found.', 'disk-size-0' => 'Total N/A', - 'display-console' => 'No advanced graphics data found on this system in console.', - 'display-driver-na' => 'n/a (using device driver)', - 'display-null' => 'No advanced graphics data found on this system.', - 'display-root' => 'Advanced graphics data unavailable in console for root.', - 'display-root-x' => 'Advanced graphics data unavailable for root.', + 'display-driver-na' => ' X driver n/a', 'display-server' => 'No display server data found. Headless machine?', - 'glxinfo-missing' => 'Unable to show advanced data. Required tool glxinfo missing.', - 'gl-empty' => 'Unset. Missing GL driver?', - 'display-try' => 'Advanced graphics data unavailable in console. Try -G --display', - 'dev' => 'Feature under development', 'dmesg-boot-permissions' => 'dmesg.boot permissions', 'dmesg-boot-missing' => 'dmesg.boot not found', - 'IP' => "No $id found. Connected to web? SSL issues?", 'dmidecode-dev-mem' => 'dmidecode is not allowed to read /dev/mem', 'dmidecode-smbios' => 'No SMBIOS data for dmidecode to process', + 'gl-console' => 'No advanced graphics data found on this system in console.', + 'gl-empty' => 'Unset. Missing GL driver?', + 'gl-null' => 'No GL data found on this system.', + 'gl-root' => 'GL data unavailable in console for root.', + 'gl-root-display' => 'GL data unavailable for root.', + 'gl-try' => 'GL data unavailable in console. Try -G --display', + 'glxinfo-missing' => 'Unable to show GL data. Required tool glxinfo missing.', + 'interface-wayland' => 'Wayland GBM/EGL data currently not available.', + '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", 'logical-data' => 'No logical block device data found.', @@ -6541,6 +6675,11 @@ sub message { 'machine-data-bsd' => 'No machine data: Is dmidecode installed? Try -M --dmidecode.', 'machine-data-dmidecode' => 'No machine data: try newer kernel. Is dmidecode installed? Try -M --dmidecode.', 'machine-data-force-dmidecode' => 'No machine data: try newer kernel. Is dmidecode installed? Try -M --dmidecode.', + 'machine-data-fruid' => 'No machine data: Is fruid_print installed?', + 'monitor-console' => 'N/A in console', + 'monitor-id' => 'not-matched', + 'monitor-na' => 'N/A', + 'monitor-wayland' => 'no compositor data', 'note-check' => 'check', 'note-est' => 'est.', 'optical-data' => 'No optical or floppy data found.', @@ -6569,6 +6708,8 @@ sub message { 'root-item-incomplete' => "Full $id report requires superuser permissions.", 'root-required' => '<superuser required>', 'root-suggested' => 'try sudo/root',# gdm only + 'screen-wayland' => 'no compositor data', + 'screen-xvesa' => 'no Xvesa data', 'sensors-data-bsd' => "$id sensor data found but not usable.", 'sensors-data-bsd-ok' => 'No sensor data found. Are sensors present?', 'sensors-data-ipmi' => 'No ipmi sensor data found.', @@ -6602,6 +6743,7 @@ sub message { 'unknown-shell' => 'ERR-100', 'weather-error' => "Error: $id", 'weather-null' => "No $id found. Internet connection working?", + 'xvesa-interface' => 'No Xvesa VBE/GOP data found.', ); return $unfound{$type}; } @@ -6619,16 +6761,16 @@ sub regex_range { return join('|',@processed); } +# Handles duplicates occuring anywhere in string sub remove_duplicates { my ($string) = @_; return if !$string; - my $holder = ''; - my (@temp); + my (%holder,@temp); foreach (split(/\s+/, $string)){ - if ($holder ne $_){ + if (!$holder{lc($_)}){ push(@temp, $_); + $holder{lc($_)} = 1; } - $holder = $_; } $string = join(' ', @temp); return $string; @@ -6710,16 +6852,12 @@ sub generate_json { my ($b_cpanel,$b_valid); error_handler('not-in-irc', 'help') if $b_irc; print Dumper $data if $b_debug; - if (check_perl_module('Cpanel::JSON::XS')){ - Cpanel::JSON::XS->import; - $json = Cpanel::JSON::XS::encode_json($data); - } - elsif (check_perl_module('JSON::XS')){ - JSON::XS->import; - $json = JSON::XS::encode_json($data); + load_json() if !$loaded{'json'}; + if ($use{'json'}){ + $json = &{$use{'json'}->{'encode'}}($data); } else { - error_handler('required-module', 'json', 'Cpanel::JSON::XS OR JSON::XS'); + error_handler('required-module', 'json', 'JSON::PP, Cpanel::JSON::XS or JSON::XS'); } if ($json){ #$json =~ s/"[0-9]+#/"/g; @@ -7174,7 +7312,7 @@ sub get { push(@rows,device_output()); } if (((%risc && !$use{'soc-audio'} && !$use{'pci-tool'}) || !@rows) && - (my $file = $system_files{'asound-cards'})){ + (my $file = $system_files{'asound-cards'})){ push(@rows,asound_output($file)); } push(@rows,usb_output()); @@ -7228,7 +7366,11 @@ sub device_output { $rows[$j]->{main::key($num++,0,3,'alternate')} = $row->[10] if $row->[10]; } if ($extra > 0){ - $rows[$j]->{main::key($num++,0,2,'bus-ID')} = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; + my $bus_id = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; + if ($extra > 1 && $bus_id ne 'N/A'){ + main::get_pcie_data($bus_id,$j,\@rows,\$num); + } + $rows[$j]->{main::key($num++,0,2,'bus-ID')} = $bus_id; } if ($extra > 1){ my $chip_id = main::get_chip_id($row->[5],$row->[6]); @@ -7466,7 +7608,7 @@ sub get { @rows = ({main::key($num++,0,1,$key1) => $val1,}); } } - (@upower_items,$b_upower,$upower) = undef; + (@upower_items,$b_upower,$upower) = (); eval $end if $b_log; return @rows; } @@ -8013,7 +8155,11 @@ sub device_output { $rows[$j]->{main::key($num++,0,3,'alternate')} = $row->[10] if $row->[10]; } if ($extra > 0){ - $rows[$j]->{main::key($num++,0,2,'bus-ID')} = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; + $bus_id = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; + if ($extra > 1 && $bus_id ne 'N/A'){ + main::get_pcie_data($bus_id,$j,\@rows,\$num); + } + $rows[$j]->{main::key($num++,0,2,'bus-ID')} = $bus_id; } if ($extra > 1){ my $chip_id = main::get_chip_id($row->[5],$row->[6]); @@ -8191,7 +8337,7 @@ sub advanced_output { # } # this data only from hciconfig if ($b_admin && - ($hci{$item}->{'acl-mtu'} || $hci{$item}->{'sco-mtu'} || $hci{$item}->{'link-policy'})){ + ($hci{$item}->{'acl-mtu'} || $hci{$item}->{'sco-mtu'} || $hci{$item}->{'link-policy'})){ $j = scalar @rows; push(@rows,{ main::key($num++,1,$l,'Info') => '', @@ -8217,7 +8363,7 @@ sub advanced_output { } } if (!@rows && !$b_hci_error && ($alerts{'hciconfig'}->{'action'} ne 'use' && - $alerts{'bt-adapter'}->{'action'} ne 'use')){ + $alerts{'bt-adapter'}->{'action'} ne 'use')){ my $key = 'Report'; my $value = ''; if ($alerts{'hciconfig'}->{'action'} eq 'platform' || @@ -8883,7 +9029,7 @@ sub cpuinfo_data { } } cpuinfo_data_grabber($file,\$cpu{'type'}) if !$loaded{'cpuinfo'}; - $cpu{'type'} = cpu_vendor($cpu_arch) if $cpu_arch =~ /e2k/; # already set to lower + $cpu{'type'} = cpu_vendor($cpu_arch) if $cpu_arch eq 'elbrus'; # already set to lower my ($core_count,$proc_count,$speed) = (0,0,0); my ($b_block_1) = (1); # need to prime for arm cpus, which do not have physical/core ids usually @@ -9504,7 +9650,7 @@ sub sysctl_data { # darwin shows machine, like MacBook7,1, not cpu # machdep.cpu.brand_string: Intel(R) Core(TM)2 Duo CPU P8600 @ 2.40GHz if (($bsd_type ne 'darwin' && $line[0] eq 'hw.model') || - $line[0] eq 'machdep.cpu.brand_string'){ + $line[0] eq 'machdep.cpu.brand_string'){ # cut L2 cache/cpu max speed out of model string, if available # openbsd 5.6: AMD Sempron(tm) Processor 3400+ ("AuthenticAMD" 686-class, 256KB L2 cache) # openbsd 6.x has Lx cache data in dmesg.boot @@ -9835,7 +9981,7 @@ sub dmidecode_data { # Older dmidecode appear to have unreliable Upgrade outputs elsif ($item->[0] == 4){ # skip first three row,s we don't need that data - ($socket,$upgrade) = (undef,undef); + ($socket,$upgrade) = (); $dmi_data{'phys-cnt'}++; # try to catch bsds without physical cpu count foreach my $value (@$item[3 .. $#$item]){ next if $value =~ /^~/; @@ -9872,11 +10018,11 @@ sub dmidecode_data { # Seen older cases where Upgrade: Other value exists if ($socket || $upgrade){ if ($socket && $upgrade){ - $upgrade = undef if $socket eq $upgrade; + undef $upgrade if $socket eq $upgrade; } elsif ($upgrade){ $socket = $upgrade; - $upgrade = undef; + undef $upgrade; } $dmi_data{'socket'} = $socket; $dmi_data{'upgrade'} = $upgrade; @@ -10074,7 +10220,7 @@ sub cp_data_dmi { } # We have to undef all the sys stuff to get back to the true dmidecode results # Too many variants to treat one by one, just clear it out if forced. - undef %$caches if $force{'dmidecode'}; + undef $caches if $force{'dmidecode'}; # We don't want to use dmi L1/L2/L3 at all for non BSD systems unless forced # because have seen totally gibberish dmidecode data for caches. /sys cache # data preferred, more granular and basically consistently right. @@ -10409,7 +10555,7 @@ sub cp_cache_desc { $desc .= $sep . $cache_desc->{$_} . 'x' . main::get_size($_,'string'); $sep = ', '; } - undef %{$cache_desc}; + undef $cache_desc; return $desc; } # $caches passed by reference @@ -10758,8 +10904,10 @@ sub cp_cpu_arch { $arch = 'Core Merom'} elsif ($model =~ /^(15)$/){ $arch = 'M Tolapai'} # pentium M system on chip - elsif ($model =~ /^(17|1D)$/){ + elsif ($model =~ /^(1D)$/){ $arch = 'Core Penryn'} + elsif ($model =~ /^(17)$/){ + $arch = 'Core Yorkfield'} # had 25 also, but that's westmere, at least for stepping 2 elsif ($model =~ /^(1A|1E|1F|2C|2E|2F)$/){ $arch = 'Nehalem'} @@ -11243,7 +11391,7 @@ sub cpu_vendor { elsif ($string =~ /centaur/){ $vendor = "centaur" } - elsif ($string =~ /(e2k|elbrus)/){ + elsif ($string eq 'elbrus'){ $vendor = "elbrus" } eval $end if $b_log; @@ -11344,9 +11492,9 @@ sub hex_and_decimal { ## DriveItem { package DriveItem; -my ($b_hddtemp,$b_nvme,$smartctl_missing); +my ($b_hddtemp,$b_nvme,$smartctl_missing,$vendors); my ($hddtemp,$nvme) = ('',''); -my (@by_id,@by_path,@vendors); +my (@by_id,@by_path); my ($debugger_dir); # main::writer("$debugger_dir/system-repo-data-urpmq.txt",\@data2) if $debugger_dir; sub get { @@ -11396,8 +11544,8 @@ sub get { if ($show{'optical'} || $show{'optical-basic'}){ push(@rows,OpticalItem::get()); } - ($b_hddtemp,$b_nvme,$hddtemp,$nvme) = (undef,undef,undef,undef); - (@by_id,@by_path) = (undef,undef); + ($b_hddtemp,$b_nvme,$hddtemp,$nvme,$vendors) = (); + (@by_id,@by_path) = (); eval $end if $b_log; return @rows; } @@ -11860,10 +12008,10 @@ sub proc_data_advanced { $drives->[$i]{'drive-type'} = 'HDD'; } elsif (($block_type && $block_type ne 'sdx') || - # note: this case could conceivabley be wrong for a spun down HDD - (defined $data[2] && $data[2] eq '0') || - ($drives->[$i]{'model'} && - $drives->[$i]{'model'} =~ /(flash|mmc|msata|\bm[\.-]?2\b|nvme|ssd|solid\s?state)/i)){ + # note: this case could conceivabley be wrong for a spun down HDD + (defined $data[2] && $data[2] eq '0') || + ($drives->[$i]{'model'} && + $drives->[$i]{'model'} =~ /(flash|mmc|msata|\bm[\.-]?2\b|nvme|ssd|solid\s?state)/i)){ $drives->[$i]{'drive-type'} = 'SSD'; } } @@ -12223,7 +12371,7 @@ sub smartctl_data { # 'Airflow_Temperature_Cel' like: 29 (Min/Max 14/43) so can't use -1 index # Temperature like 29 Celsisu elsif ($split[$a] eq 'Temperature_Celsius' || $split[$a] eq 'Temperature' || - $split[$a] eq 'Airflow_Temperature_Cel'){ + $split[$a] eq 'Airflow_Temperature_Cel'){ if (!$data->[$i]{'temp'} && $split[$r]){ $data->[$i]{'temp'} = $split[$r]; } @@ -12600,9 +12748,10 @@ sub disk_data_by_id { # 0 - match pattern; 1 - replace pattern; 2 - vendor print; 3 - serial pattern sub set_vendors { eval $start if $b_log; - @vendors = ( + my $vendors = $_[0]; + @$vendors = ( ## MOST LIKELY/COMMON MATCHES ## - ['(Crucial|^(FC)?CT|-CT|^M4\b|Gizmo!|^((C300-)?CTF[\s-]?)?DDAC)','Crucial','Crucial',''], + ['(Crucial|^(FC)?CT|-CT|^M4(\b|SSD)|Gizmo!|^((C300-)?CTF[\s-]?)?DDAC)','Crucial','Crucial',''], # H10 HBRPEKNX0202A NVMe INTEL 512GB ['(\bINTEL\b|^SSD(PAM|SA2))','\bINTEL\b','Intel',''], # note: S[AV][1-9][0-9] can trigger false positives @@ -12677,6 +12826,7 @@ sub set_vendors { # must come before AP|Apacer ['^(APPLE|iPod)','^APPLE','Apple',''], ['^(AP|Apacer)','^Apacer','Apacer',''], + ['^(Apricom|SATAWire)','^Apricom','Apricom',''], ['^(A-?RAM|ARSSD)','^A-?RAM','A-RAM',''], ['^Arch','^Arch(\s*Memory)?','Arch Memory',''], ['^(Asenno|AS[1-9])','^Asenno','Asenno',''], @@ -12686,6 +12836,7 @@ sub set_vendors { ['^Axiom','^Axiom','Axiom',''], ['^(Baititon|BT[0-9])','^Baititon','Baititon',''], ['^Bamba','^Bamba','Bamba',''], + ['^(Beckhoff)','^Beckhoff','Beckhoff',''], ['^Bell\b','^Bell','Packard Bell',''], ['^(BelovedkaiAE|GhostPen)','^BelovedkaiAE','BelovedkaiAE',''], ['^BHT','^BHT','BHT',''], @@ -12693,6 +12844,7 @@ sub set_vendors { ['^BIOSTAR','^BIOSTAR','Biostar',''], ['^BIWIN','^BIWIN','BIWIN',''], ['^Blackpcs','^Blackpcs','Blackpcs',''], + ['^(BlitzWolf|BW-?PSSD)','^BlitzWolf','BlitzWolf',''], ['^(BlueRay|SDM[0-9])','^BlueRay','BlueRay',''], ['^Bory','^Bory','Bory',''], ['^Braveeagle','^Braveeagle','BraveEagle',''], @@ -12725,6 +12877,7 @@ sub set_vendors { ['^Derler','^Derler','Derler',''], ['^detech','^detech','DETech',''], ['^DGM','^DGM\b','DGM',''], + ['^(DICOM|MAESTRO)','^DICOM','DICOM',''], ['^Digifast','^Digifast','Digifast',''], ['^DIGITAL\s?FILM','DIGITAL\s?FILM','Digital Film',''], ['^Dikom','^Dikom','Dikom',''], @@ -12752,6 +12905,7 @@ sub set_vendors { # NOTE: ESA3... may be IBM PCIe SAD card/drives ['^(EXCELSTOR|r technology)','^EXCELSTOR( TECHNO(LOGY)?)?','ExcelStor',''], ['^EYOTA','^EYOTA','EYOTA',''], + ['^EZCOOL','^EZCOOL','EZCOOL',''], ['^EZLINK','^EZLINK','EZLINK',''], ['^Fantom','^Fantom( Drive[s]?)?','Fantom Drives',''], ['^Fanxiang','^Fanxiang','Fanxiang',''], @@ -12766,6 +12920,7 @@ sub set_vendors { ['^(FOXLINE|FLD)','^FOXLINE','Foxline',''], # russian vendor? ['^(GALAX\b|Gamer\s?L)','^GALAX','GALAX',''], ['^Galaxy\b','^Galaxy','Galaxy',''], + ['^Gamer[_\s-]?Black','^Gamer[_\s-]?Black','Gamer Black',''], ['^(Garmin|Fenix|Nuvi|Zumo)','^Garmin','Garmin',''], ['^Geil','^Geil','Geil',''], ['^GelL','^GelL','GelL',''], # typo for Geil? GelL ZENITH R3 120GB @@ -12780,6 +12935,8 @@ sub set_vendors { ['^GLOWY','^GLOWY','Glowy',''], ['^Goldendisk','^Goldendisk','Goldendisk',''], ['^Goldenfir','^Goldenfir','Goldenfir',''], + ['^Golden[\s_-]?Memory','^Golden[\s_-]?Memory','Golden Memory',''], + ['^(Goldkey|GKP)','^Goldkey','GoldKey',''], # Wilk Elektronik SA, poland ['^(Wilk\s*)?(GOODRAM|GOODDRIVE|IR[\s-]?SSD|IRP|SSDPR)','^GOODRAM','GOODRAM',''], # supertalent also has FM: |FM @@ -12791,6 +12948,7 @@ sub set_vendors { ['^HDC','^HDC\b','HDC',''], ['^Hectron','^Hectron','Hectron',''], ['^HEMA','^HEMA','HEMA',''], + ['(HEORIADY|^HX-0)','^HEORIADY','HEORIADY',''], ['^(Hikvision|HKVSN|HS-SSD)','^Hikvision','Hikvision',''], ['^Hoodisk','^Hoodisk','Hoodisk',''], ['^HUAWEI','^HUAWEI','Huawei',''], @@ -12801,6 +12959,7 @@ sub set_vendors { ['^IEI Tech','^IEI Tech(\.|nology)?( Corp(\.|oration)?)?','IEI Technology',''], ['^(IGEL|UD Pocket)','^IGEL','IGEL',''], ['^(Imation|Nano\s?Pro|HQT)','^Imation(\sImation)?','Imation',''], # Imation_ImationFlashDrive; TF20 is imation/tdk + ['^(IMC|Kanguru)','^IMC\b','IMC',''], ['^(Inateck|FE20)','^Inateck','Inateck',''], ['^(Inca\b|Npenterprise)','^Inca','Inca',''], ['^(Indilinx|IND-)','^Indilinx','Indilinx',''], @@ -12812,6 +12971,7 @@ sub set_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',''], ['^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',''], @@ -12819,6 +12979,7 @@ sub set_vendors { ['^(Integrated[\s-]?Technology|IT[0-9]+)','^Integrated[\s-]?Technology','Integrated Technology',''], ['^(Iomega|ZIP\b|Clik!)','^Iomega','Iomega',''], ['^ISOCOM','^ISOCOM','ISOCOM (Shenzhen Longsys Electronics)',''], + ['^(Jaster|JS\d)','^Jaster','Jaster',''], ['^JingX','^JingX','JingX',''], #JingX 120G SSD - not confirmed, but guessing ['^Jingyi','^Jingyi','Jingyi',''], # NOTE: ITY2 120GB hard to find @@ -12828,11 +12989,11 @@ sub set_vendors { ['^Kingbank','^Kingbank','Kingbank',''], ['^Kingchux[\s-]?ing','^Kingchux[\s-]?ing','Kingchuxing',''], ['(KingDian|^NGF)','KingDian','KingDian',''], - ['^Kingfast','^Kingfast','Kingfast',''], + ['^(Kingfast|TYFS)','^Kingfast','Kingfast',''], ['^KingMAX','^KingMAX','KingMAX',''], ['^Kingrich','^Kingrich','KingrSU04Gich',''], ['KING\s?SHA\s?RE','KING\s?SHA\s?RE','KingShare',''], - ['^(KingSpec|ACSC|KS[DQ]|N[ET]-[0-9]|P4\b|PA18|T-(3260|64|128))','^KingSpec','KingSpec',''], + ['^(KingSpec|ACSC|KS[DQ]|N[ET]-[0-9]|P4\b|PA[_-]?(18|25)|T-(3260|64|128))','^KingSpec','KingSpec',''], ['^KingSSD','^KingSSD','KingSSD',''], # kingwin docking, not actual drive ['^(EZD|EZ-Dock)','','Kingwin Docking Station',''], @@ -12858,9 +13019,11 @@ sub set_vendors { ['(LITE[-\s]?ON|^PH[1-9])','LITE[-]?ON','LITE-ON',''], # PH6-CE240-L; CL1-3D256-Q11 NVMe LITEON 256GB ['^LONDISK','^LONDISK','LONDISK',''], ['^Longline','^Longline','Longline',''], + ['^LuminouTek','^LuminouTek','LuminouTek',''], ['^(LSI|MegaRAID)','^LSI\b','LSI',''], ['^(M-Systems|DiskOnKey)','^M-Systems','M-Systems',''], ['^(Mach\s*Xtreme|MXSSD|MXU|MX[\s-])','^Mach\s*Xtreme','Mach Xtreme',''], + ['^Mainic','^Mainic','Mainic',''], ['^Maximus','^Maximus','Maximus',''], ['^Maxone','^Maxone','Maxone',''], ['^(MAXTOR|Atlas|L(250|500)|TM[0-9]{4}|[KL]0[1-9]|Y[0-9]{3}[A-Z]|STM[0-9]|F[0-9]{3}L)','^MAXTOR','Maxtor',''], # note M2 M3 is usually maxtor, but can be samsung @@ -12921,6 +13084,7 @@ sub set_vendors { ['^(PQI|Intelligent\s?Stick|Cool\s?Drive)','^PQI','PQI',''], ['^(Premiertek|QSSD|Quaroni)','^Premiertek','Premiertek',''], ['^(Pretec|UltimateGuard)','Pretec','Pretec',''], + ['^(Prolific)','^Prolific( Technolgy Inc\.)?','Prolific',''], # PS3109S9 is the result of an error condition with ssd drive ['QEMU','^[0-9]*QEMU( QEMU)?','QEMU',''], # 0QUEMU QEMU HARDDISK ['(^Quantum|Fireball)','^Quantum','Quantum',''], @@ -12957,13 +13121,15 @@ sub set_vendors { ['^Skill','^Skill','Skill',''], ['^(SMART( Storage Systems)?|TX)','^(SMART( Storage Systems)?)','Smart Storage Systems',''], ['^Sobetter','^Sobetter','Sobetter',''], - ['^(S[FR]-|Sony)','^Sony','Sony',''], + ['^(S[FR]-|Sony|IM9)','^Sony','Sony',''], ['^(SSSTC|CL1-)','^SSSTC','SSSTC',''], ['^STE[CK]','^STE[CK]','sTec',''], # wd bought this one ['^STmagic','^STmagic','STmagic',''], ['^STORFLY','^STORFLY','StorFly',''], ['\dSUN\d','^SUN(\sMicrosystems)?','Sun Microsystems',''], + ['^Sundisk','^Sundisk','Sundisk',''], ['^SUNEAST','^SUNEAST','SunEast',''], + ['^Supersonic','^Supersonic','Supersonic',''], ['^SuperSSpeed','^SuperSSpeed','SuperSSpeed',''], # NOTE: F[MNETU] not reliable, g.skill starts with FM too: # Seagate ST skips STT. @@ -12985,12 +13151,12 @@ sub set_vendors { ['^TEUTONS','^TEUTONS','TEUTONS',''], ['^THU','^THU','THU',''], ['^Tigo','^Tigo','Tigo',''], - ['^Timetec','^Timetec','Timetec',''], + ['^(Timetec|35TT)','^Timetec','Timetec',''], ['^TKD','^TKD','TKD',''], ['^TopSunligt','^TopSunligt','TopSunligt',''], # is this a typo? hard to know ['^TopSunlight','^TopSunlight','TopSunlight',''], ['^TOROSUS','^TOROSUS','Torosus',''], - ['^([F]?TS|Transcend|JetDrive|JetFlash|USDU|EZEX|1307)','^(Transcend|1307)','Transcend',''], + ['(^[F]?TS|Transcend|JetDrive|JetFlash|^USDU|^EZEX|^1307)','^(Transcend|1307)','Transcend',''], ['^(TrekStor|DS (maxi|pocket)|DataStation)','^TrekStor','TrekStor',''], ['^Turbox','^Turbox','Turbox',''], ['^(TwinMOS|TW[0-9])','^TwinMOS','TwinMOS',''], @@ -13012,6 +13178,7 @@ sub set_vendors { ['^VMware','^VMware','VMware',''], ['^(Vseky|Vaseky)','^Vaseky','Vaseky',''], # ata-Vseky_V880_350G_ ['^(Walgreen|Infinitive)','^Walgreen','Walgreen',''], + ['^Walram','^Walram','WALRAM',''], ['^Walton','^Walton','Walton',''], ['^(Wearable|Air-?Stash)','^Wearable','Wearable',''], ['^Wellcomm','^Wellcomm','Wellcomm',''], @@ -13030,6 +13197,7 @@ sub set_vendors { ['^(YingChu|YGC)','^YingChu','YingChu',''], ['^(YUCUN|R880)','^YUCUN','YUCUN',''], ['^(ZALMAN|ZM\b)','^ZALMAN','Zalman',''], + ['^ZXIC','^ZXIC','ZXIC',''], ['^ZEUSLAP','^ZEUSLAP','ZEUSLAP',''], ['^(Zheino|CHN[0-9]|CNM)','^Zheino','Zheino',''], ['^(Zotac|ZTSSD)','^Zotac','Zotac',''], @@ -13048,12 +13216,15 @@ sub device_vendor { my ($vendor) = (''); my (@data); return if !$model; - set_vendors() if !@vendors; # 0 - match pattern; 1 - replace pattern; 2 - vendor print; 3 - serial pattern # Data URLs: inxi-resources.txt Section: DriveItem device_vendor() # $model = 'H10 HBRPEKNX0202A NVMe INTEL 512GB'; # $model = 'Patriot Memory'; - foreach my $row (@vendors){ + if (!$vendors){ + $vendors = []; + set_vendors($vendors); + } + foreach my $row (@$vendors){ if ($model =~ /$row->[0]/i || ($row->[3] && $serial && $serial =~ /$row->[3]/)){ $vendor = $row->[2]; # Usually we want to assign N/A at output phase, maybe do this logic there? @@ -13284,8 +13455,7 @@ sub device_speed { ## GraphicItem { package GraphicItem; -my $driver = ''; # we need this as a fallback in case no xorg log found -my %graphics; +my ($b_wayland_data,%graphics,$monitor_ids,$monitor_map); sub get { eval $start if $b_log; my (@rows); @@ -13312,16 +13482,19 @@ sub get { # note: not perfect, but we need usb gfx to show for all types, soc, pci, etc push(@rows,usb_output()); push(@rows,display_output()); - push(@rows,gl_output()); + push(@rows,interface_output()); + (%graphics,$monitor_ids,$monitor_map) = (); eval $end if $b_log; return @rows; } +## DEVICE OUTPUT ## sub device_output { eval $start if $b_log; return if !$devices{'graphics'}; my (@rows); my ($j,$num) = (0,1); + set_monitors_sys() if !$monitor_ids && -e '/sys/class/drm'; foreach my $row (@{$devices{'graphics'}}){ $num = 1; # print "$row->[0] $row->[3]\n"; @@ -13333,8 +13506,7 @@ sub device_output { next if $row->[3] != 0; # print "$row->[0] $row->[3]\n"; $j = scalar @rows; - $driver = $row->[9]; - $driver ||= 'N/A'; + push(@{$graphics{'gpu-drivers'}},$row->[9]) if $row->[9]; my $device = main::trimmer($row->[4]); $device = ($device) ? main::clean_pci($device,'output') : 'N/A'; # have seen absurdly verbose card descriptions, with non related data etc @@ -13348,6 +13520,7 @@ sub device_output { my $item = main::get_pci_vendor($row->[4],$row->[12]); $rows[$j]->{main::key($num++,0,2,'vendor')} = $item if $item; } + my $driver = ($row->[9]) ? $row->[9]:'N/A'; $rows[$j]->{main::key($num++,1,2,'driver')} = $driver; if ($row->[9] && !$bsd_type){ my $version = main::get_module_version($row->[9]); @@ -13359,7 +13532,14 @@ sub device_output { $rows[$j]->{main::key($num++,0,3,'alternate')} = $row->[10] if $row->[10]; } if ($extra > 0){ - $rows[$j]->{main::key($num++,0,2,'bus-ID')} = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; + my $bus_id = (!$row->[2] && !$row->[3]) ? 'N/A' : "$row->[2].$row->[3]"; + if ($extra > 1 && $bus_id ne 'N/A'){ + main::get_pcie_data($bus_id,$j,\@rows,\$num,'gpu'); + } + if ($extra > 1 && $monitor_ids){ + port_output($bus_id,$j,\@rows,\$num); + } + $rows[$j]->{main::key($num++,0,2,'bus-ID')} = $bus_id; } if ($extra > 1){ my $chip_id = main::get_chip_id($row->[5],$row->[6]); @@ -13403,7 +13583,11 @@ sub usb_output { main::key($num++,0,2,'driver') => $driver, },); if ($extra > 0){ - $rows[$j]->{main::key($num++,0,2,'bus-ID')} = "$path_id:$row->[1]"; + my $bus_id = "$path_id:$row->[1]"; + if ($extra > 1 && $monitor_ids){ + port_output($bus_id,$j,\@rows,\$num); + } + $rows[$j]->{main::key($num++,0,2,'bus-ID')} = $bus_id; } if ($extra > 1){ $row->[7] ||= 'N/A'; @@ -13419,53 +13603,94 @@ sub usb_output { eval $end if $b_log; return @rows; } +# $rows, $num by ref +sub port_output { + my ($bus_id,$j,$rows,$num) = @_; + my (@connected,@disabled,@empty); + foreach my $id (keys %$monitor_ids){ + next if !$monitor_ids->{$id}{'status'}; + if ($monitor_ids->{$id}{'path'} =~ m|\Q$bus_id/drm/\E|){ + # status can be: connected|disconnected|unknown + if ($monitor_ids->{$id}{'status'} eq 'connected'){ + if ($monitor_ids->{$id}{'enabled'} eq 'enabled'){ + push(@connected,$id); + } + else { + push(@disabled,$id); + } + } + else { + push(@empty,$id); + } + } + } + if (@connected || @empty || @disabled){ + my ($off,$active,$unused); + my $split = ','; # add space if many to allow for wrapping + $$rows[$j]->{main::key($$num++,1,2,'ports')} = ''; + $split = ', ' if scalar @connected > 3; + $active = (@connected) ? join($split,sort @connected) : 'none'; + $$rows[$j]->{main::key($$num++,0,3,'active')} = $active; + if (@disabled){ + $split = (scalar @disabled > 3) ? ', ' : ','; + $off = join($split,sort @disabled); + $$rows[$j]->{main::key($$num++,0,3,'off')} = $off; + } + $split = (scalar @empty > 3) ? ', ' : ','; + $unused = (@empty) ? join($split,sort @empty) : 'none'; + $$rows[$j]->{main::key($$num++,0,3,'empty')} = $unused; + } +} + +## DISPLAY OUTPUT ## sub display_output(){ eval $start if $b_log; my (@row); - my ($num,$protocol) = (0,''); + my ($num,$j) = (0,0); # note: these may not always be set, they won't be out of X, for example - $protocol = get_protocol(); + display_protocol(); + $graphics{'protocol'} = 'wayland' if $force{'wayland'}; + # get rid of all inactive or disabled monitor port ids + set_active_monitors() if $monitor_ids; # note, since the compositor is the server with wayland, always show it - if ($extra > 1 || $protocol eq 'wayland'){ - set_compositor($protocol); + if ($extra > 1 || $graphics{'protocol'} eq 'wayland'){ + set_compositor_data(); } if ($b_display){ - display_data_x(); - # currently barebones, wayland needs a lot more work - if ($protocol && $protocol eq 'wayland' && !$graphics{'screens'}){ + # Add compositors as data sources found + if ($graphics{'protocol'} eq 'wayland'){ display_data_wayland(); - # it worked! we got screen data - $graphics{'no-xdpyinfo'} = undef if $graphics{'screens'}; + } + if (!$b_wayland_data){ + display_data_x() if !$force{'wayland'}; } } else { $graphics{'tty'} = tty_data(); } - # this gives better output than the failure last case, which would only show: - # for example: X.org: 1.9 instead of: X.org: 1.9.0 - $graphics{'x-version'} = $graphics{'xorg-version'} if $graphics{'xorg-version'};; - $graphics{'x-version'} = x_version() if !$graphics{'x-version'}; - $graphics{'x-version'} = $graphics{'x-version-id'} if !$graphics{'x-version'}; + # no xdpyinfo installed + # undef $graphics{'x-server'}; + if (!$graphics{'x-server'} || !$graphics{'x-server'}->[0][1] || + !$b_display || $graphics{'protocol'} eq 'wayland'){ + # fallback, will complete x-server/x-version, set flags, if found + display_server_data(); + } + if (!defined $graphics{'display-id'} && defined $ENV{'DISPLAY'}){ + $graphics{'display-id'} = $ENV{'DISPLAY'}; + } + # print Data::Dumper::Dumper $graphics{'x-server'}; # print Data::Dumper::Dumper \%graphics; if (%graphics){ - my ($driver_missing,$resolution,$server_string) = ('','',''); - # print "$graphics{'x-vendor'} $graphics{'x-version'} $graphics{'x-vendor-release'}","\n"; - if ($graphics{'x-vendor'}){ - my $version = ($graphics{'x-version'}) ? " $graphics{'x-version'}" : ''; - # $version = (!$version && $graphics{'x-vendor-release'}) ? " $graphics{'x-vendor-release'}" : ''; - $server_string = "$graphics{'x-vendor'}$version"; + my ($driver_note,$resolution,$server_string) = ('','',''); + my ($b_screen_monitors,$x_drivers); + $x_drivers = display_drivers_x() if !$force{'wayland'}; + # print "$graphics{'x-server'} $graphics{'x-version'} $graphics{'x-vendor-release'}","\n"; + if ($graphics{'x-server'}){ + $server_string = $graphics{'x-server'}->[0][0]; # print "$server_string\n"; } - elsif ($graphics{'x-version'}){ - if ($graphics{'x-version'} =~ /^Xvesa/){ - $server_string = $graphics{'x-version'}; - } - else { - $server_string = "X.org $graphics{'x-version'}"; - } - } - my @drivers = x_drivers(); - if (!$protocol && !$server_string && !$graphics{'x-vendor'} && !@drivers){ + if (!$graphics{'protocol'} && !$server_string && !$graphics{'x-server'} && + !$x_drivers){ $server_string = main::message('display-server'); @row = ({ main::key($num++,1,1,'Display') => '', @@ -13475,55 +13700,99 @@ sub display_output(){ else { $server_string ||= 'N/A'; @row = ({ - main::key($num++,1,1,'Display') => $protocol, - main::key($num++,0,2,'server') => $server_string, + main::key($num++,1,1,'Display') => $graphics{'protocol'}, + main::key($num++,1,2,'server') => $server_string, }); - if ($graphics{'compositor'}){ - $row[0]->{main::key($num++,0,2,'compositor')} = $graphics{'compositor'}; - if ($graphics{'compositor-version'}){ - $row[0]->{main::key($num++,0,3,'v')} = $graphics{'compositor-version'}; + if ($graphics{'x-server'} && $graphics{'x-server'}->[0][1]){ + $row[0]->{main::key($num++,0,3,'v')} = $graphics{'x-server'}->[0][1]; + } + if ($graphics{'x-server'} && $graphics{'x-server'}->[1][0]){ + $row[0]->{main::key($num++,1,3,'with')} = $graphics{'x-server'}->[1][0]; + if ($graphics{'x-server'}->[1][1]){ + $row[0]->{main::key($num++,0,4,'v')} = $graphics{'x-server'}->[1][1]; + } + } + if ($graphics{'compositors'}){ + if (scalar @{$graphics{'compositors'}} == 1){ + $row[0]->{main::key($num++,1,2,'compositor')} = $graphics{'compositors'}->[0][0]; + if ($graphics{'compositors'}->[0][1]){ + $row[0]->{main::key($num++,0,3,'v')} = $graphics{'compositors'}->[0][1]; + } + } + else { + my $i =1; + $row[0]->{main::key($num++,1,2,'compositors')} = ''; + foreach (@{$graphics{'compositors'}}){ + $row[0]->{main::key($num++,1,3,$i)} = $_->[0]; + if ($_->[1]){ + $row[0]->{main::key($num++,0,4,'v')} = $_->[1]; + } + $i++; + } } } # note: if no xorg log, and if wayland, there will be no xorg drivers, # obviously, so we use the last driver found on the card section in that case. # those come from lscpi kernel drivers so there should be no xorg/wayland issues. - if (!$drivers[0]){ + if (!$x_drivers || !$x_drivers->[0]){ # Fallback: specific case: in Arch/Manjaro gdm run systems, their Xorg.0.log is # located inside this directory, which is not readable unless you are root # Normally Arch gdm log is here: ~/.local/share/xorg/Xorg.1.log # $driver comes from the Device lines, and is just last fallback. - if ($driver && $driver ne 'N/A'){ - if (-e '/var/lib/gdm' && !$b_root){ - $driver_missing = main::message('display-driver-na') . ' - ' . main::message('root-suggested'); + if (!$graphics{'protocol'} || $graphics{'protocol'} ne 'wayland'){ + if ($graphics{'gpu-drivers'}){ + if (-e '/var/lib/gdm' && !$b_root){ + $driver_note = main::message('display-driver-na'); + $driver_note .= ' - ' . main::message('root-suggested'); + } + else { + $driver_note = main::message('display-driver-na'); + } } - else { - $driver_missing = main::message('display-driver-na'); + elsif (-e '/var/lib/gdm' && !$b_root) { + $driver_note = main::message('root-suggested'); } } - else { - $driver_missing = main::message('root-suggested') if -e '/var/lib/gdm' && !$b_root; - } - } - else { - $driver = $drivers[0]; } - $row[0]->{main::key($num++,1,2,'driver')} = ''; - $driver ||= 'N/A'; - $row[0]->{main::key($num++,1,3,'loaded')} = $driver; - if ($driver_missing){ - $row[0]->{main::key($num++,0,4,'note')} = $driver_missing; - } - if ($drivers[1]){ - $row[0]->{main::key($num++,0,3,'unloaded')} = $drivers[1]; - } - if ($drivers[2]){ - $row[0]->{main::key($num++,0,3,'failed')} = $drivers[2]; + # if xvesa, will always have display-driver set + if ($graphics{'xvesa'} && $graphics{'display-driver'}){ + $row[0]->{main::key($num++,1,2,'driver')} = join(',',@{$graphics{'display-driver'}});; } - if ($extra > 1 && $drivers[3]){ - $row[0]->{main::key($num++,0,3,'alternate')} = $drivers[3]; + else { + $row[0]->{main::key($num++,1,2,'driver')} = ''; + # The only wayland setups with x drivers have xorg, transitional that is. + if ($x_drivers){ + $row[0]->{main::key($num++,1,3,'X')} = ''; + my $driver = ($x_drivers->[0]) ? $x_drivers->[0] : 'N/A'; + $row[0]->{main::key($num++,1,4,'loaded')} = $driver; + if ($x_drivers->[1]){ + $row[0]->{main::key($num++,0,4,'unloaded')} = $x_drivers->[1]; + } + if ($x_drivers->[2]){ + $row[0]->{main::key($num++,0,4,'failed')} = $x_drivers->[2]; + } + if ($extra > 1 && $x_drivers->[3]){ + $row[0]->{main::key($num++,0,4,'alternate')} = $x_drivers->[3]; + } + } + my $gpu_drivers = gpu_drivers_sys('all'); + my $drivers; + if ($gpu_drivers ){ + $drivers = join(',',@{$gpu_drivers}); + } + else { + $drivers = ($graphics{'gpu-drivers'}) ? join(',',@{$graphics{'gpu-drivers'}}): 'N/A'; + } + $row[0]->{main::key($num++,1,3,'gpu')} = $drivers; + if ($driver_note){ + $row[0]->{main::key($num++,0,4,'note')} = $driver_note; + } } } - if ($b_admin){ + if (!$show{'graphic-basic'} && $extra > 1 && $graphics{'display-rect'}){ + $row[0]->{main::key($num++,0,2,'d-rect')} = $graphics{'display-rect'}; + } + if (!$show{'graphic-basic'} && $extra > 1){ if (defined $graphics{'display-id'}){ $row[0]->{main::key($num++,0,2,'display-ID')} = $graphics{'display-id'}; } @@ -13535,504 +13804,1234 @@ sub display_output(){ $row[0]->{main::key($num++,0,2,'default screen')} = $graphics{'display-default-screen'}; } } - if ($graphics{'no-xdpyinfo'}){ - $row[0]->{main::key($num++,0,2,'resolution')} = $graphics{'no-xdpyinfo'}; + if ($graphics{'no-screens'}){ + my $res = (!$show{'graphic-basic'} && $extra > 1 && !$graphics{'xvesa'}) ? 'note' : 'resolution'; + $row[0]->{main::key($num++,0,2,$res)} = $graphics{'no-screens'}; } elsif ($graphics{'screens'}){ my ($diag,$dpi,$hz,$size); - my ($m_count,$basic_count,$row_key,$screen_count) = (0,0,0,0); + my ($m_count,$basic_count,$screen_count) = (0,0,0); my $s_count = ($graphics{'screens'}) ? scalar @{$graphics{'screens'}}: 0; foreach my $main (@{$graphics{'screens'}}){ - $m_count = scalar @{$main->{'monitors'}} if $main->{'monitors'}; + $m_count = scalar keys %{$main->{'monitors'}} if $main->{'monitors'}; $screen_count++; - ($diag,$dpi,$hz,$resolution,$size) = (undef); - $row_key++ if !$show{'graphic-basic'}; + ($diag,$dpi,$hz,$resolution,$size) = (); + $j++ if !$show{'graphic-basic'}; if (!$show{'graphic-basic'} || $m_count == 0){ if (!$show{'graphic-basic'} && defined $main->{'screen'}){ - $row[$row_key]->{main::key($num++,1,2,'Screen')} = $main->{'screen'}; + $row[$j]->{main::key($num++,1,2,'Screen')} = $main->{'screen'}; + } + if ($main->{'res-x'} && $main->{'res-y'}){ + $resolution = $main->{'res-x'} . 'x' . $main->{'res-y'}; + $resolution .= '~' . $main->{'hz'} . 'Hz' if $show{'graphic-basic'}; } - $resolution = $main->{'res-x'} . 'x' . $main->{'res-y'} if $main->{'res-x'} && $main->{'res-y'}; - $resolution .= '~' . $main->{'hz'} . 'Hz' if $show{'graphic-basic'} && $main->{'hz'} && $resolution; $resolution ||= 'N/A'; if ($s_count == 1 || !$show{'graphic-basic'}){ - $row[$row_key]->{main::key($num++,0,3,'s-res')} = $resolution; + $row[$j]->{main::key($num++,0,3,'s-res')} = $resolution; } elsif ($show{'graphic-basic'}){ - $row[$row_key]->{main::key($num++,0,3,'s-res')} = '' if $screen_count == 1; - $row[$row_key]->{main::key($num++,0,3,$screen_count)} = $resolution; + $row[$j]->{main::key($num++,0,3,'s-res')} = '' if $screen_count == 1; + $row[$j]->{main::key($num++,0,3,$screen_count)} = $resolution; } - $resolution = ''; - if ($main->{'s-dpi'} && (!$show{'graphic-basic'} || $extra > 1)){ - $row[$row_key]->{main::key($num++,0,3,'s-dpi')} = $main->{'s-dpi'}; + if ($main->{'s-dpi'} && (!$show{'graphic-basic'} && $extra > 1)){ + $row[$j]->{main::key($num++,0,3,'s-dpi')} = $main->{'s-dpi'}; } - if (!$show{'graphic-basic'}){ - if ($main->{'size-x'} && $main->{'size-y'}){ - $size = $main->{'size-x'} . 'x' . $main->{'size-y'} . - 'mm ('. $main->{'size-x-i'} . 'x' . $main->{'size-y-i'} . '")'; + if (!$show{'graphic-basic'} && $extra > 2){ + if ($main->{'size-missing'}){ + $row[$j]->{main::key($num++,0,3,'s-size')} = $main->{'size-missing'}; } - $size ||= ''; - $row[$row_key]->{main::key($num++,0,3,'s-size')} = $size if $size; - if ($main->{'diagonal'}){ - $diag = $main->{'diagonal-m'} . 'mm ('. $main->{'diagonal'} . '")'; + else { + if ($main->{'size-x'} && $main->{'size-y'}){ + $size = $main->{'size-x'} . 'x' . $main->{'size-y'} . + 'mm ('. $main->{'size-x-i'} . 'x' . $main->{'size-y-i'} . '")'; + $row[$j]->{main::key($num++,0,3,'s-size')} = $size; + } + if ($main->{'diagonal'}){ + $diag = $main->{'diagonal-m'} . 'mm ('. $main->{'diagonal'} . '")'; + $row[$j]->{main::key($num++,0,3,'s-diag')} = $diag; + } } - $diag ||= ''; - $row[$row_key]->{main::key($num++,0,3,'s-diag')} = $diag if $diag; } } if ($main->{'monitors'}){ # print $basic_count . '::' . $m_count, "\n"; - foreach my $monitor (@{$main->{'monitors'}}){ - ($diag,$dpi,$hz,$resolution,$size) = (undef); - if ($show{'graphic-basic'}){ - $basic_count++; - if ($monitor->{'res-x'} && $monitor->{'res-y'}){ - $resolution = $monitor->{'res-x'} . 'x' . $monitor->{'res-y'}; - } - # using main, noit monitor, dpi because we want xorg dpi, not physical screen dpi - $dpi = $main->{'s-dpi'} if $resolution && $extra > 1 && $main->{'s-dpi'}; - $resolution .= '~' . $monitor->{'hz'} . 'Hz' if $monitor->{'hz'} && $resolution; - $resolution ||= 'N/A'; - if ($basic_count == 1 && $m_count == 1){ - $row[$row_key]->{main::key($num++,0,2,'resolution')} = $resolution; - } - else { - $row[$row_key]->{main::key($num++,1,2,'resolution')} = '' if $basic_count == 1; - $row[$row_key]->{main::key($num++,0,3,$basic_count)} = $resolution; - } - if ($m_count == $basic_count){ - $row[$row_key]->{main::key($num++,0,2,'s-dpi')} = $dpi if $dpi; - } - next; - } - $row_key++; - $row[$row_key]->{main::key($num++,0,3,'Monitor')} = $monitor->{'monitor'}; - if ($monitor->{'res-x'} && $monitor->{'res-y'}){ - $resolution = $monitor->{'res-x'} . 'x' . $monitor->{'res-y'}; - } - $resolution ||= 'N/A'; - $row[$row_key]->{main::key($num++,0,4,'res')} = $resolution; - $hz = ($monitor->{'hz'}) ? $monitor->{'hz'} : ''; - $row[$row_key]->{main::key($num++,0,4,'hz')} = $hz if $hz; - $dpi = ($monitor->{'dpi'}) ? $monitor->{'dpi'} : ''; - $row[$row_key]->{main::key($num++,0,4,'dpi')} = $dpi if $dpi; - # print "$dpi :: $main->{'s-dpi'}\n"; - if ($monitor->{'size-x'} && $monitor->{'size-y'}){ - $size = $monitor->{'size-x'} . 'x' . $monitor->{'size-y'} . - 'mm ('. $monitor->{'size-x-i'} . 'x' . $monitor->{'size-y-i'} . '")'; - } - $size ||= ''; - $row[$row_key]->{main::key($num++,0,4,'size')} = $size if $size; - if ($monitor->{'diagonal'}){ - $diag = $monitor->{'diagonal-m'} . 'mm ('. $monitor->{'diagonal'} . '")'; - } - $diag ||= ''; - $row[$row_key]->{main::key($num++,0,4,'diag')} = $diag if $diag; + $b_screen_monitors = 1; + if ($show{'graphic-basic'}){ + monitors_output_basic('screen',$main->{'monitors'}, + $main->{'s-dpi'},$j,\@row,\$num); } + else { + monitors_output_full('screen',$main->{'monitors'}, + $j,\@row,\$num); + } + } + elsif (!$show{'graphic-basic'} && $graphics{'no-monitors'}){ + $row[$j]->{main::key($num++,0,4,'monitors')} = $graphics{'no-monitors'}; } } } - else { + elsif (!$b_display){ $graphics{'tty'} ||= 'N/A'; $row[0]->{main::key($num++,0,2,'tty')} = $graphics{'tty'}; } + # fallback, if no xrandr/xdpyinfo, if wayland, if console. Note we've + # deleted each key used in advanced_monitor_data() so those won't show again + if (!$b_screen_monitors && $monitor_ids && %$monitor_ids){ + if ($show{'graphic-basic'}){ + monitors_output_basic('monitor',$monitor_ids,'',$j,\@row,\$num); + } + else { + monitors_output_full('monitor',$monitor_ids,$j,\@row,\$num); + } + } } eval $end if $b_log; return @row; } +sub monitors_output_basic { + eval $start if $b_log; + my ($type,$monitors,$s_dpi,$j,$row,$num) = @_; + my ($dpi,$resolution); + my ($basic_count,$m_count) = (0,scalar keys %{$monitors}); + foreach my $key (sort keys %{$monitors}){ + if ($type eq 'monitor' && (!$monitors->{$key}{'res-x'} || + !$monitors->{$key}{'res-y'})){ + next; + } + ($dpi,$resolution) = (); + $basic_count++; + if ($monitors->{$key}{'res-x'} && $monitors->{$key}{'res-y'}){ + $resolution = $monitors->{$key}{'res-x'} . 'x' . $monitors->{$key}{'res-y'}; + } + # using main, not monitor, dpi because we want xorg dpi, not physical screen dpi + $dpi = $s_dpi if $resolution && $extra > 1 && $s_dpi; + if ($monitors->{$key}{'hz'} && $resolution){ + $resolution .= '~' . $monitors->{$key}{'hz'} . 'Hz'; + } + $resolution ||= 'N/A'; + if ($basic_count == 1 && $m_count == 1){ + $row->[$j]{main::key($$num++,0,2,'resolution')} = $resolution; + } + else { + if ($basic_count == 1){ + $row->[$j]{main::key($$num++,1,2,'resolution')} = ''; + } + $row->[$j]{main::key($$num++,0,3,$basic_count)} = $resolution; + } + if (!$show{'graphic-basic'} && $m_count == $basic_count && $dpi){ + $row->[$j]{main::key($$num++,0,2,'s-dpi')} = $dpi; + } + } + eval $end if $b_log; +} +# row, num passed by ref +sub monitors_output_full { + eval $start if $b_log; + my ($type,$monitors,$j,$row,$num) = @_; + my ($b_no_size,$resolution); + my ($m1,$m2,$m3) = ($type eq 'screen') ? (3,4,5) : (2,3,4); + foreach my $key (sort keys %{$monitors}){ + $j++; + $$row[$j]->{main::key($$num++,1,$m1,'Monitor')} = $monitors->{$key}{'monitor'}; + if ($monitors->{$key}{'monitor-mapped'}){ + $$row[$j]->{main::key($$num++,0,$m2,'mapped')} = $monitors->{$key}{'monitor-mapped'}; + } + if ($monitors->{$key}{'position'}){ + $$row[$j]->{main::key($$num++,0,$m2,'pos')} = $monitors->{$key}{'position'}; + } + if ($monitors->{$key}{'model'}){ + $$row[$j]->{main::key($$num++,0,$m2,'model')} = $monitors->{$key}{'model'}; + } + if ($extra > 2 && $monitors->{$key}{'serial'}){ + $$row[$j]->{main::key($$num++,0,$m2,'serial')} = main::filter($monitors->{$key}{'serial'}); + } + if ($b_admin && $monitors->{$key}{'build-date'}){ + $$row[$j]->{main::key($$num++,0,$m2,'built')} = $monitors->{$key}{'build-date'}; + } + if ($monitors->{$key}{'res-x'} || $monitors->{$key}{'res-y'} || + $monitors->{$key}{'hz'} || $monitors->{$key}{'size-x'} || + $monitors->{$key}{'size-y'}){ + if ($monitors->{$key}{'res-x'} && $monitors->{$key}{'res-y'}){ + $resolution = $monitors->{$key}{'res-x'} . 'x' . $monitors->{$key}{'res-y'}; + } + $resolution ||= 'N/A'; + $$row[$j]->{main::key($$num++,0,$m2,'res')} = $resolution; + } + else { + if ($b_display){ + $resolution = main::message('monitor-na'); + } + else { + $resolution = main::message('monitor-console'); + } + $b_no_size = 1; + $$row[$j]->{main::key($$num++,0,$m2,'size-res')} = $resolution; + } + if ($extra > 2 && $monitors->{$key}{'hz'}){ + $$row[$j]->{main::key($$num++,0,$m2,'hz')} = $monitors->{$key}{'hz'}; + } + if ($monitors->{$key}{'dpi'}){ + $$row[$j]->{main::key($$num++,0,$m2,'dpi')} = $monitors->{$key}{'dpi'}; + } + if ($b_admin && $monitors->{$key}{'gamma'}){ + $$row[$j]->{main::key($$num++,0,$m2,'gamma')} = $monitors->{$key}{'gamma'}; + } + if ($extra > 2 && $monitors->{$key}{'scale'}){ + $$row[$j]->{main::key($$num++,0,$m2,'scale')} = $monitors->{$key}{'scale'}; + } + if ($extra > 2 && $monitors->{$key}{'size-x'} && $monitors->{$key}{'size-y'}){ + my $size = $monitors->{$key}{'size-x'} . 'x' . $monitors->{$key}{'size-y'} . + 'mm ('. $monitors->{$key}{'size-x-i'} . 'x' . $monitors->{$key}{'size-y-i'} . '")'; + $$row[$j]->{main::key($$num++,0,$m2,'size')} = $size; + } + if ($monitors->{$key}{'diagonal'}){ + my $diag = $monitors->{$key}{'diagonal-m'} . 'mm ('. $monitors->{$key}{'diagonal'} . '")'; + $$row[$j]->{main::key($$num++,0,$m2,'diag')} = $diag; + } + elsif ($b_display && !$b_no_size && !$monitors->{$key}{'size-x'} && + !$monitors->{$key}{'size-y'}){ + $$row[$j]->{main::key($$num++,0,$m2,'size')} = main::message('monitor-na');; + } + if ($b_admin && $monitors->{$key}{'ratio'}){ + $$row[$j]->{main::key($$num++,0,$m2,'ratio')} = $monitors->{$key}{'ratio'}; + } + if ($extra > 2){ + if ($monitors->{$key}{'modes-min-max'}){ + $$row[$j]->{main::key($$num++,0,$m2,'modes')} = $monitors->{$key}{'modes-min-max'}; + } + elsif ($monitors->{$key}{'modes-min'} && $monitors->{$key}{'modes-max'}){ + $$row[$j]->{main::key($$num++,1,$m2,'modes')} = ''; + $$row[$j]->{main::key($$num++,0,$m3,'max')} = $monitors->{$key}{'modes-max'}; + $$row[$j]->{main::key($$num++,0,$m3,'min')} = $monitors->{$key}{'modes-min'}; + } + } + } + # we only want to see gpu drivers for wayland since otherwise it's x drivers. +# if ($b_display && $b_admin && $graphics{'protocol'} && +# $graphics{'protocol'} eq 'wayland' && $monitors->{$key}{'drivers'}){ +# $driver = join(',',@{$monitors->{$key}{'drivers'}}); +# $$row[$j]->{main::key($$num++,0,$m2,'driver')} = $driver; +# } + eval $end if $b_log; +} -sub display_data_x { +## INTERFACE OUTPUT ## +# as soon as EGL for Wayland appears add it! +sub interface_output { eval $start if $b_log; - # X vendor and version detection. - # new method added since radeon and X.org and the disappearance of - # <X server name> version : ...etc. Later on, the normal textual version string - # returned, e.g. like: X.Org version: 6.8.2 - # A failover mechanism is in place: if $version empty, release number parsed instead - if (my $program = main::check_program('xdpyinfo')){ - my ($diagonal,$diagonal_m,$dpi) = ('','',''); - my ($screen_id,$screen,@working); - my ($res_x,$res_x_i,$res_y,$res_y_i,$size_x,$size_x_i,$size_y,$size_y_i); - my @xdpyinfo = main::grabber("$program $display_opt 2>/dev/null","\n",'strip'); - # @xdpyinfo = map {s/^\s+//;$_} @xdpyinfo if @xdpyinfo; - # print join("\n",@xdpyinfo), "\n"; - foreach (@xdpyinfo){ - @working = split(/:\s+/, $_); - next if (($graphics{'screens'} && $working[0] !~ /^(dimensions$|screen\s#)/) || !$working[0]); - # print "$_\n"; - if ($working[0] eq 'vendor string'){ - $working[1] =~ s/The\s|\sFoundation//g; - # some distros, like fedora, report themselves as the xorg vendor, - # so quick check here to make sure the vendor string includes Xorg in string - if ($working[1] !~ /x/i){ - $working[1] .= ' X.org'; - } - $graphics{'x-vendor'} = $working[1]; - } - elsif ($working[0] eq 'name of display'){ - $graphics{'display-id'} = $working[1]; - } - elsif ($working[0] eq 'version number'){ - $graphics{'x-version-id'} = $working[1]; - } - # note used, fix that - elsif ($working[0] eq 'vendor release number'){ - $graphics{'x-vendor-release'} = $working[1]; - } - elsif ($working[0] eq 'X.Org version'){ - $graphics{'xorg-version'} = $working[1]; - } - elsif ($working[0] eq 'default screen number'){ - $graphics{'display-default-screen'} = $working[1]; - } - elsif ($working[0] eq 'number of screens'){ - $graphics{'display-screens'} = $working[1]; - } - elsif ($working[0] =~ /^screen #([0-9]+):/){ - $screen_id = $1; - $graphics{'screens'} = () if !$graphics{'screens'}; - } - elsif ($working[0] eq 'resolution'){ - $working[1] =~ s/^([0-9]+)x/$1/; - $graphics{'s-dpi'} = $working[1]; - } - elsif ($working[0] eq 'dimensions'){ - ($dpi,$res_x,$res_y,$size_x,$size_y) = (undef,undef,undef,undef,undef); - if ($working[1] =~ /([0-9]+)\s*x\s*([0-9]+)\s+pixels\s+\(([0-9]+)\s*x\s*([0-9]+)\s*millimeters\)/){ - $res_x = $1; - $res_y = $2; - $size_x = $3; - $size_y = $4; - $res_x_i = ($1) ? sprintf("%.1f", ($1/25.4)) : 0; - $res_y_i = ($2) ? sprintf("%.1f", ($2/25.4)) : 0; - $size_x_i = ($3) ? sprintf("%.1f", ($3/25.4)) : 0; - $size_y_i = ($4) ? sprintf("%.1f", ($4/25.4)) : 0; - $dpi = ($res_x && $size_x) ? sprintf("%.0f", ($res_x*25.4/$size_x)) : ''; - $diagonal = ($res_x && $size_x) ? sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) : ''; - $diagonal += 0 if $diagonal;# trick to get rid of decimal 0 - $diagonal_m = ($res_x && $size_x) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : ''; - } - $screen = { - 'screen' => $screen_id, - 'res-x' => $res_x, - 'res-x-i' => $res_x_i, - 'res-y' => $res_y, - 'res-y-i' => $res_y_i, - 'size-x' => $size_x, - 'size-x-i' => $size_x_i, - 'size-y' => $size_y, - 'size-y-i' => $size_y_i, - 's-dpi' => $dpi, - 'diagonal' => $diagonal, - 'diagonal-m' => $diagonal_m, - }; - push(@{$graphics{'screens'}}, $screen); - } - } - # print Data::Dumper::Dumper $graphics{'screens'}; - if (my $program = main::check_program('xrandr')){ - ($diagonal,$diagonal_m,$dpi) = (undef); - ($screen_id,$screen,@working) = (undef); - ($res_x,$res_x_i,$res_y,$res_y_i,$size_x,$size_x_i,$size_y,$size_y_i) = (undef); - my (@monitors,$monitor_id,$screen,$screen_id,@xrandr_screens); - my @xrandr = main::grabber("$program $display_opt 2>/dev/null",'','strip'); - # $graphics{'dimensions'} = (\@dimensions); - # we get a bit more info from xrandr than xdpyinfo, but xrandr fails to handle - # multiple screens from different video cards - foreach (@xrandr){ - if (/^Screen ([0-9]+):/){ - $screen_id = $1; - push(@xrandr_screens, \@monitors) if @monitors; - @monitors = (); - } - if (/^([^\s]+)\s+connected\s(primary\s)?([0-9]+)\s*x\s*([0-9]+)\+[0-9+]+(\s\([^)]+\))?(\s([0-9]+)mm\sx\s([0-9]+)mm)?/){ - $monitor_id = $1; - $res_x = $3; - $res_y = $4; - $size_x = $7; - $size_y = $8; - $res_x_i = ($3) ? sprintf("%.1f", ($3/25.4)) : 0; - $res_y_i = ($4) ? sprintf("%.1f", ($4/25.4)) : 0; - $size_x_i = ($7) ? sprintf("%.1f", ($7/25.4)) : 0; - $size_y_i = ($8) ? sprintf("%.1f", ($8/25.4)) : 0; - $dpi = ($res_x && $size_x) ? sprintf("%.0f", $res_x * 25.4 / $size_x) : ''; - $diagonal = ($res_x && $size_x) ? sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) : ''; - $diagonal += 0 if $diagonal; # trick to get rid of decimal 0 - $diagonal_m = ($res_x && $size_x) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : ''; - push(@monitors, { - 'screen' => $screen_id, - 'monitor' => $monitor_id, - 'res-x' => $res_x, - 'res-x-i' => $res_x_i, - 'res-y' => $res_y, - 'res-y-i' => $res_y_i, - 'size-x' => $size_x, - 'size-x-i' => $size_x_i, - 'size-y' => $size_y, - 'size-y-i' => $size_y_i, - 'dpi' => $dpi, - 'diagonal' => $diagonal, - 'diagonal-m' => $diagonal_m, - }); - # print "x:$size_x y:$size_y rx:$res_x ry:$res_y dpi:$dpi\n"; - ($res_x,$res_x_i,$res_y,$res_y_i,$size_x,$size_x_i,$size_y,$size_y_i) = (0,0,0,0,0,0,0,0); - - } - my @working = split(/\s+/,$_); - if ($working[1] =~ /\*/){ - $working[1] =~ s/\*|\+//g; - $working[1] = sprintf("%.0f",$working[1]); - $monitors[scalar @monitors - 1]->{'hz'} = $working[1] if @monitors; - ($diagonal,$dpi) = ('',''); - # print Data::Dumper::Dumper \@monitors; - } + my $num = 0; + my (@row,$program,$type); + # print ("$b_display : $b_root\n"); + if ($b_display){ + if (!$force{'wayland'} && ($program = main::check_program('glxinfo'))){ + interface_glx_output($program,\@row,\$num); + } + elsif ($graphics{'xvesa'}){ + interface_vesa_output(\@row,\$num); + } + # handles no data until we find one for wayland egl data + elsif ($graphics{'protocol'} eq 'wayland'){ + interface_egl_output(\@row,\$num); + } + else { + @row = ({ + main::key($num++,0,1,'Message') => main::message('glxinfo-missing'), + }); + } + } + else { + $type = 'gl-console'; + if ($graphics{'xvesa'}){ + interface_vesa_output(\@row,\$num); + } + elsif (!main::check_program('glxinfo')){ + if ($graphics{'protocol'} eq 'wayland'){ + $type = 'interface-wayland'; } - push(@xrandr_screens, \@monitors) if @monitors; - # print "xrand: " . Data::Dumper::Dumper \@xrandr_screens; - my ($i) = (0); - foreach my $main (@{$graphics{'screens'}}){ - # print "h: " . Data::Dumper::Dumper $main; - # print $main->{'screen'}, "\n"; - foreach my $screens (@xrandr_screens){ - # print "d: " . Data::Dumper::Dumper $screens; - if ($screens->[0]{'screen'} eq $main->{'screen'}){ - $graphics{'screens'}->[$i]{'monitors'} = $screens; - last; - } - } - $i++; + else { + $type = 'glxinfo-missing'; } - if (!$graphics{'screens'}){ - $graphics{'tty'} = tty_data(); + } + else { + if ($graphics{'protocol'} eq 'wayland'){ + $type = 'interface-wayland'; + } + elsif ($b_root){ + $type = 'gl-root'; + } + else { + $type = 'gl-try'; + } + } + @row = ({ + main::key($num++,0,1,'Message') => main::message($type), + }); + } + eval $end if $b_log; + return @row; +} +sub interface_egl_output { + eval $start if $b_log; + my ($row,$num) = @_; + @$row = ({ + main::key($num++,0,1,'Message') => main::message('interface-wayland'), + }); + eval $end if $b_log; +} +sub interface_glx_output { + eval $start if $b_log; + my ($program,$row,$num) = @_; + # NOTE: glxinfo -B is not always available, unfortunately + my @glxinfo = main::grabber("$program $display_opt 2>/dev/null"); + # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/graphics/glxinfo/glxinfo-ssh-centos.txt"; + # my @glxinfo = main::reader($file); + if (!@glxinfo){ + my $type = 'gl-console'; + if ($b_root){ + $type = 'gl-root-display'; + } + else { + $type = 'gl-null'; + } + @$row = ({ + main::key($$num++,0,1,'Message') => main::message($type), + }); + return; + } + # print join("\n", @glxinfo),"\n"; + my $compat_version = ''; + my ($b_compat,$b_nogl,@core_profile_version,@direct_render,@renderer, + @opengl_version,@working); + foreach (@glxinfo){ + next if /^\s/; + if (/^opengl renderer/i){ + @working = split(/:\s*/, $_, 2); + if ($working[1]){ + $working[1] = main::clean($working[1]); + } + # note: there are cases where gl drivers are missing and empty + # field value occurs. + else { + $b_nogl = 1; + $working[1] = main::message('gl-empty'); + } + push(@renderer, $working[1]); + } + # dropping all conditions from this test to just show full mesa information + # there is a user case where not f and mesa apply, atom mobo + # /opengl version/ && ( f || $2 !~ /mesa/){ + elsif (/^opengl version/i){ + @working = split(/:\s*/, $_, 2); + if ($working[1]){ + # fglrx started appearing with this extra string, does not appear + # to communicate anything of value + $working[1] =~ s/(Compatibility Profile Context|\(Compatibility Profile\))//; + $working[1] =~ s/\s\s/ /g; + $working[1] =~ s/^\s+|\s+$//; + push(@opengl_version, $working[1]); + # note: this is going to be off if ever multi opengl versions appear, + # never seen one + @working = split(/\s+/, $working[1]); + $compat_version = $working[0]; + } + elsif (!$b_nogl){ + push(@opengl_version, main::message('gl-empty')); + } + } + elsif (/^opengl core profile version/i){ + @working = split(/:\s*/, $_, 2); + # note: no need to apply empty message here since we don't have the data + # anyway + if ($working[1]){ + # fglrx started appearing with this extra string, does not appear + # to communicate anything of value + $working[1] =~ s/(Compatibility Profile Context|\((Compatibility|Core) Profile\))//; + $working[1] =~ s/\s\s/ /g; + $working[1] =~ s/^\s+|\s+$//; + push(@core_profile_version, $working[1]); } } + elsif (/direct rendering/){ + @working = split(/:\s*/, $_, 2); + push(@direct_render, $working[1]); + } + # if -B was always available, we could skip this, but it is not + elsif (/GLX Visuals/){ + last; + } + } + my ($direct_render,$renderer,$version) = ('N/A','N/A','N/A'); + $direct_render = join(', ', @direct_render) if @direct_render; + # non free drivers once filtered and cleaned show the same for core and compat + # but this stopped for some reason at 4.5/4.6 nvidia + if (@core_profile_version && @opengl_version && + join('', @core_profile_version) ne join('', @opengl_version) && + !(grep {/nvidia/i} @opengl_version)){ + @opengl_version = @core_profile_version; + $b_compat = 1; + } + $version = join(', ', @opengl_version) if @opengl_version; + $renderer = join(', ', @renderer) if @renderer; + @$row = ({ + main::key($$num++,1,1,'OpenGL') => '', + main::key($$num++,1,2,'renderer') => ($renderer) ? $renderer : 'N/A', + main::key($$num++,0,2,'v') => ($version) ? $version : 'N/A', + }); + if ($b_compat && $extra > 1 && $compat_version){ + $row->[0]{main::key($$num++,0,2,'compat-v')} = $compat_version; + } + if ($extra > 0){ + $row->[0]{main::key($$num++,0,2,'direct render')} = $direct_render; + } + eval $end if $b_log; +} +# WARNING! Never seen a GOP type UEFI, needs more data +sub interface_vesa_output { + eval $start if $b_log; + my ($row,$num) = @_; + my ($controller,$dac,$interface,$ram,$source,$version); + # note: goes to stderr, not stdout + my @data = main::grabber($graphics{'xvesa'} . ' -listmodes 2>&1'); + if ($data[0] && $data[0] =~ /^(VBE|GOP)\s+version\s+(\S+)\s\(([^)]+)\)/i){ + $interface = $1; + $version = $2; + $source = $3; + } + if ($data[1] && $data[1] =~ /^DAC is ([^,]+), controller is ([^,]+)/i){ + $dac = $1; + $controller = $2; + } + if ($data[2] && $data[2] =~ /^Total memory:\s+(\d+)\s/i){ + $ram = $1; + $ram = main::get_size($ram,'string'); + } + if (!$interface){ + $row->[0]{main::key($$num++,0,1,'Message')} = main::message('xvesa-interface'); } else { - $graphics{'no-xdpyinfo'} = main::message('tool-missing-basic','xdpyinfo'); + $row->[0]{main::key($$num++,1,1,'Interface')} = $interface; + $row->[0]{main::key($$num++,0,2,'v')} = ($version) ? $version : 'N/A'; + $row->[0]{main::key($$num++,0,2,'source')} = ($source) ? $source : 'N/A'; + if ($dac){ + $row->[0]{main::key($$num++,0,2,'dac')} = $dac; + $row->[0]{main::key($$num++,0,2,'controller')} = $controller; + } + if ($ram){ + $row->[0]{main::key($$num++,0,2,'ram')} = $ram; + } } - print 'last: ', Data::Dumper::Dumper $graphics{'screens'} if $dbg[17]; - main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log; eval $end if $b_log; } + +## DISPLAY DATA WAYLAND ## sub display_data_wayland { eval $start if $b_log; + my ($b_skip_pos,$program); if ($ENV{'WAYLAND_DISPLAY'}){ $graphics{'display-id'} = $ENV{'WAYLAND_DISPLAY'}; # return as wayland-0 or 0? $graphics{'display-id'} =~ s/wayland-?//i; } - # print 'last: ', Data::Dumper::Dumper $graphics{'screens'} if $dbg[17]; - # main::log_data('dump','@graphics{screens}',$graphics{'screens'}) if $b_log; + if ($fake{'swaymsg'} || ($program = main::check_program('swaymsg'))){ + swaymsg_data($program); + } + # until we get data proving otherwise, assuming these have same output + elsif ($fake{'wl-info'} || (($program = main::check_program('wayland-info')) || + ($program = main::check_program('weston-info')))){ + wlinfo_data($program); + } + elsif ($fake{'wlr-randr'} || ($program = main::check_program('wlr-randr'))){ + wlrrandr_data($program); + } + # make sure we got enough for advanced position data, might be from /sys + if ($extra > 1 && $monitor_ids){ + $b_skip_pos = check_wayland_data(); + } + if ($extra > 1 && $monitor_ids && $b_wayland_data){ + # map_monitor_ids([keys %$monitors]); # not required, but leave in case. + wayland_data_advanced($b_skip_pos); + } + print 'Wayland monitors: ', Data::Dumper::Dumper $monitor_ids if $dbg[17]; + main::log_data('dump','$monitor_ids',$monitor_ids) if $b_log; eval $end if $b_log; } -sub set_compositor { +# if we didn't get explicit tool for wayland data, check to see if we got most +# of the data from /sys/class/drm edid and then skip xrandr to avoid gunking up +# the data, in that case, all we get from xrandr would be the position, which is +# nice but not a must-have. We've already cleared out all disabled ports. +sub check_wayland_data { eval $start if $b_log; - my ($protocol) = @_; - # initial tests, if wayland, it is certainly a compositor - $protocol = lc($protocol) if $protocol; - $graphics{'compositor'} = display_compositor($protocol); - # gnome-shell is incredibly slow to return version - if (($extra > 2 || $protocol eq 'wayland') && $graphics{'compositor'} && - (!$show{'system'} || $graphics{'compositor'} ne 'gnome-shell')){ - $graphics{'compositor-version'} = (main::program_data($graphics{'compositor'},$graphics{'compositor'},3))[1]; + my ($b_skip_pos,$b_invalid); + foreach my $key (keys %$monitor_ids){ + # we need these 4 items to construct the grid rectangle + if (!defined $monitor_ids->{$key}{'pos-x'} || + !defined $monitor_ids->{$key}{'pos-y'} || + !$monitor_ids->{$key}{'res-x'} || !$monitor_ids->{$key}{'res-y'}){ + $b_skip_pos = 1; + } + if (!$monitor_ids->{$key}{'res-x'} || !$monitor_ids->{$key}{'res-y'}){ + $b_invalid = 1; + } } + # ok, we have enough, we don't need to do fallback xrandr checks + $b_wayland_data = 1 if !$b_invalid; eval $end if $b_log; + return $b_skip_pos; } -sub get_protocol { +# Set Display rect size for > 1 monitors, monitor positions, size-i, diag +sub wayland_data_advanced { eval $start if $b_log; - my ($protocol) = (''); - $protocol = $ENV{'XDG_SESSION_TYPE'} if $ENV{'XDG_SESSION_TYPE'}; - $protocol = $ENV{'WAYLAND_DISPLAY'} if (!$protocol && $ENV{'WAYLAND_DISPLAY'}); - # can show as wayland-0 - $protocol = 'wayland' if $protocol && $protocol =~ /wayland/i; - # yes, I've seen this in 2019 distros, sigh - $protocol = '' if $protocol eq 'tty'; - # need to confirm that there's a point to this test, I believe no, fails out of x - # loginctl also results in the session id - if (!$protocol && $b_display && $force{'display'}){ - if (my $program = main::check_program('loginctl')){ - my $id = ''; - # $id = $ENV{'XDG_SESSION_ID'}; # returns tty session in console - my @data = main::grabber("$program --no-pager --no-legend 2>/dev/null",'','strip'); - foreach (@data){ - next if /tty[v]?[0-6]$/; # freebsd: ttyv3 - $id = (split(/\s+/, $_))[0]; - last; # multiuser? too bad, we'll go for the first one + my ($b_skip_pos) = @_; + my (%x_pos,%y_pos); + my ($x_max,$y_max) = (0,0); + my @keys = keys %$monitor_ids; + foreach my $key (@keys){ + if (!$b_skip_pos){ + if ($monitor_ids->{$key}{'res-x'} && $monitor_ids->{$key}{'res-x'} > $x_max){ + $x_max = $monitor_ids->{$key}{'res-x'}; } - if ($id){ - my $temp = (main::grabber("$program show-session $id -p Type --no-pager --no-legend 2>/dev/null"))[0]; - $temp =~ s/Type=// if $temp; - # ssh will not show /dev/ttyx so would have passed the first test - $protocol = $temp if $temp && $temp ne 'tty'; + if ($monitor_ids->{$key}{'res-y'} && $monitor_ids->{$key}{'res-y'} > $y_max){ + $y_max = $monitor_ids->{$key}{'res-y'}; } + # Now we'll add the detected x, y res to the trackers + if (!defined $x_pos{$monitor_ids->{$key}{'pos-x'}}){ + $x_pos{$monitor_ids->{$key}{'pos-x'}} = $monitor_ids->{$key}{'res-x'}; + } + if (!defined $y_pos{$monitor_ids->{$key}{'pos-y'}}){ + $y_pos{$monitor_ids->{$key}{'pos-y'}} += $monitor_ids->{$key}{'res-y'}; + } + } + # this means we failed to get EDID real data, and are using just the wayland + # tool to get this info, eg. with BSD without compositor data. + if ($monitor_ids->{$key}{'size-x'} && $monitor_ids->{$key}{'size-y'} && + (!$monitor_ids->{$key}{'size-x-i'} || !$monitor_ids->{$key}{'size-y-i'} || + !$monitor_ids->{$key}{'dpi'} || !$monitor_ids->{$key}{'diagonal'})){ + my $size_x = $monitor_ids->{$key}{'size-x'}; + my $size_y = $monitor_ids->{$key}{'size-y'}; + $monitor_ids->{$key}{'size-x-i'} = sprintf("%.1f", ($size_x/25.4)); + $monitor_ids->{$key}{'size-y-i'} = sprintf("%.1f", ($size_y/25.4)); + $monitor_ids->{$key}{'diagonal'} = sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) + 0; + $monitor_ids->{$key}{'diagonal-m'} = sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))); + if ($monitor_ids->{$key}{'res-x'}){ + my $res_x = $monitor_ids->{$key}{'res-x'}; + $monitor_ids->{$key}{'dpi'} = sprintf("%.0f", $res_x * 25.4 / $size_x); + } + } + } + if (!$b_skip_pos){ + if (scalar @keys > 1 && %x_pos && %y_pos){ + my ($x,$y) = (0,0); + foreach (keys %x_pos){$x += $x_pos{$_}} + foreach (keys %y_pos){$y += $y_pos{$_}} + # handle cases with one tall portrait mode > 2 short landscapes, etc. + $x = $x_max if $x_max > $x; + $y = $y_max if $y_max > $y; + $graphics{'display-rect'} = $x . 'x' . $y; } + my $layouts = []; + set_monitor_layouts($layouts); + # only update position, we already have all the rest of the data + advanced_monitor_data($monitor_ids,$layouts); + undef $layouts; } eval $end if $b_log; - return $protocol; } -sub gl_output(){ + +## WAYLAND COMPOSITOR DATA TOOLS ## + +# NOTE: These patterns are VERY fragile, and depend on no changes at all to +# the data structure, and more important, the order. Something I would put +# almost no money on being able to count on. +sub wlinfo_data { eval $start if $b_log; - my $num = 0; - my (@row,$arg); - # print ("$b_display : $b_root\n"); - if ($b_display){ - if (my $program = main::check_program('glxinfo')){ - # NOTE: glxinfo -B is not always available, unfortunately - my @glxinfo = main::grabber("$program $display_opt 2>/dev/null"); - # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/graphics/glxinfo/glxinfo-ssh-centos.txt"; - # my @glxinfo = main::reader($file); - if (!@glxinfo){ - my $type = 'display-console'; - if ($b_root){ - $type = 'display-root-x'; + my ($program) = @_; + my (@data,%mon,@temp,$ref); + my ($b_iwlo,$b_izxdg,$file,$hz,$id,$pos_x,$pos_y,$res_x,$res_y,$scale); + if (!$fake{'wl-info'}){ + undef $monitor_ids; + @data = main::grabber("$program 2>/dev/null",'','strip'); + } + else { + $file = "$ENV{'HOME'}/bin/scripts/inxi/data/wayland/weston-info-2-mon-1.txt"; + @data = main::reader($file,'strip'); + } + print 'wayland/weston-info raw: ', Data::Dumper::Dumper \@data if $dbg[46]; + main::log_data('dump','@data', \@data) if $b_log; + foreach (@data){ + # print 'l: ', $_,"\n"; + if (/^interface: 'wl_output', version: \d+, name: (\d+)$/){ + $b_iwlo = 1; + $id = $1; + } + elsif (/^interface: 'zxdg_output/){ + $b_izxdg = 1; + $b_iwlo = 0; + } + if ($b_iwlo){ + if (/^x: (\d+), y: (\d+), scale: ([\d\.]+)/){ + $mon{$id}->{'pos-x'} = $1; + $mon{$id}->{'pos-y'} = $2; + $mon{$id}->{'scale'} = $3; + } + elsif (/^physical_width: (\d+) mm, physical_height: (\d+) mm/){ + $mon{$id}->{'size-x'} = $1 if $1; # can be 0 if edid data n/a + $mon{$id}->{'size-y'} = $2 if $2; # can be 0 if edid data n/a + } + elsif (/^make: '([^']+)', model: '([^']+)'/){ + my $make = main::clean($1); + my $model = main::clean($2); + $mon{$id}->{'model'} = $make; + if ($make && $model){ + $mon{$id}->{'model'} = $make . ' ' . $model; } - else { - $type = 'display-null'; + elsif ($model) { + $mon{$id}->{'model'} = $model; } - @row = ({ - main::key($num++,0,1,'Message') => main::message($type), - }); - return @row; - } - # print join("\n", @glxinfo),"\n"; - my $compat_version = ''; - my ($b_compat,$b_nogl,@core_profile_version,@direct_render,@renderer, - @opengl_version,@working); - foreach (@glxinfo){ - next if /^\s/; - if (/^opengl renderer/i){ - @working = split(/:\s*/, $_, 2); - if ($working[1]){ - $working[1] = main::clean($working[1]); - # Allow all mesas - # if ($working[1] =~ /mesa/i){ - # - # } - } - # note: there are cases where gl drivers are missing and empty - # field value occurs. - else { - $b_nogl = 1; - $working[1] = main::message('gl-empty'); - } - push(@renderer, $working[1]); - } - # dropping all conditions from this test to just show full mesa information - # there is a user case where not f and mesa apply, atom mobo - # /opengl version/ && ( f || $2 !~ /mesa/){ - elsif (/^opengl version/i){ - @working = split(/:\s*/, $_, 2); - if ($working[1]){ - # fglrx started appearing with this extra string, does not appear - # to communicate anything of value - $working[1] =~ s/(Compatibility Profile Context|\(Compatibility Profile\))//; - $working[1] =~ s/\s\s/ /g; - $working[1] =~ s/^\s+|\s+$//; - push(@opengl_version, $working[1]); - # note: this is going to be off if ever multi opengl versions appear, - # never seen one - @working = split(/\s+/, $working[1]); - $compat_version = $working[0]; - } - elsif (!$b_nogl){ - push(@opengl_version, main::message('gl-empty')); + elsif ($make) { + $mon{$id}->{'model'} = $make; + } + # includes remove duplicates and remove unset + if ($mon{$id}->{'model'}){ + $mon{$id}->{'model'} = main::clean_dmi($mon{$id}->{'model'}); + } + } + elsif (/^width: (\d+) px, height: (\d+) px, refresh: ([\d\.]+) Hz,/){ + $mon{$id}->{'res-x'} = $1; + $mon{$id}->{'res-y'} = $2; + $mon{$id}->{'hz'} = sprintf('%.0f',$3); + } + } + # note: we don't want to use the 'description' field because that doesn't + # always contain make/model data, sometimes it's: Built-in/Unknown Display + elsif ($b_izxdg){ + if (/^output: (\d+)/){ + $id = $1; + } + elsif (/^name: '([^']+)'$/){ + $mon{$id}->{'monitor'} = $1; + } + elsif (/^logical_x: (\d+), logical_y: (\d+)/){ + $mon{$id}->{'log-pos-x'} = $1; + $mon{$id}->{'log-pos-y'} = $2; + } + elsif (/^logical_width: (\d+), logical_height: (\d+)/){ + $mon{$id}->{'log-x'} = $1; + $mon{$id}->{'log-y'} = $2; + } + } + if ($b_izxdg && /^interface: '(?!zxdg_output)/){ + last; + } + } + # now we need to map %mon back to $monitor_ids + if (%mon){ + $b_wayland_data = 1; + foreach my $key (keys %mon){ + next if !$mon{$key}->{'monitor'}; # no way to know what it is, sorry + $id = $mon{$key}->{'monitor'}; + $monitor_ids->{$id}{'monitor'} = $id; + $monitor_ids->{$id}{'log-x'} = $mon{$key}->{'log-x'} if defined $mon{$key}->{'log-x'}; + $monitor_ids->{$id}{'log-y'} = $mon{$key}->{'log-y'} if defined $mon{$key}->{'log-y'}; + $monitor_ids->{$id}{'pos-x'} = $mon{$key}->{'pos-x'} if defined $mon{$key}->{'pos-x'}; + $monitor_ids->{$id}{'pos-y'} = $mon{$key}->{'pos-y'} if defined $mon{$key}->{'pos-y'}; + $monitor_ids->{$id}{'res-x'} = $mon{$key}->{'res-x'} if defined $mon{$key}->{'res-x'}; + $monitor_ids->{$id}{'res-y'} = $mon{$key}->{'res-y'} if defined $mon{$key}->{'res-y'}; + $monitor_ids->{$id}{'size-x'} = $mon{$key}->{'size-x'} if defined $mon{$key}->{'size-x'}; + $monitor_ids->{$id}{'size-y'} = $mon{$key}->{'size-y'} if defined $mon{$key}->{'size-y'}; + $monitor_ids->{$id}{'hz'} = $mon{$key}->{'hz'} if defined $mon{$key}->{'hz'}; + if (defined $mon{$key}->{'model'} && !$monitor_ids->{$id}{'model'}){ + $monitor_ids->{$id}{'model'} = $mon{$key}->{'model'}; + } + $monitor_ids->{$id}{'scale'} = $mon{$key}->{'scale'} if defined $mon{$key}->{'scale'}; + # fallbacks in case wl_output block is not present, which happens + if (!defined $mon{$key}->{'pos-x'} && defined $mon{$key}->{'log-pos-x'}){ + $monitor_ids->{$id}{'pos-x'} = $mon{$key}->{'log-pos-x'}; + } + if (!defined $mon{$key}->{'pos-y'} && defined $mon{$key}->{'log-pos-y'}){ + $monitor_ids->{$id}{'pos-y'} = $mon{$key}->{'log-pos-y'}; + } + if (!defined $mon{$key}->{'res-x'} && defined $mon{$key}->{'log-x'}){ + $monitor_ids->{$id}{'res-x'} = $mon{$key}->{'log-x'}; + } + if (!defined $mon{$key}->{'res-y'} && defined $mon{$key}->{'log-y'}){ + $monitor_ids->{$id}{'res-y'} = $mon{$key}->{'log-y'}; + } + } + } + print '%mon: ', Data::Dumper::Dumper \%mon if $dbg[46]; + main::log_data('dump','%mon', \%mon) if $b_log; + print 'wayland/weston-info: monitor_ids: ', Data::Dumper::Dumper $monitor_ids if $dbg[46]; + eval $end if $b_log; +} +# note; since not all systems will have /sys data, we'll repack it if it's +# missing here. +sub swaymsg_data { + eval $start if $b_log; + my ($program) = @_; + my (@data,%json,@temp,$ref); + my ($b_json,$file,$hz,$id,$model,$pos_x,$pos_y,$res_x,$res_y,$scale,$serial); + if (!$fake{'swaymsg'}){ + main::load_json() if !$loaded{'json'}; + if ($use{'json'}){ + my $result = qx($program -t get_outputs -r 2>/dev/null); + # returns array of monitors found + @data = &{$use{'json'}->{'decode'}}($result) if $result; + $b_json = 1; + print "$use{'json'}->{'type'}: " if $dbg[46]; + # print "using: $use{'json'}->{'type'}\n"; + } + else { + @data = main::grabber("$program -t get_outputs -p 2>/dev/null",'','strip'); + } + } + else { + undef $monitor_ids; + $file = "$ENV{'HOME'}/bin/scripts/inxi/data/wayland/swaymsg-2-monitor-1.txt"; + @data = main::reader($file,'strip'); + } + print 'swaymsg: ', Data::Dumper::Dumper \@data if $dbg[46]; + main::log_data('dump','@data', \@data) if $b_log; + # print Data::Dumper::Dumper \@data; + if ($b_json){ + $b_wayland_data = 1 if scalar @data > 0; + foreach my $display (@data){ + foreach my $mon (@$display){ + ($hz,$pos_x,$pos_y,$res_x,$res_y,$scale) = (); + $id = $mon->{'name'}; + if (!$monitor_ids->{$id}{'monitor'}){ + $monitor_ids->{$id}{'monitor'} = $mon->{'name'}; + } + # we don't want to overwrite good edid model data if we already got it + if (!$monitor_ids->{$id}{'model'} && $mon->{'make'}){ + $monitor_ids->{$id}{'model'} = main::clean($mon->{'make'}); + if ($mon->{'model'}){ + $monitor_ids->{$id}{'model'} .= ' ' . main::clean($mon->{'model'}); + } + $monitor_ids->{$id}{'model'} = main::remove_duplicates($monitor_ids->{$id}{'model'}); + } + if ($monitor_ids->{$id}{'primary'} && + $monitor_ids->{$id}{'primary'} ne 'false'){ + $monitor_ids->{$id}{'primary'} = $id; } - elsif (/^opengl core profile version/i){ - @working = split(/:\s*/, $_, 2); - # note: no need to apply empty message here since we don't have the data - # anyway - if ($working[1]){ - # fglrx started appearing with this extra string, does not appear - # to communicate anything of value - $working[1] =~ s/(Compatibility Profile Context|\((Compatibility|Core) Profile\))//; - $working[1] =~ s/\s\s/ /g; - $working[1] =~ s/^\s+|\s+$//; - push(@core_profile_version, $working[1]); + if (!$monitor_ids->{$id}{'serial'}){ + $monitor_ids->{$id}{'serial'} = main::clean_dmi($mon->{'serial'}); + } + # sys data will only have edid type info, not active state res/pos/hz + if ($mon->{'current_mode'}){ + if ($hz = $mon->{'current_mode'}{'refresh'}){ + $hz = sprintf('%.0f',($mon->{'current_mode'}{'refresh'}/1000)); + $monitor_ids->{$id}{'hz'} = $hz; } + $monitor_ids->{$id}{'res-x'} = $mon->{'current_mode'}{'width'}; + $monitor_ids->{$id}{'res-y'} = $mon->{'current_mode'}{'height'}; } - elsif (/direct rendering/){ - @working = split(/:\s*/, $_, 2); - push(@direct_render, $working[1]); + if ($mon->{'rect'}){ + $monitor_ids->{$id}{'pos-x'} = $mon->{'rect'}{'x'}; + $monitor_ids->{$id}{'pos-y'} = $mon->{'rect'}{'y'}; } - # if -B was always available, we could skip this, but it is not - elsif (/GLX Visuals/){ - last; + if ($mon->{'scale'}){ + $monitor_ids->{$id}{'scale'} =$mon->{'scale'}; + } + } + } + } + else { + foreach (@data){ + push(@temp,'~~') if /^Output/i; + push(@temp,$_); + } + push(@temp,'~~') if @temp; + @data = @temp; + $b_wayland_data = 1 if scalar @data > 8; + foreach (@data){ + if ($_ eq '~~' && $id){ + $monitor_ids->{$id}{'hz'} = $hz; + $monitor_ids->{$id}{'model'} = $model if $model; + $monitor_ids->{$id}{'monitor'} = $id; + $monitor_ids->{$id}{'pos-x'} = $pos_x; + $monitor_ids->{$id}{'pos-y'} = $pos_y; + $monitor_ids->{$id}{'res-x'} = $res_x; + $monitor_ids->{$id}{'res-y'} = $res_y; + $monitor_ids->{$id}{'scale'} = $scale; + $monitor_ids->{$id}{'serial'} = $serial if $serial; + ($hz,$model,$pos_x,$pos_y,$res_x,$res_y,$scale,$serial) = (); + $b_wayland_data = 1; + } + # Output VGA-1 '<Unknown> <Unknown> ' (focused) + # unknown how 'primary' is shown, if it shows in this output + if (/^Output (\S+) '([^']+)'/i){ + $id = $1; + if ($2 && !$monitor_ids->{$id}{'model'}){ + ($model,$serial) = get_model_serial($2); } } - my ($direct_render,$renderer,$version) = ('N/A','N/A','N/A'); - $direct_render = join(', ', @direct_render) if @direct_render; - # non free drivers once filtered and cleaned show the same for core and compat - # but this stopped for some reason at 4.5/4.6 nvidia - if (@core_profile_version && @opengl_version && - join('', @core_profile_version) ne join('', @opengl_version) && - !(grep {/nvidia/i} @opengl_version)){ - @opengl_version = @core_profile_version; - $b_compat = 1; + elsif (/^Current mode:\s+(\d+)x(\d+)\s+\@\s+([\d\.]+)\s+Hz/i){ + $res_x = $1; + $res_y = $2; + $hz = (sprintf('%.0f',($3/1000)) + 0) if $3; } - $version = join(', ', @opengl_version) if @opengl_version; - $renderer = join(', ', @renderer) if @renderer; - @row = ({ - main::key($num++,1,1,'OpenGL') => '', - main::key($num++,1,2,'renderer') => ($renderer) ? $renderer : 'N/A', - main::key($num++,0,2,'v') => ($version) ? $version : 'N/A', - }); - if ($b_compat && $extra > 1 && $compat_version){ - $row[0]->{main::key($num++,0,2,'compat-v')} = $compat_version; + elsif (/^Position:\s+(\d+),(\d+)/i){ + $pos_x = $1; + $pos_y = $2; } - if ($extra > 0){ - $row[0]->{main::key($num++,0,2,'direct render')} = $direct_render; + elsif (/^Scale factor:\s+([\d\.]+)/i){ + $scale = $1 + 0; } } - else { - @row = ({ - main::key($num++,0,1,'Message') => main::message('glxinfo-missing'), - }); - } + } + print 'swaymsg: ', Data::Dumper::Dumper $monitor_ids if $dbg[46]; + eval $end if $b_log; +} +# like a basic stripped down swaymsg -t get_outputs -p, less data though +# This is EXTREMELY LIKELY TO FAIL! Any tiny syntax change will break this. +sub wlrrandr_data { + eval $start if $b_log; + my ($program) = @_; + my ($file,$hz,$id,$info,$model,$pos_x,$pos_y,$res_x,$res_y,$scale,$serial); + my (@data,@temp); + if (!$fake{'wlr-randr'}){ + @data = main::grabber("$program 2>/dev/null",'','strip'); } else { - my $type = 'display-console'; - if (!main::check_program('glxinfo')){ - $type = 'glxinfo-missing'; + undef $monitor_ids; + $file = "$ENV{'HOME'}/bin/scripts/inxi/data/wayland/wlr-randr-2-monitor-1.txt"; + @data = main::reader($file,'strip'); + } + foreach (@data){ + push(@temp,'~~') if /^([A-Z]+-[ABID\d-]+)\s['"]/i; + push(@temp,$_); + } + push(@temp,'~~') if @temp; + @data = @temp; + $b_wayland_data = 1 if scalar @data > 4; + print 'wlr-randr: ', Data::Dumper::Dumper \@data if $dbg[46]; + main::log_data('dump','@data', \@data) if $b_log; + foreach (@data){ + if ($_ eq '~~' && $id){ + $monitor_ids->{$id}{'hz'} = $hz; + $monitor_ids->{$id}{'model'} = $model if $model && !$monitor_ids->{$id}{'model'}; + $monitor_ids->{$id}{'monitor'} = $id; + $monitor_ids->{$id}{'pos-x'} = $pos_x; + $monitor_ids->{$id}{'pos-y'} = $pos_y; + $monitor_ids->{$id}{'res-x'} = $res_x; + $monitor_ids->{$id}{'res-y'} = $res_y; + $monitor_ids->{$id}{'scale'} = $scale; + $monitor_ids->{$id}{'serial'} = $serial if $serial && !$monitor_ids->{$id}{'serial'}; + ($hz,$info,$model,$pos_x,$pos_y,$res_x,$res_y,$scale,$serial) = (); + $b_wayland_data = 1; + } + # Output: VGA-1 '<Unknown> <Unknown> ' (focused) + # DVI-I-1 'Samsung Electric Company SyncMaster H9NX843762' (focused) + # unknown how 'primary' is shown, if it shows in this output + if (/^([A-Z]+-[ABID\d-]+)\s([']([^']+)['])?/i){ + $id = $1; + # if model is set, we got edid data + if ($3 && !$monitor_ids->{$id}{'model'}){ + ($model,$serial) = get_model_serial($3); + } } - else { - if ($b_root){ - $type = 'display-root'; + elsif (/^(\d+)x(\d+)\s+px,\s+([\d\.]+)\s+Hz \([^\)]*?current\)/i){ + $res_x = $1; + $res_y = $2; + $hz = sprintf('%.0f',$3) if $3; + } + elsif (/^Position:\s+(\d+),(\d+)/i){ + $pos_x = $1; + $pos_y = $2; + } + elsif (/^Scale:\s+([\d\.]+)/i){ + $scale = $1 + 0; + } + } + print 'wlr-randr: ', Data::Dumper::Dumper $monitor_ids if $dbg[46]; + eval $end if $b_log; +} +# return model/serial for those horrible string type values we have to process +# in swaymsg -t get_outputs -p and wlr-randr default output +sub get_model_serial { + eval $start if $b_log; + my $info = $_[0]; + my ($model,$serial); + $info = main::clean($info); + return if !$info; + my @parts = split(/\s+/, $info); + # Perl Madness, lol: the last just checks how many integers in string + if (scalar @parts > 1 && (length($parts[-1]) > 7) && + (($parts[-1] =~ tr/[0-9]//) > 4)){ + $serial = pop @parts; + $serial = main::clean_dmi($serial); # clears out 0x00000 type non data + } + # we're assuming that we'll never get a serial without make/model data too. + $model = join(' ',@parts) if @parts; + $model = main::remove_duplicates($model) if $model && scalar @parts > 1; + eval $end if $b_log; + return ($model,$serial); +} + +# DISPLAY DATA X.org ## +sub display_data_x { + eval $start if $b_log; + my ($prog_xdpyinfo,$prog_xrandr); + if ($prog_xdpyinfo = main::check_program('xdpyinfo')){ + xdpyinfo_data($prog_xdpyinfo); + } + # print Data::Dumper::Dumper $graphics{'screens'}; + if ($prog_xrandr = main::check_program('xrandr')){ + xrandr_data($prog_xrandr); + } + if (!$graphics{'screens'}){ + $graphics{'tty'} = tty_data(); + } + if (!$prog_xrandr){ + $graphics{'no-monitors'} = main::message('tool-missing-basic','xrandr'); + if (!$prog_xdpyinfo){ + if ($graphics{'protocol'} eq 'wayland'){ + $graphics{'no-screens'} = main::message('screen-wayland'); } else { - $type = 'display-try'; + $graphics{'no-screens'} = main::message('tool-missing-basic','xdpyinfo/xrandr'); } } - @row = ({ - main::key($num++,0,1,'Message') => main::message($type), - }); } + print 'Final display x: ', Data::Dumper::Dumper $graphics{'screens'} if $dbg[17]; + main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log; eval $end if $b_log; - return @row; } -sub tty_data(){ +sub xdpyinfo_data { eval $start if $b_log; - my ($tty); - if ($size{'term-cols'}){ - $tty = "$size{'term-cols'}x$size{'term-lines'}"; + my ($program) = @_; + my ($diagonal,$diagonal_m,$dpi) = ('','',''); + my ($screen_id,$screen,@working); + my ($res_x,$res_y,$size_x,$size_x_i,$size_y,$size_y_i); + my @xdpyinfo = main::grabber("$program $display_opt 2>/dev/null","\n",'strip'); + # @xdpyinfo = map {s/^\s+//;$_} @xdpyinfo if @xdpyinfo; + # print join("\n",@xdpyinfo), "\n"; + # X vendor and version detection. + # new method added since radeon and X.org and the disappearance of + # <X server name> version : ...etc. Later on, the normal textual version string + # returned, e.g. like: X.Org version: 6.8.2 + # A failover mechanism is in place: if $version empty, release number parsed instead + foreach (@xdpyinfo){ + @working = split(/:\s+/, $_); + next if (($graphics{'screens'} && $working[0] !~ /^(dimensions$|screen\s#)/) || !$working[0]); + # print "$_\n"; + if ($working[0] eq 'vendor string'){ + $working[1] =~ s/The\s|\sFoundation//g; + # some distros, like fedora, report themselves as the xorg vendor, + # so quick check here to make sure the vendor string includes Xorg in string + if ($working[1] !~ /x/i){ + $working[1] .= ' X.org'; + } + $graphics{'x-server'} = [[$working[1]]]; + } + elsif ($working[0] eq 'name of display'){ + $graphics{'display-id'} = $working[1]; + } + # this is the x protocol version + elsif ($working[0] eq 'version number'){ + $graphics{'x-protocol-version'} = $working[1]; + } + # not used, but might be good for something? + elsif ($working[0] eq 'vendor release number'){ + $graphics{'x-vendor-release'} = $working[1]; + } + # the real X.org version string + elsif ($working[0] eq 'X.Org version'){ + push(@{$graphics{'x-server'}->[0]},$working[1]); + } + elsif ($working[0] eq 'default screen number'){ + $graphics{'display-default-screen'} = $working[1]; + } + elsif ($working[0] eq 'number of screens'){ + $graphics{'display-screens'} = $working[1]; + } + elsif ($working[0] =~ /^screen #([0-9]+):/){ + $screen_id = $1; + } + elsif ($working[0] eq 'resolution'){ + $working[1] =~ s/^([0-9]+)x/$1/; + $graphics{'s-dpi'} = $working[1]; + } + # This is Screen, not monitor: dimensions: 2560x1024 pixels (677x270 millimeters) + elsif ($working[0] eq 'dimensions'){ + ($dpi,$res_x,$res_y,$size_x,$size_y) = (); + if ($working[1] =~ /([0-9]+)\s*x\s*([0-9]+)\s+pixels\s+\(([0-9]+)\s*x\s*([0-9]+)\s*millimeters\)/){ + $res_x = $1; + $res_y = $2; + $size_x = $3; + $size_y = $4; + # flip size x,y if don't roughly match res x/y ratio + if ($size_x && $size_y && $res_y){ + flip_size_x_y(\$size_x,\$size_y,\$res_x,\$res_y); + } + $size_x_i = ($size_x) ? sprintf("%.1f", ($size_x/25.4)) : 0; + $size_y_i = ($size_y) ? sprintf("%.1f", ($size_y/25.4)) : 0; + $dpi = ($res_x && $size_x) ? sprintf("%.0f", ($res_x*25.4/$size_x)) : ''; + $diagonal = ($size_x && $size_y) ? sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) : ''; + $diagonal += 0 if $diagonal;# trick to get rid of decimal 0 + $diagonal_m = ($size_x && $size_y) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : ''; + } + $screen = { + 'screen' => $screen_id, + 'res-x' => $res_x, + 'res-y' => $res_y, + 'size-x' => $size_x, + 'size-x-i' => $size_x_i, + 'size-y' => $size_y, + 'size-y-i' => $size_y_i, + 's-dpi' => $dpi, + 'diagonal' => $diagonal, + 'diagonal-m' => $diagonal_m, + }; + push(@{$graphics{'screens'}}, $screen); + } } - # this is broken - elsif ($b_irc && $client{'console-irc'}){ - ShellData::console_irc_tty() if !$loaded{'con-irc-tty'}; - my $tty_working = $client{'con-irc-tty'}; - if ($tty_working ne '' && (my $program = main::check_program('stty'))){ - my $tty_arg = ($bsd_type) ? '-f' : '-F'; - # handle vtnr integers, and tty ID with letters etc. - $tty_working = "tty$tty_working" if -e "/dev/tty$tty_working"; - $tty = (main::grabber("$program $tty_arg /dev/$tty_working size 2>/dev/null"))[0]; - if ($tty){ - my @temp = split(/\s+/, $tty); - $tty = "$temp[1]x$temp[0]"; + print 'Data: xdpyinfo: ', Data::Dumper::Dumper $graphics{'screens'} if $dbg[17]; + main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log; + eval $end if $b_log; +} +sub xrandr_data { + eval $end if $b_log; + my ($program) = @_; + my ($diagonal,$diagonal_m,$dpi,$monitor_id,$pos_x,$pos_y,$primary); + my ($res_x,$res_x_max,$res_y,$res_y_max); + my ($screen_id,$set_as,$size_x,$size_x_i,$size_y,$size_y_i,$x_screen); + my (@ids,%monitors,@xrandr_screens,@xrandr); + if (!$fake{'xrandr'}){ + @xrandr = main::grabber("$program $display_opt 2>/dev/null",'','strip'); + } + else { + @xrandr = main::reader("$ENV{HOME}/bin/scripts/inxi/svn/branches/inxi-perl/xrandr.txt",'strip'); + } + # $graphics{'dimensions'} = (\@dimensions); + # we get a bit more info from xrandr than xdpyinfo, but xrandr fails to handle + # multiple screens from different video cards + foreach (@xrandr){ + # note: no mm as with xdpyinfo + # Screen 0: minimum 320 x 200, current 2560 x 1024, maximum 8192 x 8192 + if (/^Screen ([0-9]+):/){ + $screen_id = $1; + # handle no xdpyinfo Screen data + if ((!$graphics{'screens'} || + scalar @{$graphics{'screens'}} != (scalar @xrandr_screens + 1)) && + /:\s.*?current\s+(\d+)\s*x\s*(\d+),\smaximum\s+(\d+)\s*x\s*(\d+)/){ + $res_x = $1; + $res_y = $2; + $res_x_max = $3; + $res_y_max = $4; + $x_screen = { + 'screen' => $screen_id, + 'res-x' => $res_x, + 'res-y' => $res_y, + 'size-x' => undef, + 'size-x-i' => undef, + 'size-y' => undef, + 'size-y-i' => undef, + 's-dpi' => undef, + 'diagonal' => undef, + 'diagonal-m' => undef, + }; + push(@{$graphics{'screens'}}, $x_screen); + } + if (%monitors){ + push(@xrandr_screens,\%monitors); + %monitors = (); + } + } + # HDMI-2 connected 1920x1200+1080+0 (normal left inverted right x axis y axis) 519mm x 324mm + # 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 + elsif (/^([^\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)?/){ + $monitor_id = $1; + $set_as = $2; + $res_x = $3; + $res_y = $4; + $pos_x = $5; + $pos_y = $6; + $size_x = $9; + $size_y = $10; + # flip size x,y if don't roughly match res x/y ratio + if ($size_x && $size_y && $res_y){ + flip_size_x_y(\$size_x,\$size_y,\$res_x,\$res_y); + } + $size_x_i = ($size_x) ? sprintf("%.1f", ($size_x/25.4)) : 0; + $size_y_i = ($size_y) ? sprintf("%.1f", ($size_y/25.4)) : 0; + $dpi = ($res_x && $size_x) ? sprintf("%.0f", $res_x * 25.4 / $size_x) : ''; + $diagonal = ($res_x && $size_x) ? sprintf("%.1f", (sqrt($size_x**2 + $size_y**2)/25.4)) : ''; + $diagonal += 0 if $diagonal; # trick to get rid of decimal 0 + $diagonal_m = ($res_x && $size_x) ? sprintf("%.0f", (sqrt($size_x**2 + $size_y**2))) : ''; + undef $primary; + push(@ids,$monitor_id); + if ($set_as){ + $primary = $monitor_id; + $set_as =~ s/\s$//; + } + $monitors{$monitor_id} = { + 'screen' => $screen_id, + 'monitor' => $monitor_id, + 'pos-x' => $pos_x, + 'pos-y' => $pos_y, + 'primary' => $primary, + 'res-x' => $res_x, + 'res-y' => $res_y, + 'size-x' => $size_x, + 'size-x-i' => $size_x_i, + 'size-y' => $size_y, + 'size-y-i' => $size_y_i, + 'dpi' => $dpi, + 'diagonal' => $diagonal, + 'diagonal-m' => $diagonal_m, + 'position' => $set_as, + }; + # print "x:$size_x y:$size_y rx:$res_x ry:$res_y dpi:$dpi\n"; + ($res_x,$res_y,$size_x,$size_x_i,$size_y,$size_y_i,$set_as) = (0,0,0,0,0,0,0,0,undef); + } + my @working = split(/\s+/,$_); + # this is the monitor current dimensions + if ($working[1] =~ /\*/){ + $working[1] =~ s/\*|\+//g; + $working[1] = sprintf("%.0f",$working[1]); + if ($monitor_id && %monitors){ + $monitors{$monitor_id}->{'hz'} = $working[1]; + } + ($diagonal,$dpi) = ('',''); + # print Data::Dumper::Dumper \@monitors; + } + } + if (%monitors){ + push(@xrandr_screens,\%monitors); + } + my $i = 0; + my $layouts; + if (!defined $graphics{'display-screens'} && $graphics{'screens'}){ + $graphics{'display-screens'} = scalar @{$graphics{'screens'}}; + } + map_monitor_ids(\@ids) if @ids; + foreach my $main (@{$graphics{'screens'}}){ + # print "h: " . Data::Dumper::Dumper $main; + # print "h: " . Data::Dumper::Dumper @xrandr_screens; + # print $main->{'screen'}, "\n"; + foreach my $x_screen (@xrandr_screens){ + # print "d: " . Data::Dumper::Dumper $x_screen; + my @keys = sort keys %$x_screen; + if ($x_screen->{$keys[0]}{'screen'} eq $main->{'screen'} && + !defined $graphics{'screens'}->[$i]{'monitors'}){ + $graphics{'screens'}->[$i]{'monitors'} = $x_screen; + } + if ($extra > 1){ + if (!$layouts){ + $layouts = []; + set_monitor_layouts($layouts); + } + advanced_monitor_data($x_screen,$layouts); + } + if (!defined $main->{'size-x'}){ + $graphics{'screens'}->[$i]{'size-missing'} = main::message('tool-missing-basic','xdpyinfo'); } } + $i++; } + undef $layouts; + # print "xrand: " . Data::Dumper::Dumper \@xrandr_screens; + print 'Data: xrandr: ', Data::Dumper::Dumper $graphics{'screens'} if $dbg[17]; + main::log_data('dump','$graphics{screens}',$graphics{'screens'}) if $b_log; eval $end if $b_log; - return $tty; } -sub x_drivers { +# case where no xpdyinfo display server/version data exists, or to set Wayland +# Xwayland version, or Xvesa data. +sub display_server_data { + eval $start if $b_log; + my ($program); + # load the extra X paths, it's important that these are first, because + # later Xorg versions show error if run in console or ssh if the true path + # is not used. + @paths = (qw(/usr/lib /usr/lib/xorg /usr/lib/xorg-server /usr/libexec /usr/X11R6/bin), @paths); + my (@data,$server,$version); + if (!$graphics{'x-server'} || !$graphics{'x-server'}->[0][1]){ + # IMPORTANT: both commands send version data to stderr! + if ($program = main::check_program('Xorg')){ + @data = main::grabber("$program -version 2>&1",'','strip'); + $server = 'X.org'; + } + elsif ($program = main::check_program('X')){ + @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'); + } + } + # print join('^ ', @paths), " :: $program\n"; + # print Data::Dumper::Dumper \@data; + if ($data[0]){ + if ($data[0] =~ /X.org X server (\S+)/i){ + $version = $1; + } + elsif ($data[0] =~ /XFree86 Version (\S+)/i){ + $version = $1; + $server = 'XFree86'; + } + 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; + } + if ((!$b_display || $graphics{'protocol'} eq 'wayland') && + ($program = main::check_program('Xwayland'))){ + undef $version; + @data = main::grabber("$program -version 2>&1",'','strip'); + # Slackware Linux Project Xwayland Version 21.1.4 (12101004) + # The X.Org Foundation Xwayland Version 21.1.4 (12101004) + if (@data){ + $data[0] =~ /Xwayland Version (\S+)/; + $version = $1; + } + $graphics{'x-server'} = [] if !$graphics{'x-server'}; + push(@{$graphics{'x-server'}},['Xwayland',$version]); + } + # remove extra X paths from global @paths + @paths = grep { !/^\/usr\/lib|xorg|X11R6|libexec/ } @paths; + eval $end if $b_log; +} +# for wayland display/monitor drivers, or if no display drivers found for x +sub gpu_drivers_sys { + eval $start if $b_log; + my ($id) = @_; + my ($driver,@drivers); + # we only want list of drivers for cards with a connected monitor, and inactive + # ports are already removed by the 'all' stage. + foreach my $port (keys %{$monitor_ids}){ + if (!$monitor_ids->{$port}{'drivers'} || + ($id ne 'all' && $id ne $port) || + !$monitor_ids->{$port}{'status'} || + $monitor_ids->{$port}{'status'} ne 'connected'){ + next; + } + else { + foreach $driver (@{$monitor_ids->{$port}{'drivers'}}){ + push(@drivers,$driver); + } + } + } + if (@drivers){ + @drivers = sort(@drivers); + main::uniq(\@drivers); + } + eval $end if $b_log; + @drivers ? return \@drivers : return; +} +sub display_drivers_x { eval $start if $b_log; my ($driver,@driver_data,,%drivers); my ($alternate,$failed,$loaded,$sep,$unloaded) = ('','','','',''); @@ -14048,13 +15047,12 @@ sub x_drivers { # list is from sgfxi plus non-free drivers, plus ARM drivers my $list = join('|', qw(amdgpu apm ark armsoc atimisc ati chips cirrus cyrix fbdev fbturbo fglrx geode glide glint - i128 i740 i810-dec100 i810e i810 i815 i830 i845 i855 i865 i915 i945 - i965 iftv imstt intel ivtv mach64 mesa mga modesetting neomagic newport - nouveau nsc nvidia nv openchrome r128 radeonhd radeon - rendition s3virge s3 savage siliconmotion sisimedia sisusb sis - sunbw2 suncg14 suncg3 suncg6 sunffb sunleo suntcx - tdfx tga trident tseng unichrome v4l vboxvideo vesa vga via vmware vmwgfx - voodoo)); + i128 i740 i810-dec100 i810e i810 i815 i830 i845 i855 i865 i915 i945 i965 + iftv imstt intel ivtv mach64 mesa mga modesetting neomagic newport + nouveau nsc nvidia nv openchrome r128 radeonhd radeon rendition + s3virge s3 savage siliconmotion sisimedia sisusb sis + sunbw2 suncg14 suncg3 suncg6 sunffb sunleo suntcx tdfx tga trident tseng + unichrome v4l vboxvideo vesa vga via vmware vmwgfx voodoo)); # it's much cheaper to grab the simple pattern match then do the expensive one # in the main loop. # @xorg = grep {/Failed|Unload|Loading/} @xorg; @@ -14124,123 +15122,433 @@ sub x_drivers { $alternate .= $sep . $_; } } - @driver_data = ($loaded,$unloaded,$failed,$alternate); + if ($loaded || $unloaded || $failed || $alternate){ + @driver_data = ($loaded,$unloaded,$failed,$alternate); + } } eval $end if $b_log; - return @driver_data; + @driver_data ? return \@driver_data : return; } -# fallback if no glx x version data found -sub x_version { +sub display_protocol { eval $start if $b_log; - my ($version,@data,$program); - # load the extra X paths, it's important that these are first, because - # later Xorg versions show error if run in console or ssh if the true path - # is not used. - @paths = (qw(/usr/lib /usr/lib/xorg /usr/lib/xorg-server /usr/libexec /usr/X11R6/bin), @paths); - # IMPORTANT: both commands send version data to stderr! - if ($program = main::check_program('Xorg')){ - @data = main::grabber("$program -version 2>&1"); + $graphics{'protocol'} = ''; + if ($ENV{'XDG_SESSION_TYPE'}){ + $graphics{'protocol'} = $ENV{'XDG_SESSION_TYPE'}; } - elsif ($program = main::check_program('X')){ - @data = main::grabber("$program -version 2>&1"); + if (!$graphics{'protocol'} && $ENV{'WAYLAND_DISPLAY'}){ + $graphics{'protocol'} = $ENV{'WAYLAND_DISPLAY'}; } - elsif ($program = main::check_program('Xvesa')){ - @data = main::grabber("$program -version 2>&1"); + # can show as wayland-0 + if ($graphics{'protocol'} && $graphics{'protocol'} =~ /wayland/i){ + $graphics{'protocol'} = 'wayland'; } - # print join('^ ', @paths), " :: $program\n"; - # print Data::Dumper::Dumper \@data; - if (@data){ - foreach (@data){ - if (/^X.org X server/i){ - $version = (split(/\s+/, $_))[3]; - last; + # yes, I've seen this in 2019 distros, sigh + elsif ($graphics{'protocol'} eq 'tty'){ + $graphics{'protocol'} = ''; + } + # need to confirm that there's a point to this test, I believe no, fails out of x + # loginctl also results in the session id + if (!$graphics{'protocol'} && $b_display && $force{'display'}){ + if (my $program = main::check_program('loginctl')){ + my $id = ''; + # $id = $ENV{'XDG_SESSION_ID'}; # returns tty session in console + my @data = main::grabber("$program --no-pager --no-legend 2>/dev/null",'','strip'); + foreach (@data){ + next if /tty[v]?[0-6]$/; # freebsd: ttyv3 + $id = (split(/\s+/, $_))[0]; + last; # multiuser? too bad, we'll go for the first one } - elsif (/^X Window System Version/i){ - $version = (split(/\s+/, $_))[4]; - last; + if ($id){ + my $temp = (main::grabber("$program show-session $id -p Type --no-pager --no-legend 2>/dev/null"))[0]; + $temp =~ s/Type=// if $temp; + # ssh will not show /dev/ttyx so would have passed the first test + $graphics{'protocol'} = $temp if $temp && $temp ne 'tty'; } - elsif (/^Xvesa from/i){ - $version = (split(/\s+/, $_))[3]; - $version = "Xvesa $version" if $version; - last; + } + } + $graphics{'protocol'} = lc($graphics{'protocol'}) if $graphics{'protocol'}; + eval $end if $b_log; +} + +## MONITOR DATA ## +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}'; + my @ports_glob = main::globber($pattern); + # print Data::Dumper::Dumper \@cards_glob; + # print Data::Dumper::Dumper \@ports_glob; + my ($card,%cards,@data,$file,$item,$path,$port); + foreach $file (@cards_glob){ + next if ! -e $file; + if ($file =~ m|^/sys/class/drm/(card\d+)/.+?/drivers/(\S+):(\S+)$|){ + push(@{$cards{$1}},[$2,$3]); + } + } + # print Data::Dumper::Dumper \%cards; + foreach $file (sort @ports_glob){ + next if ! -r $file; + $item = $file; + $item =~ s|(/.*/(card\d+)-([^/]+))/(.+)||; + $path = $1; + $card = $2; + $port = $3; + $item = $4; + next if !$1; + $monitor_ids = {} if !$monitor_ids; + $monitor_ids->{$port}{'monitor'} = $port; + if (!$monitor_ids->{$port}{'drivers'} && $cards{$card}){ + foreach my $info (@{$cards{$card}}){ + push(@{$monitor_ids->{$port}{'drivers'}},$info->[1]); + } + } + $monitor_ids->{$port}{'path'} = readlink($path); + $monitor_ids->{$port}{'path'} =~ s|^\.\./\.\.|/sys|; + if ($item eq 'status' || $item eq 'enabled'){ + # print "$file\n"; + $monitor_ids->{$port}{$item} = main::reader($file,'strip',0); + } + # arm: U:1680x1050p-0 + elsif ($item eq 'modes'){ + @data = main::reader($file,'strip'); + next if !@data; + if (scalar @data == 1 || $data[-1] eq $data[0]){ + $monitor_ids->{$port}{'modes-min-max'} = $data[0]; + } + else { + $monitor_ids->{$port}{'modes-min'} = $data[-1]; + $monitor_ids->{$port}{'modes-max'} = $data[0]; + } + } + elsif ($item eq 'edid'){ + next if -s $file; + monitor_edid_data($file,$port); + } + } + main::log_data('dump','$ports ref',$monitor_ids) if $b_log; + print Data::Dumper::Dumper $monitor_ids if $dbg[44]; + eval $end if $b_log; +} +sub monitor_edid_data { + eval $start if $b_log; + my ($file,$port) = @_; + my (@data); + open my $fh, '<:raw', $file or return; # it failed, give up, we don't care why + my $edid_raw = do { local $/; <$fh> }; + return if !$edid_raw; + my $edid = ParseEDID::parse_edid($edid_raw,$dbg[47]); + main::log_data('dump','Parse::EDID',$edid) if $b_log; + print Data::Dumper::Dumper $edid if $dbg[44]; + return if !$edid || ref $edid ne 'HASH' || !%$edid; + $monitor_ids->{$port}{'build-date'} = $edid->{'year'}; + if ($edid->{'gamma'}){ + $monitor_ids->{$port}{'gamma'} = ($edid->{'gamma'}/100 + 0); + } + if ($edid->{'monitor_name'} || $edid->{'manufacturer_name_nice'}){ + my $model = ''; + if ($edid->{'manufacturer_name_nice'}){ + $model = $edid->{'manufacturer_name_nice'}; + } + if ($edid->{'monitor_name'}){ + $model .= ' ' if $model; + $model .= $edid->{'monitor_name'}; + } + $monitor_ids->{$port}{'model'} = main::remove_duplicates(main::clean($model)); + } + if ($edid->{'diagonal_size'}){ + $monitor_ids->{$port}{'diagonal-m'} = sprintf('%.0f',($edid->{'diagonal_size'}*25.4)) + 0; + $monitor_ids->{$port}{'diagonal'} = sprintf('%.1f',$edid->{'diagonal_size'}) + 0; + } + if ($edid->{'ratio_name'}){ + $edid->{'ratio_name'} =~ s|/|:|; # this should be changed in ParseEDID + $monitor_ids->{$port}{'ratio'} = $edid->{'ratio_name'}; + } + 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_image_size'}){ + $monitor_ids->{$port}{'size-x'} = $edid->{'detailed_timings'}[0]{'horizontal_image_size'}; + $monitor_ids->{$port}{'size-x-i'} = sprintf('%.1f',($edid->{'detailed_timings'}[0]{'horizontal_image_size'}/25.4)) + 0; + } + if ($edid->{'detailed_timings'}[0]{'vertical_image_size'}){ + $monitor_ids->{$port}{'size-y'} = $edid->{'detailed_timings'}[0]{'vertical_image_size'}; + $monitor_ids->{$port}{'size-y-i'} = sprintf('%.1f',($edid->{'detailed_timings'}[0]{'vertical_image_size'}/25.4)) + 0; + } + if ($edid->{'detailed_timings'}[0]{'horizontal_dpi'}){ + $monitor_ids->{$port}{'dpi'} = sprintf('%.0f',$edid->{'detailed_timings'}[0]{'horizontal_dpi'}) + 0; + } + } + if ($edid->{'serial_number'} || $edid->{'serial_number2'}){ + # this looks much more like a real serial than the default: serial_number + if ($edid->{'serial_number2'} && @{$edid->{'serial_number2'}}){ + $monitor_ids->{$port}{'serial'} = main::clean_dmi($edid->{'serial_number2'}[0]); + } + elsif ($edid->{'serial_number'}){ + $monitor_ids->{$port}{'serial'} = main::clean_dmi($edid->{'serial_number'}); + } + } + eval $end if $b_log; +} +sub advanced_monitor_data { + eval $start if $b_log; + my ($monitors,$layouts) = @_; + my (@horiz,@vert); + my $position = ''; + # then see if we can locate a default position primary monitor + foreach my $key (keys %$monitors){ + next if !defined $monitors->{$key}{'pos-x'}; + # this is the only scenario we can guess at if no primary detected + if (!$monitors->{$key}{'primary'} && + $monitors->{$key}{'pos-x'} == 0 && $monitors->{$key}{'pos-y'} == 0){ + $monitors->{$key}{'position'} = 'primary'; + $monitors->{$key}{'primary'} = $monitors->{$key}{'monitor'}; + } + if (!grep {$monitors->{$key}{'pos-x'} == $_} @horiz){ + push(@horiz,$monitors->{$key}{'pos-x'}); + } + if (!grep {$monitors->{$key}{'pos-y'} == $_} @vert){ + push(@vert,$monitors->{$key}{'pos-y'}); + } + } + @horiz = sort(@horiz); + @vert = sort(@vert); + my ($h,$v) = (scalar(@horiz),scalar(@vert)); + # print Data::Dumper::Dumper \@horiz; + # print Data::Dumper::Dumper \@vert; + # print Data::Dumper::Dumper $layouts; + # print Data::Dumper::Dumper $monitor_map; + foreach my $key (keys %$monitors){ + if (@horiz && @vert){ + $monitors->{$key}{'position'} ||= ''; + $position = ''; + $position = get_monitor_position($monitors->{$key},\@horiz,\@vert); + $position = $layouts->[$v][$h]{$position} if $layouts->[$v][$h]{$position}; + $monitors->{$key}{'position'} .= ',' if $monitors->{$key}{'position'}; + $monitors->{$key}{'position'} .= $position; + } + my $mon_mapped = ($monitor_map) ? $monitor_map->{$monitors->{$key}{'monitor'}} : undef; + # these are already set for monitor_ids, only need this for Xorg data. + if ($mon_mapped && $monitor_ids->{$mon_mapped}){ + # note: xorg drivers can be different than gpu drivers + $monitors->{$key}{'drivers'} = gpu_drivers_sys($mon_mapped); + $monitors->{$key}{'build-date'} = $monitor_ids->{$mon_mapped}{'build-date'}; + $monitors->{$key}{'diagonal'} = $monitor_ids->{$mon_mapped}{'diagonal'}; + $monitors->{$key}{'diagonal-m'} = $monitor_ids->{$mon_mapped}{'diagonal-m'}; + $monitors->{$key}{'gamma'} = $monitor_ids->{$mon_mapped}{'gamma'}; + $monitors->{$key}{'modes-min-max'} = $monitor_ids->{$mon_mapped}{'modes-min-max'}; + $monitors->{$key}{'modes-max'} = $monitor_ids->{$mon_mapped}{'modes-max'}; + $monitors->{$key}{'modes-min'} = $monitor_ids->{$mon_mapped}{'modes-min'}; + $monitors->{$key}{'model'} = $monitor_ids->{$mon_mapped}{'model'}; + $monitors->{$key}{'ratio'} = $monitor_ids->{$mon_mapped}{'ratio'}; + $monitors->{$key}{'serial'} = $monitor_ids->{$mon_mapped}{'serial'}; + if ($mon_mapped ne $monitors->{$key}{'monitor'}){ + $monitors->{$key}{'monitor-mapped'} = $mon_mapped; + } + } + } + # not printing out primary if Screen has only 1 Monitor + if (scalar keys %$monitors == 1){ + my @keys = keys %$monitors; + $monitors->{$keys[0]}{'position'} = undef; + } + print Data::Dumper::Dumper $monitors if $dbg[45]; + eval $end if $b_log; +} +# clear out all disabled or not connected monitor ports +sub set_active_monitors { + eval $start if $b_log; + foreach my $key (keys %$monitor_ids){ + if (!$monitor_ids->{$key}{'enabled'} || + $monitor_ids->{$key}{'enabled'} ne 'enabled' || + !$monitor_ids->{$key}{'status'} || + $monitor_ids->{$key}{'status'} ne 'connected'){ + delete $monitor_ids->{$key}; + } + } + # print 'active monitors: ', Data::Dumper::Dumper $monitor_ids; + eval $end if $b_log; +} +sub get_monitor_position { + eval $start if $b_log; + my ($monitor,$horiz,$vert) = @_; + my ($i,$position) = (1,''); + foreach (@$vert){ + if ($_ == $monitor->{'pos-y'}){ + $position = $i . '-'; + last; + } + $i++; + } + $i = 1; + foreach (@$horiz){ + if ($_ == $monitor->{'pos-x'}){ + $position .= $i; + last; + } + $i++; + } + main::log_data('data','pos-raw: ' . $position) if $b_log; + eval $end if $b_log; + return $position; +} +sub set_monitor_layouts { + my ($layouts) = @_; + $layouts->[1][2] = {'1-1' => 'left','1-2' => 'right'}; + $layouts->[1][3] = {'1-1' => 'left','1-2' => 'center','1-3' => 'right'}; + $layouts->[1][4] = {'1-1' => 'left','1-2' => 'center-l','1-3' => 'center-r', + '1-4' => 'right'}; + $layouts->[2][1] = {'1-1' => 'top','2-1' => 'bottom'}; + $layouts->[2][2] = {'1-1' => 'top-left','1-2' => 'top-right', + '2-1' => 'bottom-l','2-2' => 'bottom-r'}; + $layouts->[2][3] = {'1-1' => 'top-left','1-2' => 'top-center','1-3' => 'top-right', + '2-1' => 'bottom-l','2-2' => 'bottom-c','2-3' => 'bottom-r'}; + $layouts->[3][1] = {'1-1' => 'top','2-1' => 'middle','3-1' => 'bottom'}; + $layouts->[3][2] = {'1-1' => 'top-left','1-2' => 'top-right', + '2-1' => 'middle-l','2-2' => 'middle-r', + '3-1' => 'bottom-l','3-2' => 'bottom-r'}; + $layouts->[3][3] = {'1-1' => 'top-left','1-2' => 'top-center',,'1-3' => 'top-right', + '2-1' => 'middle-l','2-2' => 'middle-c','2-3' => 'middle-r', + '3-1' => 'bottom-l','3-2' => 'bottom-c','3-3' => 'bottom-r'}; +} +# this is required to resolve the insane situation where some xorg drivers change +# the kernel ID for the port to something slightly different, amdgpu in particular. +sub map_monitor_ids { + eval $start if $b_log; + my ($display_ids) = @_; + return if !$monitor_ids; + @$display_ids = sort { lc($a) cmp lc($b) } @$display_ids; + my @sys_ids; + foreach my $key (keys %$monitor_ids){ + if ($monitor_ids->{$key}{'status'} eq 'connected' && + $monitor_ids->{$key}{'enabled'} eq 'enabled'){ + push(@sys_ids,$key); + } + } + @sys_ids = sort { lc($a) cmp lc($b) } @sys_ids; + # @sys_ids = ('DP-1-1','DVI-I-1','VGA-1'); + main::log_data('dump','@sys_ids',\@sys_ids) if $b_log; + main::log_data('dump','$xrandr_ids ref',$display_ids) if $b_log; + 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; + $monitor_map = {}; + # known patterns: s: DP-1, d: DisplayPort-0; s: HDMI-A-2, d: HDMI-A-1 + # s: HDMI-A-2, d: HDMI-2; s: DVI-1 d: DVI1; s: HDMI-1, d: HDMI1 + # s: DVI-I-1, d: DVI0; s: VGA-1, d: VGA1; s: DP-1-1; d: DP-1-1 + my ($d_1,$d_2,$d_3,$d_4,$s_1,$s_2,$s_3,$s_4); + for (my $i=0; $i < scalar @$display_ids; $i++){ + print "s: $sys_ids[$i] x: $display_ids->[$i]\n" if $dbg[45]; + if ($display_ids->[$i] =~ /^([A-Z]+)(-[AB]|-[ADI]|-[ADI]-\d+?|-\d+?)?(-)?(\d+)$/i){ + $d_1 = $1; + $d_2 = ($2) ? $2 : ''; + $d_3 = ($3) ? $3 : ''; + $d_4 = $4; + $d_1 =~ s/^DisplayPort/DP/i; # amdgpu... + print " d1: $d_1 d2: $d_2 d3: $d_3 d4: $d_4\n" if $dbg[45]; + if ($sys_ids[$i] =~ /^([A-Z]+?)(-[AB]|-[ADI]|-[ADI]-\d+?|-\d+?)?(-)?(\d+)$/i){ + $s_1 = $1; + $s_2 = ($2) ? $2 : ''; + $s_3 = ($3) ? $3 : ''; + $s_4 = $4; + $d_1 = $s_1 if uc($d_1) eq 'XWAYLAND'; + print " d1: $d_1 s1: $s_1 s2: $s_2 s3: $s_3 s4: $s_4\n" if $dbg[45]; + if ($d_1 eq $s_1 && ($d_4 == $s_4 || $d_4 == ($s_4 - 1))){ + $monitor_map->{$display_ids->[$i]} = $sys_ids[$i]; + } + } + } + if (!$monitor_map->{$display_ids->[$i]}){ + $monitor_map->{$display_ids->[$i]} = main::message('monitor-id'); + } + } + main::log_data('dump','$monitor_map ref',$monitor_map) if $b_log; + print Data::Dumper::Dumper $monitor_map if $dbg[45]; + eval $end if $b_log; +} +# handle case of monitor on left or right edge, vertical that is. +# mm dimensiions are based on the default position of monitor as sold. +# very old systems may not have non 0 value for size x or y +# size, res x,y by reference +sub flip_size_x_y { + eval $start if $b_log; + my ($size_x,$size_y,$res_x,$res_y) = @_; + if ((($$res_x/$$res_y > 1 && $$size_x/$$size_y < 1) || + ($$res_x/$$res_y < 1 && $$size_x/$$size_y > 1))){ + ($$size_x,$$size_y) = ($$size_y,$$size_x); + } + eval $end if $b_log; +} +## COMPOSITOR DATA ## +sub set_compositor_data { + eval $start if $b_log; + if (my $compositors = get_compositors()){ + my @data; + foreach my $compositor (@$compositors){ + # gnome-shell is incredibly slow to return version + if (($extra > 1 || $graphics{'protocol'} eq 'wayland') && + (!$show{'system'} || $compositor ne 'gnome-shell')){ + $graphics{'compositors'} = [] if !$graphics{'compositors'}; + push(@{$graphics{'compositors'}},[main::program_data($compositor,$compositor)]); + } + else { + $graphics{'compositors'} = [] if !$graphics{'compositors'}; + push(@{$graphics{'compositors'}},[(main::program_values($compositor))[3]]); } } } - # remove extra X paths - @paths = grep { !/^\/usr\/lib|xorg|X11R6|libexec/ } @paths; eval $end if $b_log; - return $version; } -# $1 - protocol: wayland|x11 -sub display_compositor { +sub get_compositors { eval $start if $b_log; - my ($protocol) = @_; - my ($compositor) = (''); + my @found; main::set_ps_gui() if !$loaded{'ps-gui'}; if (@ps_gui){ - # 1 check program; 2 search; 3 unused version; 4 print - my @compositors = ( - ['asc','asc','','asc'], - ['budgie-wm','budgie-wm','','budgie-wm'], - # owned by: compiz-core in debian - ['compiz','compiz','','compiz'], - ['compton','compton','','compton'], - # as of version 20 is wayland compositor - ['enlightenment','enlightenment','','enlightenment'], - ['gnome-shell','gnome-shell','','gnome-shell'], - ['kwin_wayland','kwin_wayland','','kwin_wayland'], - ['kwin_x11','kwin_x11','','kwin_x11'], - # ['kwin','kwin','','kwin'], - ['marco','marco','','marco'], - ['muffin','muffin','','muffin'], - ['mutter','mutter','','mutter'], - ['weston','weston','','weston'], - # these are more obscure, so check for them last - ['3dwm','3dwm','','3dwm'], - ['dcompmgr','dcompmgr','','dcompmgr'], - ['dwc','dwc','','dwc'], - ['fireplace','fireplace','','fireplace'], - ['grefson','grefson','','grefson'], - ['kmscon','kmscon','','kmscon'], - ['liri','liri','','liri'], - ['metisse','metisse','','metisse'], - ['mir','mir','','mir'], - ['moblin','moblin','','moblin'], - ['motorcar','motorcar','','motorcar'], - ['monsterwm','monsterwm','','monsterwm'], - ['orbital','orbital','','orbital'], - ['papyros','papyros','','papyros'], - ['perceptia','perceptia','','perceptia'], - ['picom','picom','','picom'], - ['rustland','rustland','','rustland'], - ['sommelier','sommelier','','sommelier'], - ['sway','sway','','sway'], - ['swc','swc','','swc'], - ['ukwm','ukwm','','ukwm'], - ['unagi','unagi','','unagi'], - ['unity-system-compositor','unity-system-compositor','','unity-system-compositor'], - ['way-cooler','way-cooler','','way-cooler'], - ['wavy','wavy','','wavy'], - ['wayfire','wayfire','','wayfire'], - ['wayhouse','wayhouse','','wayhouse'], - ['westford','westford','','westford'], - ['xcompmgr','xcompmgr','','xcompmgr'], - ['xfwm4','xfwm4','','xfwm4'], - ['xfwm5','xfwm5','','xfwm5'], - ['xfwm','xfwm','','xfwm'], - ); - foreach my $item (@compositors){ - # no need to use check program with short list of ps_gui - # if (main::check_program($item[0]) && (grep {/^$item[1]$/} @ps_gui)){ - if (grep {/^$item->[1]$/} @ps_gui){ - $compositor = $item->[3]; - last; + # ORDER MATTES! + # notes: compiz: debian package compiz-core; + # enlightenment: as of version 20 wayland compositor + my @compositors = qw(budgie-wm compiz compton enlightenment gnome-shell + kwin_wayland kwin_x11 kwinft marco muffin mutter); + # these are more obscure, so check for them after primary common ones + push (@compositors,qw(3dwm dcompmgr gala kmscon metisse mir moblin + monsterwm picom ukwm unagi unity-system-compositor xcompmgr xfwm4 + xfwm5 xfwm)); + my $matches = join('|',@compositors) . $wl_compositors; + foreach my $psg (@ps_gui){ + if ($psg =~ /^($matches)$/){ + push(@found,$1); + } + } + } + main::log_data('dump','compositors:', \@found) if $b_log; + eval $end if $b_log; + (@found) ? return \@found : return; +} + +## UTILITIES ## +sub tty_data(){ + eval $start if $b_log; + my ($tty); + if ($size{'term-cols'}){ + $tty = "$size{'term-cols'}x$size{'term-lines'}"; + } + # this is broken + elsif ($b_irc && $client{'console-irc'}){ + ShellData::console_irc_tty() if !$loaded{'con-irc-tty'}; + my $tty_working = $client{'con-irc-tty'}; + if ($tty_working ne '' && (my $program = main::check_program('stty'))){ + my $tty_arg = ($bsd_type) ? '-f' : '-F'; + # handle vtnr integers, and tty ID with letters etc. + $tty_working = "tty$tty_working" if -e "/dev/tty$tty_working"; + $tty = (main::grabber("$program $tty_arg /dev/$tty_working size 2>/dev/null"))[0]; + if ($tty){ + my @temp = split(/\s+/, $tty); + $tty = "$temp[1]x$temp[0]"; } } } - main::log_data('data',"compositor: $compositor") if $b_log; eval $end if $b_log; - return $compositor; + return $tty; } } @@ -14281,7 +15589,7 @@ sub get { },); } elsif (@lsblk && !$use{'logical-lvm'} && ($alerts{'lvs'}->{'action'} eq 'permissions' || - $alerts{'lvs'}->{'action'} eq 'missing')){ + $alerts{'lvs'}->{'action'} eq 'missing')){ my $key = 'Message'; push(@rows, { main::key($num++,0,1,$key) => main::message('logical-data',''), @@ -14445,9 +15753,9 @@ sub general_data { %parent = LsblkData::get($row->{'parent'}); next if !$parent{'fs'}; if ($row->{'type'} && (($row->{'type'} eq 'crypt' || - $row->{'type'} eq 'mpath' || $row->{'type'} eq 'multipath') || - ($row->{'type'} eq 'dm' && $row->{'name'} =~ /veracrypt/i) || - ($parent{'fs'} eq 'bcache'))){ + $row->{'type'} eq 'mpath' || $row->{'type'} eq 'multipath') || + ($row->{'type'} eq 'dm' && $row->{'name'} =~ /veracrypt/i) || + ($parent{'fs'} eq 'bcache'))){ my (@full_components,$mapped,$type); $mapped = $mapper{$row->{'name'}} if %mapper; next if grep(/^$row->{'name'}$/, @found); @@ -14656,6 +15964,18 @@ sub get { } } } + elsif ($fake{'elbrus'} || $cpu_arch eq 'elbrus'){ + if ($fake{'elbrus'} || (my $program = main::check_program('fruid_print'))){ + %data = machine_data_fruid($program); + } + if (%data){ + @rows = machine_output(\%data); + } + elsif (!$key1){ + $key1 = 'Message'; + $val1 = main::message('machine-data-fruid'); + } + } elsif (!$bsd_type){ # this uses /proc/cpuinfo so only GNU/Linux if (%risc){ @@ -14696,8 +16016,9 @@ sub machine_output { # print "$key: $data->{$key}\n"; # } if (!$data->{'sys_vendor'} || - ($data->{'board_vendor'} && $data->{'sys_vendor'} eq $data->{'board_vendor'} && - !$data->{'product_name'} && !$data->{'product_version'} && !$data->{'product_serial'})){ + ($data->{'board_vendor'} && $data->{'sys_vendor'} eq $data->{'board_vendor'} && + !$data->{'product_name'} && !$data->{'product_version'} && + !$data->{'product_serial'})){ $b_skip_system = 1; } # The goal here is to not show laptop/mobile devices @@ -14708,11 +16029,11 @@ sub machine_output { # in case where the vendor is the same and the version is the same and not null, # otherwise the version information is going to be different in all cases I think if (($data->{'sys_vendor'} && $data->{'board_vendor'} && - $data->{'sys_vendor'} eq $data->{'board_vendor'}) && - (($data->{'product_version'} && $data->{'board_version'} && - $data->{'product_version'} eq $data->{'board_version'}) || - (!$data->{'product_version'} && $data->{'product_name'} && $data->{'board_name'} && - $data->{'product_name'} eq $data->{'board_name'}))){ + $data->{'sys_vendor'} eq $data->{'board_vendor'}) && + (($data->{'product_version'} && $data->{'board_version'} && + $data->{'product_version'} eq $data->{'board_version'}) || + (!$data->{'product_version'} && $data->{'product_name'} && $data->{'board_name'} && + $data->{'product_name'} eq $data->{'board_name'}))){ $b_skip_system = 1; } } @@ -14797,6 +16118,9 @@ sub machine_output { if ($extra > 2 && $data->{'board_uuid'}){ $rows[$j]->{main::key($num++,0,3,'uuid')} = $data->{'board_uuid'}; } + if ($extra > 1 && $data->{'board_mfg_date'}){ + $rows[$j]->{main::key($num++,0,3,'mfg-date')} = $data->{'board_mfg_date'}; + } $rows[$j]->{main::key($num++,1,1,$firmware)} = $bios_vendor; $rows[$j]->{main::key($num++,0,2,'v')} = $bios_version; if ($bios_rev){ @@ -14846,7 +16170,48 @@ sub machine_soc_output { eval $end if $b_log; return @rows; } - +sub machine_data_fruid { + eval $start if $b_log; + my ($program) = @_; + my ($b_start,%data,@fruid); + if (!$fake{'elbrus'}){ + @fruid = main::grabber("$program 2>/dev/null",'','strip'); + } + else { + # my $file; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/fruid/fruid-e904-1_full.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/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; + my @split = split(/\s*:\s+/,$_,2); + if ($split[0] eq 'Mfg. Date/Time'){ + $data{'board_mfg_date'} = $split[1]; + $data{'board_mfg_date'} =~ s/^(\d+:\d+)\s//; + } + elsif ($split[0] eq 'Board manufacturer'){ + $data{'board_vendor'} = $split[1]; + } + elsif ($split[0] eq 'Board part number'){ + $data{'board_part_nu'} = $split[1]; + } + elsif ($split[0] eq 'Board product name'){ + $data{'board_name'} = $split[1]; + } + elsif ($split[0] eq 'Board serial number'){ + $data{'board_serial'} = $split[1]; + } + elsif ($split[0] eq 'Board product version'){ + $data{'board_version'} = $split[1]; + } + } + print Data::Dumper::Dumper \%data if $dbg[28]; + main::log_data('dump','%data',\%data) if $b_log; + return %data; +} sub machine_data_sys { eval $start if $b_log; my (%data,$path,$vm); @@ -15454,6 +16819,9 @@ sub device_output { $rows[$j]->{main::key($num++,0,3,'modules')} = $row->[10] if $row->[10]; } $row->[8] ||= 'N/A'; + if ($extra > 1 && $bus_id ne 'N/A'){ + main::get_pcie_data($bus_id,$j,\@rows,\$num); + } # as far as I know, wifi has no port, but in case it does in future, use it $rows[$j]->{main::key($num++,0,2,'port')} = $row->[8] if (!$b_wifi || ($b_wifi && $row->[8] ne 'N/A')); $rows[$j]->{main::key($num++,0,2,'bus-ID')} = $bus_id; @@ -16749,7 +18117,7 @@ sub swap_data { } sub swap_advanced_data { eval $start if $b_log; - my ($swappiness,$cache_pressure) = (undef,undef); + my ($swappiness,$cache_pressure) = (); if (-r '/proc/sys/vm/swappiness'){ $swappiness = main::reader('/proc/sys/vm/swappiness','',0); if (defined $swappiness){ @@ -18394,7 +19762,7 @@ sub check_zfs_status { ## RamItem { package RamItem; -my (@vendors,%vendor_ids); +my ($vendors,$vendor_ids); sub get { my (@data,@rows,$key1,@ram,$val1); my $num = 0; @@ -18436,6 +19804,7 @@ sub get { }); } push(@rows,@data); + ($vendors,$vendor_ids) = (); eval $end if $b_log; return @rows; } @@ -18511,7 +19880,7 @@ sub ram_output { $rows[$j]->{main::key($num++,0,3,'info')} = $mod->{'type'}; } if ($mod->{'speed'} && $mod->{'configured-clock-speed'} && - $mod->{'speed'} ne $mod->{'configured-clock-speed'}){ + $mod->{'speed'} ne $mod->{'configured-clock-speed'}){ $rows[$j]->{main::key($num++,1,3,'speed')} = ''; $rows[$j]->{main::key($num++,0,4,'spec')} = $mod->{'speed'}; $rows[$j]->{main::key($num++,0,4,'note')} = $mod->{'speed-note'} if $mod->{'speed-note'}; @@ -18801,9 +20170,9 @@ sub dmidecode_data { $part_number = $result[1] if $result[1]; } if ($vendor_id && !$manufacturer){ - set_vendor_ids() if !%vendor_ids; - if ($vendor_ids{$vendor_id}){ - $manufacturer = $vendor_ids{$vendor_id}; + set_vendor_ids() if !$vendor_ids; + if ($vendor_ids->{$vendor_id}){ + $manufacturer = $vendor_ids->{$vendor_id}; } } $ram[$handle]->{'derived-module-size'} = $derived_module_size; @@ -18959,7 +20328,7 @@ sub process_data { } # 2: now check to see if actually found module sizes are > than listed max module, replace if > if ($item->{'max-module-size'} && $item->{'derived-module-size'} && - $item->{'derived-module-size'} > $item->{'max-module-size'}){ + $item->{'derived-module-size'} > $item->{'max-module-size'}){ $item->{'max-module-size'} = $item->{'derived-module-size'}; $est_mod = $est; } @@ -18974,13 +20343,13 @@ sub process_data { if ($item->{'used-capacity'} && $item->{'max-capacity-16'}){ if ($item->{'used-capacity'} > $max_cap){ if ($item->{'max-module-size'} && - $item->{'used-capacity'} < ($item->{'slots-16'} * $item->{'max-module-size'})){ + $item->{'used-capacity'} < ($item->{'slots-16'} * $item->{'max-module-size'})){ $max_cap = $item->{'slots-16'} * $item->{'max-module-size'}; $est_cap = $est; print "A\n" if $b_debug; } elsif ($item->{'derived-module-size'} && - $item->{'used-capacity'} < ($item->{'slots-16'} * $item->{'derived-module-size'})){ + $item->{'used-capacity'} < ($item->{'slots-16'} * $item->{'derived-module-size'})){ $max_cap = $item->{'slots-16'} * $item->{'derived-module-size'}; $est_cap = $est; print "B\n" if $b_debug; @@ -18997,7 +20366,7 @@ sub process_data { if (!$est_cap){ # do not do this for only single modules found, max mod size can be equal to the array size if ($item->{'slots-16'} > 1 && $item->{'device-count-found'} > 1 && - $max_cap < ($item->{'derived-module-size'} * $item->{'slots-16'})){ + $max_cap < ($item->{'derived-module-size'} * $item->{'slots-16'})){ $max_cap = $item->{'derived-module-size'} * $item->{'slots-16'}; $est_cap = $est; print "D\n" if $b_debug; @@ -19010,9 +20379,9 @@ sub process_data { ## handle cases where we have type 5 data: mms x device count equals type 5 max cap # however do not use it if cap / devices equals the derived module size elsif ($item->{'max-module-size'} > 0 && - ($item->{'max-module-size'} * $item->{'slots-16'}) == $item->{'max-capacity-5'} && - $item->{'max-capacity-5'} != $item->{'max-capacity-16'} && - $item->{'derived-module-size'} != ($item->{'max-capacity-16'}/$item->{'slots-16'})){ + ($item->{'max-module-size'} * $item->{'slots-16'}) == $item->{'max-capacity-5'} && + $item->{'max-capacity-5'} != $item->{'max-capacity-16'} && + $item->{'derived-module-size'} != ($item->{'max-capacity-16'}/$item->{'slots-16'})){ $max_cap = $item->{'max-capacity-5'}; $est_cap = $est; print "F\n" if $b_debug; @@ -19192,7 +20561,7 @@ sub speed_mapper { return ($speeds{$type}) ? $speeds{$type} . ' MT/s' : $type; } sub set_vendors { - @vendors = ( + $vendors = [ # A-Data xpg: AX4U; AX\d{4} for axiom ['^(A[DX]\dU|AVD|A[\s-]?Data)','A[\s-]?Data','A-Data',''], ['^(A[\s-]?Tech)','A[\s-]?Tech','A-Tech',''], # don't know part nu @@ -19216,6 +20585,7 @@ sub set_vendors { # ['^(HYS]|Qimonda)','Qimonda','Qimonda',''], ['^(HY|Infineon)','Infineon','Infineon',''],#HY[A-Z]\d ['^(KSM|KVR|Kingston)','Kingston','Kingston',''], + ['^(LuminouTek)','LuminouTek','LuminouTek',''], ['^(MT|Micron)','Micron','Micron',''], # seen: 992069 991434 997110S ['^(M[BLERS][A-Z][1-7]|99[0-9]{3}|Mushkin)','Mushkin','Mushkin',''], @@ -19235,11 +20605,11 @@ sub set_vendors { ['^(TR\d|JM\d|Transcend)','Transcend','Transcend',''], ['^(VK\d|Vaseky)','Vaseky','Vaseky',''], ['^(Yangtze|Zhitai)','Yangtze(\s*Memory)?','Yangtze Memory',''], - ); + ]; } # note: many of these are pci ids, not confirmed valid for ram sub set_vendor_ids { - %vendor_ids = { + $vendor_ids = { '01f4' => 'Transcend',# confirmed '02fe' => 'Elpida',# confirmed '0314' => 'Mushkin',# confirmed @@ -19274,9 +20644,9 @@ sub set_vendor_ids { sub ram_vendor { eval $end if $b_log; my ($id) = $_[0]; - set_vendors() if !@vendors; + set_vendors() if !$vendors; my ($vendor,@data); - foreach my $row (@vendors){ + foreach my $row (@$vendors){ if ($id =~ /$row->[0]/i){ $vendor = $row->[2]; # Usually we want to assign N/A at output phase, maybe do this logic there? @@ -20145,8 +21515,8 @@ sub get { # we're allowing 1 or 2 ipmi tools, first the gnu one, then the # almost certain to be present in BSDs if ($fake{'ipmi'} || (main::globber('/dev/ipmi**') && - (($program = main::check_program('ipmi-sensors')) || - ($program = main::check_program('ipmitool'))))){ + (($program = main::check_program('ipmi-sensors')) || + ($program = main::check_program('ipmitool'))))){ if ($fake{'ipmi'} || $b_root){ %sensors = ipmi_data($program); @data = sensors_output('ipmi',\%sensors); @@ -20315,7 +21685,7 @@ sub sensors_output { my $gpu_unit = (defined $gpu[0]->{'temp-unit'}) ? " $gpu[0]->{'temp-unit'}" : ' C'; foreach my $info (@gpu){ # speed unit is either '' or % - my $gpu_fan = (defined $info->{'fan-speed'}) ? $info->{'fan-speed'} . $info->{'speed-unit'}: undef ; + my $gpu_fan = (defined $info->{'fan-speed'}) ? $info->{'fan-speed'} . $info->{'speed-unit'}: undef; my $gpu_type = $info->{'type'}; my $gpu_temp = (defined $info->{'temp'}) ? $info->{'temp'} . $gpu_unit: 'N/A'; $rows[$j]->{main::key($num++,1,2,'device')} = $gpu_type; @@ -20338,7 +21708,8 @@ sub sensors_output { } } if ($extra > 0 && ($source eq 'ipmi' || - ($sensors->{'volts-12'} || $sensors->{'volts-5'} || $sensors->{'volts-3.3'} || $sensors->{'volts-vbat'}))){ + ($sensors->{'volts-12'} || $sensors->{'volts-5'} || $sensors->{'volts-3.3'} || + $sensors->{'volts-vbat'}))){ $j = scalar @rows; $sensors->{'volts-12'} ||= 'N/A'; $sensors->{'volts-5'} ||= 'N/A'; @@ -20377,6 +21748,7 @@ sub ipmi_data { # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmitool-sensors-crazy-epyc-1.txt";$program='ipmitool'; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmitool-sensors-RK016013.txt";$program='ipmitool'; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmitool-sensors-freebsd-offsite-backup.txt"; + # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmitool-sensor-tyan-1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmi-sensors-crazy-epyc-1.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmi-sensors-lathander.txt"; # $file = "$ENV{'HOME'}/bin/scripts/inxi/data/ipmitool/ipmi-sensors-zwerg.txt"; @@ -20413,7 +21785,7 @@ sub ipmi_data { $working_unit =~ s/degrees\s// if $b_ipmitool; $sensors{'temp-unit'} = set_temp_unit($sensors{'temp-unit'},$working_unit) if $working_unit; } - elsif ($row[$i_key] =~ /^(Ambient)([\s_]Temp)?$/i){ + elsif ($row[$i_key] =~ /^(System\s)?(Ambient)([\s_]Temp)?$/i){ $sensors{'ambient-temp'} = int($row[$i_value]); $working_unit = $row[$i_unit]; $working_unit =~ s/degrees\s// if $b_ipmitool; @@ -20422,14 +21794,14 @@ sub ipmi_data { # Platform Control Hub (PCH), it is the X370 chip on the Crosshair VI Hero. # VRM: voltage regulator module # NOTE: CPU0_TEMP CPU1_TEMP is possible, unfortunately; CPU Temp Interf - elsif (!$sensors{'cpu-temp'} && $row[$i_key] =~ /^CPU([01])?([\s_]Temp)?$/i){ + elsif (!$sensors{'cpu-temp'} && $row[$i_key] =~ /^CPU([01])?([\s_](below[\s_]Tmax|Temp))?$/i){ $b_cpu_0 = 1 if defined $1 && $1 == 0; $sensors{'cpu-temp'} = int($row[$i_value]); $working_unit = $row[$i_unit]; $working_unit =~ s/degrees\s// if $b_ipmitool; $sensors{'temp-unit'} = set_temp_unit($sensors{'temp-unit'},$working_unit) if $working_unit; } - elsif ($row[$i_key] =~ /^CPU([1-4])([\s_]Temp)?$/i){ + elsif ($row[$i_key] =~ /^CPU([1-4])([\s_](below[\s_]Tmax|Temp))?$/i){ $temp_working = $1; $temp_working++ if $b_cpu_0; $sensors{"cpu${temp_working}-temp"} = int($row[$i_value]); @@ -20466,19 +21838,23 @@ sub ipmi_data { } $sensors{'temp-unit'} = set_temp_unit($sensors{'temp-unit'},$working_unit) if $working_unit; } - elsif (!$sensors{'sodimm-temp'} && $row[$i_key] =~ /^(DIMM[-_]([A-Z][0-9][-_])?[A-Z]?[0-9][A-Z]?)$/i){ + elsif (!$sensors{'sodimm-temp'} && ($row[$i_key] =~ /^(DIMM[-_]([A-Z][0-9][-_])?[A-Z]?[0-9][A-Z]?)$/i || + $row[$i_key] =~ /^DIMM[0-9] Area.*/)){ $sensors{'sodimm-temp'} = int($row[$i_value]); $working_unit = $row[$i_unit]; $working_unit =~ s/degrees\s// if $b_ipmitool; $sensors{'temp-unit'} = set_temp_unit($sensors{'temp-unit'},$working_unit) if $working_unit; } # note: can be cpu fan:, cpu fan speed:, etc. - elsif ($row[$i_key] =~ /^(CPU|Processor)[\s_]Fan/i){ + elsif ($row[$i_key] =~ /^(CPU|Processor)[\s_]Fan/i || + $row[$i_key] =~ /^SYS\.[0-9][\s_]?\(CPU\s?0\)$/i){ $sensors{'fan-main'}->[1] = int($row[$i_value]); } # note that the counters are dynamically set for fan numbers here # otherwise you could overwrite eg aux fan2 with case fan2 in theory # note: cpu/mobo/ps are 1/2/3 + # SYS.3(Front 2) + # $row[$i_key] =~ /^(SYS[\.])([0-9])\s?\((Front|Rear).+\)$/i elsif ($row[$i_key] =~ /^(SYS[\s_])?FAN[\s_]?([0-9A-F]+)/i){ $sys_fan_nu = hex($2); $fan_working = int($row[$i_value]); @@ -20505,13 +21881,13 @@ sub ipmi_data { $sensors{'fan-psu-2'} = int($row[$i_value]); } if ($extra > 0){ - if ($row[$i_key] =~ /^((MAIN\s|P[_]?)?12V|PSU[12]_VOUT)$/i){ + if ($row[$i_key] =~ /^((MAIN\s|P[_]?)?\+?12V|PSU[12]_VOUT)$/i){ $sensors{'volts-12'} = $row[$i_value]; } - elsif ($row[$i_key] =~ /^(MAIN\s5V|P5V|5VCC|5V PG|5V_SB)$/i){ + elsif ($row[$i_key] =~ /^(MAIN\s5V|P5V|5VCC|5V( PG)?|5V_SB)$/i){ $sensors{'volts-5'} = $row[$i_value]; } - elsif ($row[$i_key] =~ /^(MAIN\s3\.3V|P3V3|3\.3VCC|3\.3V PG|3V3_SB)$/i){ + elsif ($row[$i_key] =~ /^(MAIN\s3\.3V|P3V3|3\.3VCC|3\.3V( PG)?|3V3_SB)$/i){ $sensors{'volts-3.3'} = $row[$i_value]; } elsif ($row[$i_key] =~ /^((P_)?VBAT|CMOS Battery|BATT 3.0V)$/i){ @@ -21616,11 +22992,11 @@ sub proc_data { # In arm/android seen /dev/block/mmcblk0p12 # print "mount: $row->[-1]\n"; if ($row->[-1] !~ /^(nvme[0-9]+n|mmcblk|mtdblk|mtdblock)[0-9]+$/ && - $row->[-1] =~ /[a-z][0-9]+$|dm-[0-9]+$/ && - $row->[-1] !~ /\bloop/ && - !(grep {$row->[-1] =~ /$_$/} (@filters,@mounted)) && - !(grep {$_ =~ /(block\/)?$row->[-1]$/} @mounted) && - !(grep {$_ =~ /^sd[a-z]+$/ && $row->[-1] =~ /^$_[0-9]+/} @mounted)){ + $row->[-1] =~ /[a-z][0-9]+$|dm-[0-9]+$/ && + $row->[-1] !~ /\bloop/ && + !(grep {$row->[-1] =~ /$_$/} (@filters,@mounted)) && + !(grep {$_ =~ /(block\/)?$row->[-1]$/} @mounted) && + !(grep {$_ =~ /^sd[a-z]+$/ && $row->[-1] =~ /^$_[0-9]+/} @mounted)){ $dev_mapped = $dmmapper{$row->[-1]} if $dmmapper{$row->[-1]}; if (@lsblk){ my $id = ($dev_mapped) ? $dev_mapped: $row->[-1]; @@ -22897,7 +24273,7 @@ sub get { 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) = undef; + # ($b_xprop,$kde_session_version,$xdg_desktop,@data,@xprop) = (); eval $end if $b_log; return @desktop; } @@ -23047,8 +24423,8 @@ sub get_env_de_data { 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))){ + (!$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]; @@ -23250,101 +24626,58 @@ sub get_ps_de_data { 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 - # 1 check program; 2 ps_gui search; 3 data; 4: trigger alternate values/version - my @desktops =( - ['icewm','icewm','icewm'], - ['WindowMaker','WindowMaker','wmaker',''], - ['2bwm','2bwm','2bwm',''],# unverified - ['9wm','9wm','9wm',''], - ['afterstep','afterstep','afterstep',''], - ['aewm++','aewm\+\+','aewm++',''], - ['aewm','aewm','aewm',''], - ['amiwm','amiwm','amiwm',''], - ['antiwm','antiwm','antiwm',''], - ['awesome','awesome','awesome',''], - ['blackbox','blackbox','blackbox',''], - ['bspwm','bspwm','bspwm',''], - ['cagebreak','cagebreak','cagebreak',''], - ['calmwm','calmwm','calmwm',''], - ['catwm','catwm','catwm',''],# unverified - ['clfswm','.*(sh|c?lisp)?.*clfswm','clfswm',''], - ['ctwm','ctwm','ctwm',''], - ['cwm','(openbsd-)?cwm','cwm',''], - ['dwm','dwm','dwm',''], - ['echinus','echinus','echinus',''], - ['evilwm','evilwm','evilwm',''], - ['fireplace','fireplace','fireplace',''], - ['fluxbox','fluxbox','fluxbox',''], - ['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',''], - ['fvwm','fvwm','fvwm',''], - ['glass','glass','glass',''], - ['hackedbox','hackedbox','hackedbox',''], - ['herbstluftwm','herbstluftwm','herbstluftwm'], - ['instantwm','instantwm','instantwm',''], - ['i3','i3','i3',''], - ['ion3','ion3','ion3',''], - ['jbwm','jbwm','jbwm',''], - ['jwm','jwm','jwm',''], - ['larswm','larswm','larswm',''], - ['leftwm','leftwm','leftwm',''], - ['lwm','lwm','lwm',''], - ['mcwm','mcwm','mcwm',''],# unverified - ['mini','mini','mini',''], - ['musca','musca','musca',''], - ['mvwm','mvwm','mvwm',''], - ['mwm','mwm','mwm',''], - ['nawm','nawm','nawm',''], - ['notion','notion','notion',''], - ['openbox','openbox','openbox',''], - ['orbital','orbital','orbital',''], - ['pekwm','pekwm','pekwm',''], - ['perceptia','perceptia','perceptia',''], - ['penrose','penrose','penrose',''],# unverified - ['qtile','.*(python.*)?qtile','qtile',''], - ['qvwm','qvwm','qvwm',''], - ['ratpoison','ratpoison','ratpoison',''], - ['sawfish','sawfish','sawfish',''], - ['scrotwm','scrotwm','scrotwm',''], - ['snapwm','snapwm','snapwm',''],# unverified - ['spectrwm','spectrwm','spectrwm',''], - ['stumpwm','(sh|c?lisp)?.*stumpwm','stumpwm',''], - ['sway','sway','sway',''], - ['matchbox-window-manager','matchbox-window-manager','matchbox-window-manager',''], - ['tinywm','tinywm','tinywm',''], - ['tvtwm','tvtwm','tvtwm',''], - ['twm','twm','twm',''], - ['uwm','uwm','uwm',''],# unverified - ['waycooler','waycooler','way-cooler',''], - ['way-cooler','way-cooler','way-cooler',''], - ['windowlab','windowlab','windowlab',''], - ['wmfs','wmfs','wmfs',''],# unverified - ['wmfs2','wmfs2','wmfs2',''],# unverified - ['wingo','wingo','wingo',''],# unverified - # not in debian apt, current is wmii, version 3 - ['wmii2','wmii2','wmii2',''], - ['wmii','wmii','wmii',''], - ['wmx','wmx','wmx',''], - ['xmonad','xmonad','xmonad',''], - ## fallback for xfce in case no xprop - ['xfdesktop','xfdesktop','xfdesktop',''], - ['yeahwm','yeahwm','yeahwm',''], - ); - foreach my $item (@desktops){ + # 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 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 + 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){ # 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); + 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); } 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; + } + } + } } eval $end if $b_log; } @@ -23407,7 +24740,7 @@ sub get_wm_main { # 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|kwin|marco|'; + $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)/){ @@ -23421,21 +24754,18 @@ sub get_wm_main { 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 - $wms = '2bwm|9wm|aewm\+\+|aewm|afterstep|amiwm|antiwm|awesome|blackbox|'; - $wms .= 'cagebreak|calmwm|catwm|clfswm|compiz|ctwm|(openbsd-)?cwm|fluxbox'; - $wms .= '|bspwm|budgie-wm|deepin-wm|dwm|echinus|evilwm|'; - $wms .= 'fireplace|flwm|fvwm-crystal|fvwm1|fvwm2|fvwm3|fvwm95|fvwm|'; - $wms .= 'gala|glass|gnome-shell|hackedbox|i3|instantwm|ion3|jbwm|jwm|'; - $wms .= 'twin|kwin_wayland|kwin_x11|kwin|larswm|leftwm|lwm|'; - $wms .= 'matchbox-window-manager|marco|mcwm|mini|muffin|'; - $wms .= 'musca|deepin-mutter|mutter|deepin-metacity|metacity|mvwm|mwm|'; - $wms .= 'nawm|notion|openbox|orbital|perceptia|qtile|qvwm|'; - $wms .= 'penrose|ratpoison|sawfish|scrotwm|snapwm|spectrwm|'; - $wms .= 'stumpwm|sway|tinywm|tvtwm|twm|ukwm|'; - $wms .= 'way-?cooler|windowlab|WindowMaker|wingo|wm2|wmfs2?|wmii2?|wmx|'; - $wms .= 'xfwm[45]?|xmonad|yeahwm'; - foreach (@ps_gui){ - if (/^($wms)$/){ + 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; last; } @@ -23493,14 +24823,16 @@ sub set_info_data { 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|i3bar|i3status|icewmtray|'; + $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|lxpanel|lxqt-panel|'; - $pattern .= 'matchbox-panel|mate-panel|ourico|'; + $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|stalonetray|swaybar|taskbar|tint2|trayer|'; - $pattern .= 'ukui-panel|vala-panel|wbar|wharf|wingpanel|witray|'; - $pattern .= 'xfce4-panel|xfce5-panel|xmobar|yabar'; + $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){ @@ -23611,7 +24943,7 @@ sub set { main::log_data('dump','$devices{timer}',$devices{'timer'}); } } - @devices = undef; + undef @devices; eval $end if $b_log; } @@ -23623,7 +24955,7 @@ sub lspci_data { foreach (@data){ # print "$_\n"; if ($device){ - if ($_ =~ /^~$/){ + if ($_ eq '~'){ @temp = ($type,$type_id,$busid,$busid_nu,$device,$vendor_id,$chip_id, $rev,$port,$driver,$modules,$driver_nu,$subsystem,$subsystem_id); assign_data('pci',\@temp); @@ -23756,7 +25088,7 @@ sub pciconf_data { my @data = pci_grabber('pciconf'); foreach (@data){ if ($driver){ - if ($_ =~ /^~$/){ + if ($_ eq '~'){ $vendor = main::clean($vendor); $device = main::clean($device); # handle possible regex in device name, like [ConnectX-3] @@ -23829,12 +25161,12 @@ sub pcidump_data { my @data = pci_grabber('pcidump'); main::set_dboot_data() if !$loaded{'dboot'}; foreach (@data){ - if ($_ =~ /^~$/ && $busid && $device){ + if ($_ eq '~' && $busid && $device){ @temp = ($type,$type_id,$busid,$busid_nu,$device,$vendor_id,$chip_id, $rev,$port,$driver,$modules,$driver_nu,'','','',$serial); assign_data('pci',\@temp); ($type,$type_id,$busid,$busid_nu,$device,$vendor_id,$chip_id, - $rev,$port,$driver,$modules,$driver_nu,$serial) = undef; + $rev,$port,$driver,$modules,$driver_nu,$serial) = (); next; } if ($_ =~ /^([0-9a-f:]+):([0-9]+):\s([^:]+)$/i){ @@ -23878,12 +25210,12 @@ sub pcictl_data { my @data = pci_grabber('pcictl'); my @data2 = pci_grabber('pcictl-n'); foreach (@data){ - if ($_ =~ /^~$/ && $busid && $device){ + if ($_ eq '~' && $busid && $device){ @temp = ($type,$type_id,$busid,$busid_nu,$device,$vendor_id,$chip_id, $rev,$port,$driver,$modules,$driver_nu); assign_data('pci',\@temp); ($type,$type_id,$busid,$busid_nu,$device,$vendor_id,$chip_id, - $rev,$port,$driver,$modules,$driver_nu) = undef; + $rev,$port,$driver,$modules,$driver_nu) = (); next; } # it's too fragile to get these in one matching so match, trim, next match @@ -23954,6 +25286,7 @@ sub pci_grabber { # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/kot--book-lspci-nnv.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/steve-mint-topaz-lspci-nnkv.txt"; # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/ben81-hwraid-lspci-nnv.txt"; + # my $file = "$ENV{'HOME'}/bin/scripts/inxi/data/lspci/gx78b-lspci-nnv.txt"; # @data = main::reader($file,'strip'); } else { @@ -24033,7 +25366,7 @@ sub soc_devices_files { push(@files,@temp2) if @temp2; @temp2 = main::globber('/sys/devices/*/*/uevent'); # see case 10 push(@files,@temp2) if @temp2; - @temp2 = undef; + undef @temp2; # not sure why, but even as root/sudo, /subsystem|driver/uevent are unreadable with -r test true @files = grep {!/\/(subsystem|driver)\//} @files if @files; main::uniq(\@files); @@ -24054,7 +25387,7 @@ sub soc_devices { $chip_id = $5; $temp = $7; @working = main::reader($file, 'strip') if -r $file; - ($device,$driver,$handle,$type,$vendor_id) = (undef,undef,undef,undef,undef); + ($device,$driver,$handle,$type,$vendor_id) = (); foreach my $data (@working){ @temp2 = split('=', $data); if ($temp2[0] eq 'DRIVER'){ @@ -24453,7 +25786,7 @@ sub set_disklabel_data { last; } else { - my ($b_part,$duid,$part_id,$bytes_sector) = undef; + my ($b_part,$duid,$part_id,$bytes_sector) = (); if ($extra > 2 && $show{'disk'} && $alerts{'fdisk'}->{'action'} eq 'use'){ $disks_bsd{$id}->{'partition-table'} = fdisk_data($id); } @@ -24606,43 +25939,65 @@ sub set_gpart_data { sub get_display_manager { eval $start if $b_log; - my (@data,@found,$path,$working,$b_run,$b_vrun,$b_vrunrc); + my (@data,@found,@glob,$link,$path,@temp); # ldm - LTSP display manager. Note that sddm does not appear to have a .pid - # extension in Arch note: to avoid positives with directories, test for -f - # explicitly, not -e. Guessing on cdm.pid. pcdm uses vt, PCDM-vt9.pid - my @dms = qw(cdm.pid entranced.pid gdm.pid gdm3.pid kdm.pid kdm3.pid ldm.pid - lightdm.pid lxdm.pid mdm.pid nodm.pid pcdm.pid sddm.pid slim.lock - slim.pid tdm.pid udm.pid wdm.pid xdm.pid xenodm.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 + my @dms = qw(cdm emptty entranced gdm gdm3 greetd kdm kdm3 ldm lightdm lxdm ly + mdm nodm pcdm qingy sddm slim tbsm tdm udm wdm xdm xenodm); # these are the only one I know of so far that have version info - my @dms_version = qw(gdm gdm3 lightdm slim); - $b_run = 1 if -d "/run"; + my @dms_version = qw(gdm gdm3 lightdm ly slim); + my $pattern = ''; + if (-d '/run'){ + $pattern .= '/run'; + } # in most linux, /var/run is a sym link to /run, so no need to check it twice - if (-d "/var/run"){ - my $rdlink = readlink('/var/run'); - $b_vrun = 1 if !$rdlink || ($rdlink && $rdlink ne '/run'); - $b_vrunrc = 1 if -d "/var/run/rc.d"; - } - foreach my $id (@dms){ - # note: $working will create a dir name out of the dm $id, then - # test if pid is in that note: sddm, in an effort to be unique and special, - # do not use a pid/lock file, but rather a random string inside a directory - # called /run/sddm/ so assuming the existence of the pid inside a directory named - # from the dm. Hopefully this change will not have negative results. - $working = $id; - $working =~ s/\.\S+$//; - # note: there were issues with duplicated dm's in inxi, checking @found corrects it - if ((($b_run && (-f "/run/$id" || -d "/run/$working")) || - ($b_vrun && (-f "/var/run/$id" || -d "/var/run/$working")) || - ($b_vrunrc && (-f "/var/run/rc.d/$working" || -d "/var/run/rc.d/$id"))) && - !grep {/$working/i} @found){ - if ($extra > 2 && awk(\@dms_version, $working) && ($path = check_program($working))){} - else {$path = $working;} - # print "$path $extra\n"; - @data = program_data($working,$path,3); - $working = $data[0]; - $working .= ' ' . $data[1] if $data[1]; - push(@found, $working); - } + if (-d '/var/run' && ! -l '/var/run'){ + $pattern .= ',' if $pattern; + $pattern .= '/var/run'; + } + if (-d '/var/run/rc.d'){ + $pattern .= ',' if $pattern; + $pattern .= '/var/run/rc.d'; + } + if ($pattern){ + $pattern = '{' . $pattern . '/*}' if $pattern; + # for dm.pid type file or dm directory names, like greetd-684.sock + @glob = globber($pattern) if $pattern; + } + # print Data::Dumper::Dumper \@glob; + # used to test for .pid/lock type file or directory, now just see if the + # search name exists in run and call it good since test would always be true + # 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){ + 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; + } + } + @dms = @temp; + # 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"; + @data = program_data($dm,$path,3); + $dm = $data[0]; + $dm .= ' ' . $data[1] if $data[1]; + push(@found,$dm); } if (!@found){ # ly does not have a run/pid file @@ -24719,8 +26074,8 @@ sub get_bsd_os { $distro_id = lc($uname[0]); } if ($distro && - (-e '/etc/pkg/GhostBSD.conf' || -e '/usr/local/etc/pkg/repos/GhostBSD.conf') && - $distro =~ /freebsd/i){ + (-e '/etc/pkg/GhostBSD.conf' || -e '/usr/local/etc/pkg/repos/GhostBSD.conf') && + $distro =~ /freebsd/i){ my $version = (main::grabber("pkg query '%v' os-generic-userland-base 2>/dev/null"))[0]; # only swap if we get result from the query if ($version){ @@ -25010,10 +26365,10 @@ sub system_base_bsd { sub system_base { eval $start if $b_log; - my $base_arch_distro = 'anarchy|antergos|archbang|archlabs|archman|archstrike|arco|artix'; + my $base_arch_distro = 'anarchy|antergos|arch(bang|craft|labs|man|strike)|arco|artix'; # note: arch linux derived distro page claims kaos as arch derived but it is NOT $base_arch_distro .= '|blackarch|bluestar|chakra|ctios|endeavour|garuda|hyperbola|linhes'; - $base_arch_distro .= '|manjaro|mysys2|netrunner\s?rolling|ninja|obarun|parabola'; + $base_arch_distro .= '|mabox|manjaro|mysys2|netrunner\s?rolling|ninja|obarun|parabola'; $base_arch_distro .= '|puppyrus-?a|reborn|snal|talkingarch|ubos'; my $base_debian_version_distro = 'sidux'; my $base_debian_version_osr = '\belive|lmde|neptune|parrot|pureos|rescatux|septor|sparky|tails'; @@ -25045,7 +26400,7 @@ sub system_base { @osr = @osr_working; $system_base = get_os_release(); @osr = @osr_temp if !$system_base; - (@osr_temp,@osr_working) = (undef,undef); + (@osr_temp,@osr_working) = (); } } elsif (-r $base_upstream_lsb){ @@ -25224,7 +26579,7 @@ sub get_os_release { } # note: mint has varying formats here, some have ubuntu as name, 17 and earlier else { - # mint 17 used ubuntu os-release, so won't have $base_version + # mint 17 used ubuntu os-release, so won't have $base_version if ($base_name && $base_version){ $base_id = ubuntu_id($base_version) if $base_type eq 'ubuntu' && $base_version; $base_id = '' if $base_id && "$base_name$base_version" =~ /$base_id/; @@ -25282,8 +26637,9 @@ sub debian_id { return $id; } -# note, these are only for matching derived names, no need to go -# all the way back here, update as new names are known. This is because +# note, these are only for matching distro/mint derived names. +# Update list as new names become available. While first Mint was 2006-08, +# this method depends on /etc/os-release which was introduced 2012-02. # Mint is using UBUNTU_CODENAME without ID data. sub ubuntu_id { eval $start if $b_log; @@ -25291,25 +26647,25 @@ sub ubuntu_id { $codename = lc($codename); my ($id) = (''); my %codenames = ( - 'hirsute' => '21.04', - 'groovy' => '20.10', - 'focal' => '20.04 LTS', - 'eoan' => '19.10', - 'disco' => '19.04', - 'cosmic' => '18.10', - 'bionic' => '18.04 LTS', - 'artful' => '17.10', - 'zesty' => '17.04', - 'yakkety' => '16.10', - 'xenial' => '16.04 LTS', - 'wily' => '15.10', - 'vivid' => '15.04', - 'utopic' => '14.10', - 'trusty' => '14.04 LTS ', - 'saucy' => '13.10', - 'raring' => '13.04', - 'quantal' => '12.10', - 'precise' => '12.04 LTS ', + 'jammy' => '22.04 LTS', + 'impish' => '21.10','hirsute' => '21.04', + 'groovy' => '20.10','focal' => '20.04 LTS', + 'eoan' => '19.10','disco' => '19.04', + 'cosmic' => '18.10','bionic' => '18.04 LTS', + 'artful' => '17.10','zesty' => '17.04', + 'yakkety' => '16.10','xenial' => '16.04 LTS', + 'wily' => '15.10','vivid' => '15.04', + 'utopic' => '14.10','trusty' => '14.04 LTS ', + 'saucy' => '13.10','raring' => '13.04', + 'quantal' => '12.10','precise' => '12.04 LTS ', + # 'oneiric' => '11.10','natty' => '11.04', + # 'maverick' => '10.10','lucid' => '10.04', + # 'karmic' => '9.10','jaunty' => '9.04', + # 'intrepid' => '8.10','hardy' => '8.04', + # 'gutsy' => '7.10','feisty' => '7.04', + # 'edgy' => '6.10', 'dapper' => '6.06', + # 'breezy' => '5.10', 'hoary' => '5.04', + # 'warty' => '4.10', ); $id = $codenames{$codename} if defined $codenames{$codename}; eval $end if $b_log; @@ -25916,9 +27272,10 @@ sub set { # note: for bcache and luks, the device that has that fs is the parent!! if ($show{'logical'}){ $use{'logical-lvm'} = 1 if !$use{'logical-lvm'} && $2 && $2 eq 'lvm'; - if (!$use{'logical-general'} && (($4 && ($4 eq 'crypto_LUKS' || $4 eq 'bcache')) - || ($2 && ($2 eq 'dm' && $1 =~ /veracrypt/i) || - $2 eq 'crypto' || $2 eq 'mpath' || $2 eq 'multipath'))){ + if (!$use{'logical-general'} && (($4 && + ($4 eq 'crypto_LUKS' || $4 eq 'bcache')) || + ($2 && ($2 eq 'dm' && $1 =~ /veracrypt/i) || $2 eq 'crypto' || + $2 eq 'mpath' || $2 eq 'multipath'))){ $use{'logical-general'} = 1; } } @@ -26342,10 +27699,10 @@ sub package_counts { @list = main::globber($_->[3]); } else { - @list = undef; + undef @list; $error = main::message('pm-disabled'); } - $libs = undef; + undef $libs; # print Data::Dumper::Dumper \@list; if (!$error){ $count = scalar @list; @@ -26388,6 +27745,603 @@ sub count_libs { } } +## ParseEDID +{ +package ParseEDID; +# CVT_ratios: +my @known_ratios = qw(5/4 4/3 3/2 16/10 15/9 16/9); +my @edid_info = ( + ['a8', '_header'], + ['a2', 'manufacturer_name'], + + ['v', 'product_code'], + ['V', 'serial_number'], + ['C', 'week'], + ['C', 'year'], + ['C', 'edid_version'], + ['C', 'edid_revision'], + ['a', 'video_input_definition'], + + ['C', 'max_size_horizontal'], # in cm, 0 on projectors + ['C', 'max_size_vertical'], # in cm, 0 on projectors + ['C', 'gamma'], + ['a', 'feature_support'], + ['a10', '_color_characteristics'], + ['a3' , 'established_timings'], + ['a16', 'standard_timings'], + ['a72', 'monitor_details'], + + ['C', 'extension_flag'], + ['C', 'checksum'], +); +my %subfields = ( + manufacturer_name => [ + [1, ''], + [5, '1'], + [5, '2'], + [5, '3'], + ], + video_input_definition => [ + [1, 'digital'], + [1, 'separate_sync'], + [1, 'composite_sync'], + [1, 'sync_on_green'], + [2, ''], + [2, 'voltage_level'], + ], + feature_support => [ + [1, 'DPMS_standby'], + [1, 'DPMS_suspend'], + [1, 'DPMS_active_off'], + [1, 'rgb'], + + [1, ''], + [1, 'sRGB_compliance'], + [1, 'has_preferred_timing'], + [1, 'GTF_compliance'], + ], + # these are VESA timings, basically: VESA-EEDID-A2.pdf + established_timings => [ + # byte 1, 23h + [1, '720x400_70'], + [1, '720x400_88'], + [1, '640x480_60'], + [1, '640x480_67'], + [1, '640x480_72'], + [1, '640x480_75'], + [1, '800x600_56'], + [1, '800x600_60'], + # byte 2, 24h + [1, '800x600_72'], + [1, '800x600_75'], + [1, '832x624_75'], + [1, '1024x768_87i'], + [1, '1024x768_60'], + [1, '1024x768_70'], + [1, '1024x768_75'], + [1, '1280x1024_75'], + # byte 3, 25h + # 7: [1, '1152x870_75'], # apple macII + # 6-0: manufacturer's timings + ], + detailed_timing => [ + [8, 'horizontal_active'], + [8, 'horizontal_blanking'], + [4, 'horizontal_active_hi'], + [4, 'horizontal_blanking_hi'], + [8, 'vertical_active'], + [8, 'vertical_blanking'], + [4, 'vertical_active_hi'], + [4, 'vertical_blanking_hi'], + [8, 'horizontal_sync_offset'], + [8, 'horizontal_sync_pulse_width'], + [4, 'vertical_sync_offset'], + [4, 'vertical_sync_pulse_width'], + [2, 'horizontal_sync_offset_hi'], + [2, 'horizontal_sync_pulse_width_hi'], + [2, 'vertical_sync_offset_hi'], + [2, 'vertical_sync_pulse_width_hi'], + [8, 'horizontal_image_size'], # in mm + [8, 'vertical_image_size'], # in mm + [4, 'horizontal_image_size_hi'], + [4, 'vertical_image_size_hi'], + [8, 'horizontal_border'], + [8, 'vertical_border'], + + [1, 'interlaced'], + [2, 'stereo'], + [2, 'digital_composite'], + [1, 'horizontal_sync_positive'], + [1, 'vertical_sync_positive'], + [1, ''], + ], + # 16 bytes, up to 8 additional timings, each identified by a unique 2 byte + # code derived from the horizontal active pixel count, the image aspect ratio + # and field refresh rate as described in Table 3.19 + standard_timing => [ + [8, 'X'], + [2, 'aspect'], + [6, 'vfreq'], + ], + monitor_range => [ + [8, 'vertical_min'], + [8, 'vertical_max'], + [8, 'horizontal_min'], + [8, 'horizontal_max'], + [8, 'pixel_clock_max'], + ], + manufacturer_specified_range_timing => [ + # http://www.spwg.org/salisbury_march_19_2002.pdf + # for the glossary: http://www.vesa.org/Public/PSWG/PSWG15v1.pdf + [8, 'horizontal_sync_pulse_width_min'], # HSPW (Horizontal Sync Pulse Width) + [8, 'horizontal_sync_pulse_width_max'], + [8, 'horizontal_back_porch_min'], # t_hbp + [8, 'horizontal_back_porch_max'], + [8, 'vertical_sync_pulse_width_min'], # VSPW (Vertical Sync Pulse Width) + [8, 'vertical_sync_pulse_width_max'], + [8, 'vertical_back_porch_min'], # t_vbp (Vertical Back Porch) + [8, 'vertical_back_porch_max'], + [8, 'horizontal_blanking_min'], # t_hp (Horizontal Period) + [8, 'horizontal_blanking_max'], + [8, 'vertical_blanking_min'], # t_vp + [8, 'vertical_blanking_max'], + [8, 'module_revision'], + ], + cea_data_block_collection => [ + [3, 'type'], + [5, 'size'], + ], + cea_video_data_block => [ + [1, 'native'], + [7, 'mode'], + ], +); +my @cea_video_mode_to_detailed_timing = ( + 'pixel_clock', + 'horizontal_active', + 'vertical_active', + 'aspect', + 'horizontal_blanking', + 'horizontal_sync_offset', + 'horizontal_sync_pulse_width', + 'vertical_blanking', + 'vertical_sync_offset', + 'vertical_sync_pulse_width', + 'horizontal_sync_positive', + 'vertical_sync_positive', + 'interlaced' +); +my @cea_video_modes = ( +# [0] pixel clock, [1] X, [2] Y, [3] aspect, [4] Hblank, [5] Hsync_offset, [6] Hsync_pulse_width, +# [7] Vblank, [8] Vsync_offset, [9] Vsync_pulse_width, [10] Hsync+, [11] Vsync+, [12] interlaced +# 59.94/29.97 and similar modes also have a 60.00/30.00 counterpart by raising the pixel clock + [ 25.175, 640, 480, "4/3", 160, 16, 96, 45, 10, 2, 0, 0, 0 ], # 1: 640x 480@59.94 + [ 27.000, 720, 480, "4/3", 138, 16, 62, 45, 9, 6, 0, 0, 0 ], # 2: 720x 480@59.94 + [ 27.000, 720, 480, "16/9", 138, 16, 62, 45, 9, 6, 0, 0, 0 ], # 3: 720x 480@59.94 + [ 74.250, 1280, 720, "16/9", 370, 110, 40, 30, 5, 5, 1, 1, 0 ], # 4: 1280x 720@60.00 + [ 74.250, 1920, 1080, "16/9", 280, 88, 44, 45, 4, 10, 1, 1, 1 ], # 5: 1920x1080@30.00 + [ 27.000, 1440, 480, "4/3", 276, 38, 124, 45, 8, 6, 0, 0, 1 ], # 6: 1440x 480@29.97 + [ 27.000, 1440, 480, "16/9", 276, 38, 124, 45, 8, 6, 0, 0, 1 ], # 7: 1440x 480@29.97 + [ 27.000, 1440, 240, "4/3", 276, 38, 124, 22, 4, 3, 0, 0, 0 ], # 8: 1440x 240@60.05 + [ 27.000, 1440, 240, "16/9", 276, 38, 124, 22, 4, 3, 0, 0, 0 ], # 9: 1440x 240@60.05 + [ 54.000, 2880, 480, "4/3", 552, 76, 248, 45, 8, 6, 0, 0, 1 ], # 10: 2880x 480@29.97 + [ 54.000, 2880, 480, "16/9", 552, 76, 248, 45, 8, 6, 0, 0, 1 ], # 11: 2880x 480@29.97 + [ 54.000, 2880, 240, "4/3", 552, 76, 248, 22, 4, 3, 0, 0, 0 ], # 12: 2880x 240@60.05 + [ 54.000, 2880, 240, "16/9", 552, 76, 248, 22, 4, 3, 0, 0, 0 ], # 13: 2880x 240@60.05 + [ 54.000, 1440, 480, "4/3", 276, 32, 124, 45, 9, 6, 0, 0, 0 ], # 14: 1440x 480@59.94 + [ 54.000, 1440, 480, "16/9", 276, 32, 124, 45, 9, 6, 0, 0, 0 ], # 15: 1440x 480@59.94 + [ 148.500, 1920, 1080, "16/9", 280, 88, 44, 45, 4, 5, 1, 1, 0 ], # 16: 1920x1080@60.00 + [ 27.000, 720, 576, "4/3", 144, 12, 64, 49, 5, 5, 0, 0, 0 ], # 17: 720x 576@50.00 + [ 27.000, 720, 576, "16/9", 144, 12, 64, 49, 5, 5, 0, 0, 0 ], # 18: 720x 576@50.00 + [ 74.250, 1280, 720, "16/9", 700, 440, 40, 30, 5, 5, 1, 1, 0 ], # 19: 1280x 720@50.00 + [ 74.250, 1920, 1080, "16/9", 720, 528, 44, 45, 4, 10, 1, 1, 1 ], # 20: 1920x1080@25.00 + [ 27.000, 1440, 576, "4/3", 288, 24, 126, 49, 4, 6, 0, 0, 1 ], # 21: 1440x 576@25.00 + [ 27.000, 1440, 576, "16/9", 288, 24, 126, 49, 4, 6, 0, 0, 1 ], # 22: 1440x 576@25.00 + [ 27.000, 1440, 288, "4/3", 288, 24, 126, 24, 2, 3, 0, 0, 0 ], # 23: 1440x 288@50.08 + [ 27.000, 1440, 288, "16/9", 288, 24, 126, 24, 2, 3, 0, 0, 0 ], # 24: 1440x 288@50.08 + [ 54.000, 2880, 576, "4/3", 576, 48, 252, 49, 4, 6, 0, 0, 1 ], # 25: 2880x 576@25.00 + [ 54.000, 2880, 576, "16/9", 576, 48, 252, 49, 4, 6, 0, 0, 1 ], # 26: 2880x 576@25.00 + [ 54.000, 2880, 288, "4/3", 576, 48, 252, 24, 2, 3, 0, 0, 0 ], # 27: 2880x 288@50.08 + [ 54.000, 2880, 288, "16/9", 576, 48, 252, 24, 2, 3, 0, 0, 0 ], # 28: 2880x 288@50.08 + [ 54.000, 1440, 576, "4/3", 288, 24, 128, 49, 5, 5, 0, 0, 0 ], # 29: 1440x 576@50.00 + [ 54.000, 1440, 576, "16/9", 288, 24, 128, 49, 5, 5, 0, 0, 0 ], # 30: 1440x 576@50.00 + [ 148.500, 1920, 1080, "16/9", 720, 528, 44, 45, 4, 5, 1, 1, 0 ], # 31: 1920x1080@50.00 + [ 74.250, 1920, 1080, "16/9", 830, 638, 44, 45, 4, 5, 1, 1, 0 ], # 32: 1920x1080@24.00 + [ 74.250, 1920, 1080, "16/9", 720, 528, 44, 45, 4, 5, 1, 1, 0 ], # 33: 1920x1080@25.00 + [ 74.250, 1920, 1080, "16/9", 280, 88, 44, 45, 4, 5, 1, 1, 0 ], # 34: 1920x1080@30.00 + [ 108.000, 2880, 480, "4/3", 552, 64, 248, 45, 9, 6, 0, 0, 0 ], # 35: 2880x 480@59.94 + [ 108.000, 2880, 480, "16/9", 552, 64, 248, 45, 9, 6, 0, 0, 0 ], # 36: 2880x 480@59.94 + [ 108.000, 2880, 576, "4/3", 576, 48, 256, 49, 5, 5, 0, 0, 0 ], # 37: 2880x 576@50.00 + [ 108.000, 2880, 576, "16/9", 576, 48, 256, 49, 5, 5, 0, 0, 0 ], # 38: 2880x 576@50.00 + [ 72.000, 1920, 1080, "16/9", 384, 32, 168, 170, 46, 10, 1, 0, 1 ], # 39: 1920x1080@25.00 + [ 148.500, 1920, 1080, "16/9", 720, 528, 44, 45, 4, 10, 1, 1, 1 ], # 40: 1920x1080@50.00 + [ 148.500, 1280, 720, "16/9", 700, 440, 40, 30, 5, 5, 1, 1, 0 ], # 41: 1280x 720@100.00 + [ 54.000, 720, 576, "4/3", 144, 12, 64, 49, 5, 5, 0, 0, 0 ], # 42: 720x 576@100.00 + [ 54.000, 720, 576, "16/9", 144, 12, 64, 49, 5, 5, 0, 0, 0 ], # 43: 720x 576@100.00 + [ 54.000, 1440, 576, "4/3", 288, 24, 126, 49, 4, 6, 0, 0, 0 ], # 44: 1440x 576@50.00 + [ 54.000, 1440, 576, "16/9", 288, 24, 126, 49, 4, 6, 0, 0, 0 ], # 45: 1440x 576@50.00 + [ 148.500, 1920, 1080, "16/9", 280, 88, 44, 45, 4, 10, 1, 1, 1 ], # 46: 1920x1080@60.00 + [ 148.500, 1280, 720, "16/9", 370, 110, 40, 30, 5, 5, 1, 1, 0 ], # 47: 1280x 720@120.00 + [ 54.000, 720, 480, "4/3", 138, 16, 62, 45, 9, 6, 0, 0, 0 ], # 48: 720x 480@119.88 + [ 54.000, 720, 480, "16/9", 138, 16, 62, 45, 9, 6, 0, 0, 0 ], # 49: 720x 480@119.88 + [ 54.000, 1440, 480, "4/3", 276, 38, 124, 45, 8, 6, 0, 0, 1 ], # 50: 1440x 480@59.94 + [ 54.000, 1440, 480, "16/9", 276, 38, 124, 45, 8, 6, 0, 0, 1 ], # 51: 1440x 480@59.94 + [ 108.000, 720, 576, "4/3", 144, 12, 64, 49, 5, 5, 0, 0, 0 ], # 52: 720x 576@200.00 + [ 108.000, 720, 576, "16/9", 144, 12, 64, 49, 5, 5, 0, 0, 0 ], # 53: 720x 576@200.00 + [ 108.000, 1440, 576, "4/3", 288, 24, 126, 49, 4, 6, 0, 0, 1 ], # 54: 1440x 576@100.00 + [ 108.000, 1440, 576, "16/9", 288, 24, 126, 49, 4, 6, 0, 0, 1 ], # 55: 1440x 576@100.00 + [ 108.000, 720, 480, "4/3", 138, 16, 62, 45, 9, 6, 0, 0, 0 ], # 56: 720x 480@239.76 + [ 108.000, 720, 480, "16/9", 138, 16, 62, 45, 9, 6, 0, 0, 0 ], # 57: 720x 480@239.76 + [ 108.000, 1440, 480, "4/3", 276, 38, 124, 45, 8, 6, 0, 0, 1 ], # 58: 1440x 480@119.88 + [ 108.000, 1440, 480, "16/9", 276, 38, 124, 45, 8, 6, 0, 0, 1 ], # 59: 1440x 480@119.88 + [ 59.400, 1280, 720, "16/9", 2020, 1760, 40, 30, 5, 5, 1, 1, 0 ], # 60: 1280x 720@24.00 + [ 74.250, 1280, 720, "16/9", 2680, 2420, 40, 30, 5, 5, 1, 1, 0 ], # 61: 1280x 720@25.00 + [ 74.250, 1280, 720, "16/9", 2020, 1760, 40, 30, 5, 5, 1, 1, 0 ], # 62: 1280x 720@30.00 + [ 297.000, 1920, 1080, "16/9", 280, 88, 44, 45, 4, 5, 1, 1, 0 ], # 63: 1920x1080@120.00 + [ 297.000, 1920, 1080, "16/9", 720, 528, 44, 45, 4, 10, 1, 1, 0 ], # 64: 1920x1080@100.00 +); +# Exist but IDs Unknown: Pixio, AOpen (AON?), AORUS [probably GBT], Deco Gear, +# Eyoyo, GAEMS, GeChic, KOORUI, Lilliput, Mobile Pixels, Nexanic, +# SunFounder, TECNII, TPEKKA, V7/VSEVEN, +# Guesses: KYY=KYY, MSI=MSI, +# PGS: Princeton Graphic Systems; SDC: Samsung Display Co; +# SIS: Silicon Integrated Systems; STN: Samsung Electronics America; +# TAI: Toshiba America +my %vendors = ( +'ACI' => 'Asus', 'ACR' => 'Acer', 'ACT' => 'Targa', 'ADI' => 'ADI', +'AMW' => 'AMW', 'ANX' => 'Acer Netxix', 'AOC' => 'AOC', 'API' => 'Acer', +'APP' => 'Apple', 'ART' => 'ArtMedia', 'AST' => 'AST Research', 'AUO' => 'AU Optronics', +'BEL' => 'Beltronic', 'BMM' => 'BMM', 'BNQ' => 'BenQ', 'BOE' => 'BOE Display', +'CMN' => 'Chi Mei Innolux', 'CPL' => 'Compal/ALFA', 'CPQ' => 'Compaq', +'CPT' => 'Asus', 'CTX' => 'CTX (Chuntex)', 'CVT' => 'DGM', +'DEC' => 'DEC', 'DEL' => 'Dell', 'DPC' => 'Delta', 'DPL' => 'Digital Projection', 'DWE' => 'Daewoo', +'ECS' => 'Elitegroup', 'EIZ' => 'EIZO', 'EPI' => 'Envision', 'ETR' => 'Rotel', +'FCM' => 'Funai', 'FUS' => 'Fujitsu Siemens', +'GBT' => 'Gigabyte', 'GSM' => 'LG (GoldStar)', 'GWY' => 'Gateway 2000', +'HEI' => 'Hyundai.', 'HIQ' => 'Hyundai ImageQuest', 'HIT' => 'Hitachi', 'HPN' => 'HP', +'HSD' => 'Hannspree', 'HSL' => 'Hansol', 'HTC' => 'Hitachi', 'HVR' => 'Hitache', 'HWP' => 'HP', +'IBM' => 'IBM', 'ICL' => 'Fujitsu ICL', 'IFS' => 'InFocus', 'IQT' => 'Hyundai', +'IVM' => 'Idek Iiyama', +'KDS' => 'KDS', 'KFC' => 'KFC Computek', 'KYY' => 'KYY', +'LEN' => 'Lenovo', 'LGD' => 'LG', 'LKM' => 'Adlas/Azalea', 'LNK' => 'LINK', +'LPL' => 'LG Philips', 'LTN' => 'Lite-On', +'MAG' => 'MAG InnoVision', 'MAX' => 'Maxdata', 'MED' => 'Medion', +'MEI' => 'Panasonic', 'MEL' => 'Mitsubishi', 'MIR' => 'Miro', 'MSI' => 'MSI', 'MTC' => 'MITAC', +'NAN' => 'NANAO', 'NEC' => 'NEC', 'NOK' => 'Nokia', 'NVD' => 'Nvidia', +'OQI' => 'ViewSonic Optiquest', 'ORN' => 'Orion', +'PBN' => 'Packard Bell', 'PCK' => 'Daewoo', 'PDC' => 'Polaroid', 'PGS' => 'Princeton', +'PHL' => 'Philips', 'PIO' => 'Pioneer', 'PNR' => 'Planar', 'PRT' => 'Princeton', +'QDI' => 'Quahtum Data', 'QDS' => 'Quanta Display', 'REL' => 'Relisys', +'SAM' => 'Samsung', 'SAN' => 'Sanyo', 'SDC' => 'Samsung', 'SEC' => 'Seiko Epson', +'SEN' => 'Sensics', 'SHP' => 'Sharp', 'SII' => 'Silicon Image', 'SIS' => 'SIS', +'SMC' => 'Samtron', 'SMI' => 'Smile', 'SNI' => 'Siemens Nixdorf', 'SNY' => 'Sony', +'SPT' => 'Sceptre', 'SRC' => 'Shamrock', 'STN' => 'Samsung', 'STP' => 'Sceptre', +'TAI' => 'Toshiba', 'TAT' => 'Tatung', 'TOS' => 'Toshiba', 'TRL' => 'Royal Information', +'TSB' => 'Toshiba', 'UEG' => 'EliteGroup', 'UNM' => 'Unisys', +'VIT' => 'Visitech', 'VLV' => 'Valve', 'VSC' => 'ViewSonic', 'VTK' => 'Viewteck', +'WTC' => 'Wen Technology', 'ZCM' => 'Zenith', +); +sub _within_limit { + my ($value, $type, $limit) = @_; + $type eq 'min' ? $value >= $limit : $value <= $limit; +} +sub _get_many_bits { + my ($s, $field_name) = @_; + my @bits = split('', unpack('B*', $s)); + my %h; + foreach (@{$subfields{$field_name}}) { + my ($size, $field) = @$_; + my @l = ('0' x (8 - $size), splice(@bits, 0, $size)); + $h{$field} = unpack("C", pack('B*', join('', @l))) if $field && $field !~ /^_/; + } + \%h; +} +sub check_parsed_edid { + my ($edid) = @_; + $edid->{edid_version} >= 1 && $edid->{edid_version} <= 2 or return 'bad edid_version'; + $edid->{edid_revision} != 0xff or return 'bad edid_revision'; + if ($edid->{monitor_range}) { + $edid->{monitor_range}{horizontal_min} && + $edid->{monitor_range}{horizontal_min} <= $edid->{monitor_range}{horizontal_max} + or return 'bad HorizSync'; + $edid->{monitor_range}{vertical_min} && + $edid->{monitor_range}{vertical_min} <= $edid->{monitor_range}{vertical_max} + or return 'bad VertRefresh'; + } + ''; +} +sub _build_detailed_timing { + my ($pixel_clock, $vv) = @_; + my $h = _get_many_bits($vv, 'detailed_timing'); + $h->{pixel_clock} = $pixel_clock / 100; # to have it in MHz + my %detailed_timing_field_size = map { $_->[1], $_->[0] } @{$subfields{detailed_timing}}; + foreach my $field (keys %detailed_timing_field_size) { + $field =~ s/_hi$// or next; + my $hi = delete($h->{$field . '_hi'}); + $h->{$field} += $hi << $detailed_timing_field_size{$field}; + } + $h; +} +sub _add_standard_timing_modes { + my ($edid, $v) = @_; + my @aspect2ratio = ( + $edid->{edid_version} > 1 || $edid->{edid_revision} > 2 ? '16/10' : '1/1', + '4/3', '5/4', '16/9', + ); + $v = [ map { + my $h = _get_many_bits($_, 'standard_timing'); + $h->{X} = ($h->{X} + 31) * 8; + if ($_ ne "\x20\x20" && $h->{X} > 256) { # cf VALID_TIMING in Xorg edid.h + $h->{vfreq} += 60; + if ($h->{ratio} = $aspect2ratio[$h->{aspect}]) { + delete $h->{aspect}; + $h->{Y} = $h->{X} / eval($h->{ratio}); + } + $h; + } else { () } + } unpack('a2' x (length($v) / 2), $v) ]; + $v; +} +sub parse_edid { + my ($raw_edid, $verbose) = @_; + my %edid; + my ($main_edid, @eedid_blocks) = unpack("a128" x (length($raw_edid) / 128), $raw_edid); + my @vals = unpack(join('', map { $_->[0] } @edid_info), $main_edid); + my $i; + foreach (@edid_info) { + my ($field, $v) = ($_->[1], $vals[$i++]); + if ($field eq 'year') { + $v += 1990; + } elsif ($field eq 'manufacturer_name') { + my $h = _get_many_bits($v, 'manufacturer_name'); + $v = join('', map { chr(ord('A') + $h->{$_} - 1) } 1 .. 3); + $v = "" if $v eq "@@@"; + $edid{'manufacturer_name_nice'} = ($v && $vendors{$v}) ? $vendors{$v} : ''; + } elsif ($field eq 'video_input_definition') { + $v = _get_many_bits($v, 'video_input_definition'); + } elsif ($field eq 'feature_support') { + $v = _get_many_bits($v, 'feature_support'); + } elsif ($field eq 'established_timings') { + my $h = _get_many_bits($v, 'established_timings'); + $v = [ + sort { $a->{X} <=> $b->{X} || $a->{vfreq} <=> $b->{vfreq} } + map { /(\d+)x(\d+)_(\d+)(i?)/ ? { X => $1, Y => $2, vfreq => $3, $4 ? (interlace => 1) : () } : () } + grep { $h->{$_} } keys %$h ]; + } elsif ($field eq 'standard_timings') { + $v = _add_standard_timing_modes(\%edid, $v); + } elsif ($field eq 'monitor_details') { + while ($v) { + (my $pixel_clock, my $vv, $v) = unpack("v a16 a*", $v); + if ($pixel_clock) { + # detailed timing + my $h = _build_detailed_timing($pixel_clock, $vv); + push @{$edid{detailed_timings}}, $h + if $h->{horizontal_active} > 1 && $h->{vertical_active} > 1; + } else { + (my $flag, $vv) = unpack("n x a*", $vv); + if ($flag == 0xfd) { + # range + $edid{monitor_range} = _get_many_bits($vv, 'monitor_range'); + if ($edid{monitor_range}{pixel_clock_max} == 0xff) { + delete $edid{monitor_range}{pixel_clock_max}; + } else { + $edid{monitor_range}{pixel_clock_max} *= 10; #- to have it in MHz + } + } elsif ($flag == 0xf) { + my $range = _get_many_bits($vv, 'manufacturer_specified_range_timing'); + my $e = $edid{detailed_timings}[0]; + my $valid = 1; + foreach my $m ('min', 'max') { + my %total; + foreach my $dir ('horizontal', 'vertical') { + $range->{$dir . '_sync_pulse_width_' . $m} *= 2; + $range->{$dir . '_back_porch_' . $m} *= 2; + $range->{$dir . '_blanking_' . $m} *= 2; + if ($e && $e->{$dir . '_active'} + && _within_limit($e->{$dir . '_blanking'}, $m, $range->{$dir . '_blanking_' . $m}) + && _within_limit($e->{$dir . '_sync_pulse_width'}, $m, $range->{$dir . '_sync_pulse_width_' . $m}) + && _within_limit($e->{$dir . '_blanking'} - $e->{$dir . '_sync_offset'} - $e->{$dir . '_sync_pulse_width'}, + $m, $range->{$dir . '_back_porch_' . $m})) { + $total{$dir} = $e->{$dir . '_active'} + $range->{$dir . '_blanking_' . $m}; + } + } + if ($total{horizontal} && $total{vertical}) { + my $hfreq = $e->{pixel_clock} * 1000 / $total{horizontal}; + my $vfreq = $hfreq * 1000 / $total{vertical}; + $range->{'horizontal_' . ($m eq 'min' ? 'max' : 'min')} = _round($hfreq); + $range->{'vertical_' . ($m eq 'min' ? 'max' : 'min')} = _round($vfreq); + } else { + $valid = 0; + } + } + $edid{$valid ? 'monitor_range' : 'manufacturer_specified_range_timing'} = $range; + } elsif ($flag == 0xfa) { + push @{$edid{standard_timings}}, _add_standard_timing_modes(\%edid, unpack('a12', $vv)); + } elsif ($flag == 0xfc) { + my $prev = $edid{monitor_name}; + $edid{monitor_name} = ($prev ? "$prev " : '') . unpack('A13', $vv); + } elsif ($flag == 0xfe) { + push @{$edid{monitor_text}}, unpack('A13', $vv); + } elsif ($flag == 0xff) { + push @{$edid{serial_number2}}, unpack('A13', $vv); + } else { + $verbose && $vv ne "\0" x 13 && $vv ne " " x 13 and + warn "parse_edid: unknown flag $flag\n"; + } + } + } + } + $edid{$field} = $v if $field && $field !~ /^_/; + } + foreach (@eedid_blocks) { + my ($tag, $v) = unpack("C a*", $_); + if ($tag == 0x02) { # CEA EDID + my $dtd_offset; + ($dtd_offset, $v) = unpack("x C x a*", $v); + next if $dtd_offset < 4; + $dtd_offset -= 4; + while ($dtd_offset > 0) { + if (!$v) { + warn "parse_edid: DTD offset outside of available data\n" if $verbose; + last; + } + my $h = _get_many_bits($v, 'cea_data_block_collection'); + $dtd_offset -= $h->{size} + 1; + my $vv; + ($vv, $v) = unpack("x a$h->{size} a*", $v); + if ($h->{type} == 0x02) { # Video Data Block + my @vmodes = unpack("a" x $h->{size}, $vv); + foreach my $vmode (@vmodes) { + $h = _get_many_bits($vmode, 'cea_video_data_block'); + my $cea_mode = $cea_video_modes[$h->{mode} - 1]; + if (!$cea_mode) { + warn "parse_edid: unhandled CEA mode $h->{mode}\n" if $verbose; + next; + } + my %det_mode = (source => 'cea_vdb'); + @det_mode{@cea_video_mode_to_detailed_timing} = @$cea_mode; + push @{$edid{detailed_timings}}, \%det_mode; + } + } + } + while (length($v) >= 18) { + (my $pixel_clock, my $vv, $v) = unpack("v a16 a*", $v); + last if !$pixel_clock; + my $h = _build_detailed_timing($pixel_clock, $vv); + push @{$edid{detailed_timings}}, $h + if $h->{horizontal_active} > 1 && $h->{vertical_active} > 1; + } + } else { + $verbose && warn "parse_edid: unknown tag $tag\n"; + } + } + $edid{max_size_precision} = 'cm'; + $edid{EISA_ID} = $edid{manufacturer_name} . sprintf('%04x', $edid{product_code}) if $edid{product_code} && $edid{manufacturer_name}; + if ($edid{monitor_range}) { + $edid{HorizSync} = $edid{monitor_range}{horizontal_min} . '-' . $edid{monitor_range}{horizontal_max}; + $edid{VertRefresh} = $edid{monitor_range}{vertical_min} . '-' . $edid{monitor_range}{vertical_max}; + } + if ($edid{max_size_vertical}) { + $edid{ratio} = $edid{max_size_horizontal} / $edid{max_size_vertical}; + $edid{ratio_name} = _ratio_name($edid{max_size_horizontal}, $edid{max_size_vertical}, 'cm'); + $edid{ratio_precision} = 'cm'; + } + if ($edid{feature_support}{has_preferred_timing} && $edid{detailed_timings}[0]) { + $edid{detailed_timings}[0]{preferred} = 1; + } + foreach my $h (@{$edid{detailed_timings}}) { + # EDID standard is ambiguous on how interlaced modes should be + # specified; workaround clearly broken modes: + if ($h->{interlaced}) { + foreach ("720x480", "1440x480", "2880x480", "720x576", "1440x576", "2880x576", "1920x1080") { + if ($_ eq $h->{horizontal_active} . 'x' . $h->{vertical_active} * 2) { + $h->{vertical_active} *= 2; + $h->{vertical_blanking} *= 2; + $h->{vertical_sync_offset} *= 2; + $h->{vertical_sync_pulse_width} *= 2; + $h->{vertical_blanking} |= 1; + } + } + } + # if the mm size given in the detailed_timing is not far from the cm size + # put it as a more precise cm size + my %in_cm = ( + horizontal => _define($h->{horizontal_image_size}) / 10, + vertical => _define($h->{vertical_image_size}) / 10, + ); + my ($error) = sort { $b <=> $a } map { abs($edid{'max_size_' . $_} - $in_cm{$_}) } keys %in_cm; + if ($error <= 0.5) { + $edid{'max_size_' . $_} = $in_cm{$_} foreach keys %in_cm; + $edid{max_size_precision} = 'mm'; + } + if ($error < 1 && $in_cm{vertical}) { + # using it for the ratio + $edid{ratio} = $in_cm{horizontal} / $in_cm{vertical}; + $edid{ratio_name} = _ratio_name($in_cm{horizontal}, $in_cm{vertical}, 'mm'); + $edid{ratio_precision} = 'mm'; + } + $h->{bad_ratio} = 1 if + $edid{ratio_precision} && + abs($edid{ratio} - $h->{horizontal_active} / $h->{vertical_active}) > ($edid{ratio_precision} eq 'mm' ? 0.02 : 0.2); + + if ($edid{max_size_vertical}) { + $h->{vertical_dpi} = $h->{vertical_active} / $edid{max_size_vertical} * 2.54; + } + if ($edid{max_size_horizontal}) { + $h->{horizontal_dpi} = $h->{horizontal_active} / $edid{max_size_horizontal} * 2.54; + } + my $dpi_string = ''; + if ($h->{vertical_dpi} && $h->{horizontal_dpi}) { + $dpi_string = + abs($h->{vertical_dpi} / $h->{horizontal_dpi} - 1) < 0.05 ? + sprintf("%d dpi", $h->{horizontal_dpi}) : + sprintf("%dx%d dpi", $h->{horizontal_dpi}, $h->{vertical_dpi}); + } + my $horizontal_total = $h->{horizontal_active} + $h->{horizontal_blanking}; + my $vertical_total = $h->{vertical_active} + $h->{vertical_blanking}; + no warnings 'uninitialized'; + $h->{ModeLine_comment} = sprintf qq(# Monitor %s%s modeline (%.1f Hz vsync, %.1f kHz hsync, %sratio %s%s)), + $h->{preferred} ? "preferred" : "supported", + $h->{source} eq 'cea_vdb' ? " CEA" : '', + $h->{pixel_clock} / $horizontal_total / $vertical_total * 1000 * 1000 * ($h->{interlaced} ? 2 : 1), + $h->{pixel_clock} / $horizontal_total * 1000, + $h->{interlaced} ? "interlaced, " : '', + _nearest_ratio($h->{horizontal_active} / $h->{vertical_active}, 0.01) || sprintf("%.2f", $h->{horizontal_active} / $h->{vertical_active}), + $dpi_string ? ", $dpi_string" : ''; + + $h->{ModeLine} = sprintf qq("%dx%d" $h->{pixel_clock} %d %d %d %d %d %d %d %d %shsync %svsync%s), + $h->{horizontal_active}, $h->{vertical_active}, + + $h->{horizontal_active}, + $h->{horizontal_active} + $h->{horizontal_sync_offset}, + $h->{horizontal_active} + $h->{horizontal_sync_offset} + $h->{horizontal_sync_pulse_width}, + $horizontal_total, + + $h->{vertical_active}, + $h->{vertical_active} + $h->{vertical_sync_offset}, + $h->{vertical_active} + $h->{vertical_sync_offset} + $h->{vertical_sync_pulse_width}, + $vertical_total, + + $h->{horizontal_sync_positive} ? '+' : '-', + $h->{vertical_sync_positive} ? '+' : '-', + $h->{interlaced} ? ' Interlace' : ''; + } + $edid{diagonal_size} = sqrt(_sqr($edid{max_size_horizontal}) + _sqr($edid{max_size_vertical})) / 2.54; + + \%edid; +} +sub _nearest_ratio { + my ($ratio, $max_error) = @_; + my @sorted = + sort { $a->[1] <=> $b->[1] } + map { + my $error = abs($ratio - eval($_)); + $error > $max_error ? () : [ $_, $error ]; + } @known_ratios; + $sorted[0][0]; +} +sub _ratio_name { + my ($horizontal, $vertical, $precision) = @_; + if ($precision eq 'mm') { + _nearest_ratio($horizontal / $vertical, 0.1); + } else { + my $error = 0.5; + my $ratio1 = _nearest_ratio(($horizontal + $error) / ($vertical - $error), 0.2); + my $ratio2 = _nearest_ratio(($horizontal - $error) / ($vertical + $error), 0.2); + $ratio1 && $ratio2 or return; + if ($ratio1 eq $ratio2) { + $ratio1; + } else { + my $ratio = _nearest_ratio($horizontal / $vertical, 0.2); + join(' or ', $ratio, $ratio eq $ratio1 ? $ratio2 : $ratio1); + } + } +} +sub _define { defined $_[0] ? $_[0] : 0 } +sub _sqr { $_[0] * $_[0] } +sub _round { int($_[0] + 0.5) } +} + ## PartitionData - set/get # for /proc/partitions only, see DiskDataBSD for BSD partition data. { @@ -26459,6 +28413,79 @@ sub get_pci_vendor { return $vendor; } +# $rows, $num by ref. +sub get_pcie_data { + eval $start if $b_log; + my ($bus_id,$j,$rows,$num,$type) = @_; + $type ||= ''; + # see also /sys/class/drm/ + my $path_start = '/sys/bus/pci/devices/0000:'; + return if !$bus_id || ! -d $path_start . $bus_id; + $path_start .= $bus_id; + my $path = $path_start . '/{max_link_width,current_link_width,max_link_speed'; + $path .= ',current_link_speed}'; + my @files = globber($path); + if ($type eq 'gpu'){ + $path = $path_start . '/0000*/0000*/{mem_info_vram_used,mem_info_vram_total}'; + push(@files,globber($path)); + } + # print @files,"\n"; + return if !@files; + my (%data,$name); + my %gen = ( + '2.5 GT/s' => 1, + '5 GT/s' => 2, + '8 GT/s' => 3, + '16 GT/s' => 4, + '32 GT/s' => 5, + '64 GT/s' => 6, + ); + foreach (@files){ + if (-r $_){ + $name = $_; + $name =~ s|^/.*/||; + $data{$name} = reader($_,'strip',0); + if ($name eq 'max_link_speed' || $name eq 'current_link_speed'){ + $data{$name} =~ s/\.0\b| PCIe$//g; # trim .0 off in 5.0, 8.0 + } + } + } + # print Data::Dumper::Dumper \%data; + # Maximum PCIe Bandwidth = SPEED * WIDTH * (1 - ENCODING) - 1Gb/s. + if ($data{'current_link_speed'} && $data{'current_link_width'}){ + $$rows[$j]->{key($$num++,1,2,'pcie')} = ''; + if ($b_admin && $gen{$data{'current_link_speed'}}){ + $$rows[$j]{key($$num++,0,3,'gen')} = $gen{$data{'current_link_speed'}}; + } + $$rows[$j]{key($$num++,0,3,'speed')} = $data{'current_link_speed'}; + $$rows[$j]->{key($$num++,0,3,'lanes')} = $data{'current_link_width'}; + if ($b_admin && (($data{'max_link_speed'} && + $data{'max_link_speed'} ne $data{'current_link_speed'}) || + ($data{'max_link_width'} && + $data{'max_link_width'} > $data{'current_link_width'}))){ + $$rows[$j]->{key($$num++,1,3,'link-max')} = ''; + if ($data{'max_link_speed'} && + $data{'max_link_speed'} ne $data{'current_link_speed'}){ + $$rows[$j]{key($$num++,0,4,'gen')} = $gen{$data{'max_link_speed'}}; + $$rows[$j]->{key($$num++,0,4,'speed')} = $data{'max_link_speed'}; + } + if ($data{'max_link_width'} && + $data{'max_link_width'} > $data{'current_link_width'}){ + $$rows[$j]->{key($$num++,0,4,'lanes')} = $data{'max_link_width'}; + } + } + } + if ($type eq 'gpu' && $data{'mem_info_vram_used'} && $data{'mem_info_vram_total'}){ + $$rows[$j]->{key($$num++,1,2,'vram')} = ''; + $$rows[$j]->{key($$num++,0,3,'total')} = get_size($data{'mem_info_vram_total'}/1024,'string'); + my $used = get_size($data{'mem_info_vram_used'}/1024,'string'); + $used .= ' (' . sprintf('%0.1f',($data{'mem_info_vram_used'}/$data{'mem_info_vram_total'}*100)) . '%)'; + $$rows[$j]->{key($$num++,0,3,'used')} = $used; + + } + eval $end if $b_log; +} + sub set_ps_aux { eval $start if $b_log; my ($header,@ps,@temp); @@ -26503,30 +28530,29 @@ sub set_ps_aux { sub set_ps_gui { eval $start if $b_log; $loaded{'ps-gui'} = 1; - my ($working,@match,@temp); + my ($b_wl,$working,@match,@temp); # 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 - cagebreak calmwm catwm (sh|c?lisp).*clfswm ctwm (openbsd-)?cwm dwm evilwm + blackbox bspwm calmwm catwm (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 orbital pekwm penrose perceptia python.*qtile qtile qvwm ratpoison - sawfish scrotwm snapwm spectrwm (sh|c?lisp).*stumpwm sway - tinywm tvtwm twm uwm - waycooler way-cooler windowlab WindowMaker wingo wm2 wmfs wmfs2 wmii2 wmii - wmx - xfdesktop xmonad yeahwm); + openbox 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: + # 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 kwin marco + twin kwin_wayland kwin_x11 kwinft kwin marco deepin-metacity metacity metisse mir muffin deepin-mutter mutter ukwm xfwm[45]?); push(@match,@temp); @@ -26538,29 +28564,42 @@ sub set_ps_gui { 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 icewmtray - kdocker kicker latte latte-dock lemonbar ltpanel lxpanel lxqt-panel - matchbox-panel mate-panel ourico + 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 stalonetray swaybar taskbar tint2 trayer - ukui-panel vala-panel wbar wharf wingpanel witray - xfce[45]?-panel xmobar yabar); + 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. # for wayland always show, so always load these - if ($show{'graphic'} && $extra > 0){ - @temp=qw(3dwm asc budgie-wm compiz compton deepin-wm dwc dcompmgr - enlightenment fireplace gnome-shell grefson kmscon kwin_wayland kwin_x11 - liri marco metisse mir moblin motorcar muffin mutter - orbital papyros perceptia picom rustland sommelier sway swc - ukwm unagi unity-system-compositor - wavy waycooler way-cooler wayfire wayhouse westford weston xcompmgr - xfwm[45]?); + if ($show{'graphic'}){ + @temp=qw(3dwm budgie-wm cairo compiz compton deepin-wm dcompmgr enlightenment + gala gnome-shell kmscon kwin_wayland kwin_x11 kwinft kwin + marco metisse mir moblin muffin mutter picom steamcompmgr + ukwm unagi unity-system-compositor wayland xcompmgr xfwm[45]?); push(@match,@temp); + $b_wl = 1; } uniq(\@match); my $matches = join('|', @match); + if ($b_wl){ + # 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 + cage cagebreak cardboard chameleonwm clayland comfc + dwc dwl epd-wm fireplace feathers fenestra glass gamescope greenfield grefson + hikari hopalong inaban japokwm kiwmi labwc laikawm lipstick liri + mahogany marina maze motorcar newm nucleus orbital perceptia phoc pywm qtile + river rootston rustland simulavr skylight sommelier sway swc swvkc + 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; + } foreach (@ps_cmd){ if (/^(|[\S]*\/)($matches)(\/|\s|$)/){ $working = $2; @@ -26953,8 +28992,8 @@ sub shell_launcher { } # in case sudo starts inxi, parent is shell (or perl inxi if run by debugger) # so: perl (2) started pinxi with sudo (3) in sh (4) in terminal - my $shells = 'ash|bash|busybox|cicada|csh|dash|doas|elvish|fish|fizsh|ksh|ksh93|'; - $shells .= 'lksh|login|loksh|mksh|nash|oh|oil|osh|pdksh|perl|posh|'; + my $shells = 'ash|bash|busybox|cicada|csh|dash|doas|elvish|fish|fizsh|ksh|'; + $shells .= 'ksh93|lksh|login|loksh|mksh|nash|oh|oil|osh|pdksh|perl|posh|'; $shells .= 'su|sudo|tcsh|xonsh|yash|zsh'; $shells .= shell_test('return'); my $i = 0; @@ -27416,7 +29455,7 @@ sub usbconfig_data { undef @working; } elsif (/^([a-z_-]+)([0-9]+)\.([0-9]+):\s+<[^>]+>\s+at usbus([0-9]+)\b/){ - ($class_id,$cfg,$power,$speed,$subclass_id,$type) = undef; + ($class_id,$cfg,$power,$speed,$subclass_id,$type) = (); ($product,$product_id,$vendor,$vendor_id) = ('','','',''); $hub_id = $2; $addr_id = $3; @@ -27925,9 +29964,8 @@ sub assign_usb_type { # nested hubs of course can be > 1 too. No need to build these if none of # lines are showing. if (($row->[4] && $row->[4] eq '09') || - ($row->[14] && $row->[14] eq 'Hub') || - $row->[1] <= 1 || - (!$show{'audio'} && !$show{'bluetooth'} && !$show{'graphic'} && !$show{'network'})){ + ($row->[14] && $row->[14] eq 'Hub') || $row->[1] <= 1 || + (!$show{'audio'} && !$show{'bluetooth'} && !$show{'graphic'} && !$show{'network'})){ return; } $row->[13] = '' if !defined $row->[13]; # product @@ -27937,27 +29975,24 @@ sub assign_usb_type { set_network_regex() if $show{'network'} && !$network_regex; # NOTE: a device, like camera, can be audio+graphic if ($show{'audio'} && ( - (@asound_ids && $row->[7] && (grep {$row->[7] eq $_} @asound_ids)) || - ($row->[14] =~ /Audio/) || - ($row->[15] && $row->[15] =~ /audio/) || - ($row->[13] && lc($row->[13]) =~ /(audio|\bdac[0-9]*\b|headphone|\bmic(rophone)?\b)/))){ + (@asound_ids && $row->[7] && (grep {$row->[7] eq $_} @asound_ids)) || + ($row->[14] =~ /Audio/) || ($row->[15] && $row->[15] =~ /audio/) || + ($row->[13] && lc($row->[13]) =~ /(audio|\bdac[0-9]*\b|headphone|\bmic(rophone)?\b)/))){ push(@{$usb{'audio'}},$row); } - if ($show{'graphic'} && ( - $row->[14] && ($row->[14] =~ /Video/) || - ($row->[15] && $row->[15] =~ /video/) || - ($row->[13] && lc($row->[13]) =~ /(camera|\bdvb-t|\b(pc)?tv\b|video|webcam)/))){ + if ($show{'graphic'} && ($row->[14] && ($row->[14] =~ /Video/) || + ($row->[15] && $row->[15] =~ /video/) || + ($row->[13] && lc($row->[13]) =~ /(camera|\bdvb-t|\b(pc)?tv\b|video|webcam)/))){ push(@{$usb{'graphics'}},$row); } - elsif ($show{'bluetooth'} && ( - $row->[14] && $row->[14] =~ /Bluetooth/ || - ($row->[15] && $row->[15] =~ /\b(btusb|ubt)\b/))){ + elsif ($show{'bluetooth'} && ($row->[14] && $row->[14] =~ /Bluetooth/ || + ($row->[15] && $row->[15] =~ /\b(btusb|ubt)\b/))){ push(@{$usb{'bluetooth'}},$row); } elsif ($show{'network'} && ( - ($row->[14] && $row->[14] =~ /(Ethernet|Network|WiFi)/i) || - ($row->[15] && $row->[15] =~ /(^ipw|^iwl|wifi)/) || - ($row->[13] && $row->[13] =~ /($network_regex)/i))){ + ($row->[14] && $row->[14] =~ /(Ethernet|Network|WiFi)/i) || + ($row->[15] && $row->[15] =~ /(^ipw|^iwl|wifi)/) || + ($row->[13] && $row->[13] =~ /($network_regex)/i))){ # print "$1\n"; push(@{$usb{'network'}},$row); } @@ -28038,7 +30073,7 @@ sub check_type { $type = 'Bluetooth' } elsif (($driver && $driver =~ /video/) || - $name =~ /(camera|display|\bdvb-t|\b(pc)?tv\bvideo|webcam)/){ + $name =~ /(camera|display|\bdvb-t|\b(pc)?tv\bvideo|webcam)/){ $type = 'Video'; } elsif ($name =~ /(wlan|wi-?fi|802\.1[15]|(11|54|108|240|300|450|1300)\s?mbps|(11|54|108|240)g\b|wireless[\s-][gn]\b|wireless.*adapter)/){ @@ -28054,7 +30089,7 @@ sub check_type { $type = 'HID'; } elsif (($driver && $driver =~ /^(umass)$/) || - $name =~ /\b(disk|drive|flash)\b/){ + $name =~ /\b(disk|drive|flash)\b/){ $type = 'Mass Storage'; } return $type; @@ -28600,8 +30635,8 @@ sub system_item { } # don't print the desktop if it's a wm and the same if ($extra > 1 && $desktop_data[5] && - (!$desktop_data[0] || $desktop_data[5] =~ /^(deepin.+|gnome[\s_-]shell|budgie.+)$/i || - index(lc($desktop_data[5]),lc($desktop_data[0])) == -1)){ + (!$desktop_data[0] || $desktop_data[5] =~ /^(deepin.+|gnome[\s_-]shell|budgie.+)$/i || + index(lc($desktop_data[5]),lc($desktop_data[0])) == -1)){ $wm = $desktop_data[5]; $wm .= ' ' . $desktop_data[6] if $extra > 2 && $desktop_data[6]; } |
