pax_global_header00006660000000000000000000000064141767222500014520gustar00rootroot0000000000000052 comment=fc68788468351138477f6ad71d6f4cf717e3810b hw-probe-1.6.2/000077500000000000000000000000001417672225000132515ustar00rootroot00000000000000hw-probe-1.6.2/Dockerfile000066400000000000000000000053041417672225000152450ustar00rootroot00000000000000FROM alpine:3.13 RUN apk update \ && apk add --no-cache perl curl xz dmidecode pciutils usbutils \ smartmontools hdparm sysstat util-linux lm_sensors acpi iw wireless-tools glib libxrandr zlib eudev-libs libusb libdrm \ alsa-utils xrandr xdpyinfo xinput acpica iasl perl-libwww \ && apk add --no-cache --virtual build-deps git gcc g++ make autoconf automake libtool file bsd-compat-headers libc-dev util-linux-dev flex linux-headers glib-dev libxrandr-dev zlib-dev eudev-dev libusb-dev libdrm-dev \ && git clone https://git.linuxtv.org/edid-decode.git 2>/dev/null \ && cd edid-decode \ && make \ && find . -type f | perl -lne 'print if -B and -x' | xargs strip \ && make install \ && cd .. \ && rm -fr edid-decode \ && git clone https://github.com/rockowitz/ddcutil.git \ && cd ddcutil \ && git checkout 1.1.0-dev \ && NOCONFIGURE=1 NO_CONFIGURE=1 sh autogen.sh \ && ./configure --prefix=/usr \ && make \ && find . -type f | perl -lne 'print if -B and -x' | xargs strip \ && make install \ && cd .. \ && rm -fr ddcutil \ && git clone https://github.com/wfeldt/libx86emu.git \ && cd libx86emu \ && make \ && find . -type f | perl -lne 'print if -B and -x' | xargs strip \ && make install \ && cd .. \ && rm -fr libx86emu \ && git clone https://github.com/openSUSE/hwinfo.git \ && cd hwinfo \ && make \ && find . -type f | perl -lne 'print if -B and -x' | xargs strip \ && make install \ && cd .. \ && rm -fr hwinfo \ && curl -L https://github.com/linuxhw/build-stuff/releases/download/1.6/hw-probe-1.6-AI.tar.gz > hw-probe-1.6-AI.tar.gz \ && tar -xf hw-probe-1.6-AI.tar.gz \ && rm -fr hw-probe-1.6-AI.tar.gz \ && cd hw-probe-1.6-AI \ && make install \ && cd .. \ && rm -fr hw-probe-1.6-AI \ && apk del build-deps \ && rm -fr /usr/bin/acpibin /usr/bin/acpiexamples /usr/bin/acpiexec /usr/bin/acpihelp /usr/bin/acpinames /usr/bin/acpisrc /usr/bin/lsusb.py /usr/bin/usbhid-dump \ && rm -fr /usr/sbin/convert_hd /usr/sbin/check_hd /usr/sbin/mk_isdnhwdb /usr/sbin/getsysinfo /usr/sbin/fancontrol /usr/sbin/pwmconfig /usr/sbin/isadump /usr/sbin/isaset /usr/sbin/ownership /usr/sbin/setpci /usr/sbin/vpddecode /usr/sbin/update-smart-drivedb /usr/sbin/smartd \ && rm -fr /usr/share/man /usr/share/doc /usr/share/pkgconfig /usr/share/cmake /usr/share/ddcutil \ && rm -fr /usr/include \ && rm -fr /usr/lib/pkgconfig /usr/lib/systemd /usr/lib/libddc* \ && rm -fr /usr/share/perl5/vendor_perl/libwww/*.pod \ && rm -fr /usr/bin/lwp-* \ && rm -fr /var/cache/apk/* ENV LD_LIBRARY_PATH /usr/lib64:/usr/lib ENV DISPLAY :0 ENTRYPOINT ["/usr/bin/hw-probe", "-docker"] hw-probe-1.6.2/INSTALL.BSD.md000066400000000000000000000215471417672225000153210ustar00rootroot00000000000000INSTALL HOWTO FOR BSD ===================== HW Probe 1.6 (Sep 21, 2021) This file explains how to install and setup environment for the tool in your computer. Just find the name of your BSD variant on this page. See more info in the [README.md](README.md). Contents -------- * [ Install on FreeBSD ](#install-on-freebsd) * [ Install on OpenBSD ](#install-on-openbsd) * [ Install on NetBSD ](#install-on-netbsd) * [ Install on helloSystem ](#install-on-hellosystem) * [ Install on DragonFly ](#install-on-dragonfly) * [ Install on MidnightBSD ](#install-on-midnightbsd) * [ Install on OPNsense ](#install-on-opnsense) * [ Install on TrueNAS ](#install-on-truenas) * [ Install on FreeNAS ](#install-on-freenas) * [ Install on pfSense ](#install-on-pfsense) * [ Install on XigmaNAS ](#install-on-xigmanas) * [ Install on other BSD ](#install-on-other-bsd) * [ Easy way to contribute ](#easy-way-to-contribute) * [ Run without Installing ](#run-without-installing) Install on FreeBSD ------------------ On FreeBSD and derivatives (GhostBSD, NomadBSD, FuryBSD, TrueOS, PC-BSD, HardenedBSD, DesktopBSD, ArisbluBSD, helloSystem, etc.). ###### Latest systems For FreeBSD 11.x, 12.x and newer and derivatives install this port: https://www.freshports.org/sysutils/hw-probe/ pkg install hw-probe or manually: cd /usr/ports/sysutils/hw-probe make install Probe your computer: hw-probe -all -upload ###### From upstream Get latest version of the tool: fetch http://bsd-hardware.info/hw-probe Install dependencies manually: pkg install dmidecode smartmontools hwstat lscpu curl perl5 or automatically: perl hw-probe -install-deps Probe your computer: perl hw-probe -all -upload ###### Old systems Get the tool from upstream (see above) and install deps in the following way: For old FreeBSD releases < 9.3: env PACKAGESITE='http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/ports//packages--release/Latest/' pkg_add -r dmidecode smartmontools hwstat cpuid curl perl For older FreeBSD releases < 8.0 you need also `usbutil` package to be installed: pkg_add -r usbutil For older FreeBSD releases < 7.0: pkg_add -r p5-Digest-SHA Oldest supported FreeBSD version is currently 6.4. Probe your computer: perl hw-probe -all -upload ###### Graphical desktops Desktop users should enable `sudo` by installing `sudo` package and adding user to `sudoers` file (https://www.freebsd.org/doc/handbook/security-sudo.html) to preserve user environment variables: sudo -E hw-probe -all -upload Install on OpenBSD ------------------ On OpenBSD and derivatives (AdJ, FuguIta, etc.). ###### Latest systems For OpenBSD, a package is available (see https://cvsweb.openbsd.org/ports/sysutils/hw-probe/): pkg_add hw-probe Probe your computer: hw-probe -all -upload ###### From upstream Get the tool: ftp http://bsd-hardware.info/hw-probe Install dependencies manually: pkg_add dmidecode smartmontools usbutil lscpu curl or automatically: perl hw-probe -install-deps Probe your computer: perl hw-probe -all -upload ###### Old systems For old OpenBSD releases < 6.5: PKG_PATH=https://ftp.nluug.nl/OpenBSD//packages/ pkg_add dmidecode smartmontools usbutil lscpu curl Install on NetBSD ----------------- On NetBSD and derivatives (OS108, etc.). Get the tool: ftp http://bsd-hardware.info/hw-probe Install dependencies manually: pkgin install dmidecode smartmontools usbutil curl perl or automatically: perl hw-probe -install-deps Probe your computer: perl hw-probe -all -upload Install on helloSystem ---------------------- Pre-installed on helloSystem 0.3.0 and newer. From the menu, launch the __Hardware Probe__ utility and follow the on-screen instructions: ![image](https://user-images.githubusercontent.com/2480569/103484839-12564480-4df2-11eb-8c57-d6ee6ef48e2b.png) Install on DragonFly -------------------- ###### Latest systems For DragonFlyBSD 5.8 and newer install this dport: https://github.com/DragonFlyBSD/DPorts/tree/master/sysutils/hw-probe pkg install hw-probe Probe your computer: hw-probe -all -upload ###### From upstream Get latest version of the tool: fetch http://bsd-hardware.info/hw-probe Install dependencies manually: pkg install dmidecode smartmontools hwstat lscpu curl perl5 or automatically: perl hw-probe -install-deps Probe your computer: perl hw-probe -all -upload Install on MidnightBSD ---------------------- ###### Latest systems For MidnightBSD 1.2.7 and newer install this mport: https://www.midnightbsd.org/mports/sysutils/hw-probe/ mport install hw-probe Probe your computer: hw-probe -all -upload ###### From upstream Get latest version of the tool: fetch http://bsd-hardware.info/hw-probe Install dependencies manually: mport install dmidecode smartmontools cpuid curl perl or automatically: perl hw-probe -install-deps Probe your computer: perl hw-probe -all -upload Install on OPNsense ------------------- For OPNsense 20.7.8 and newer. Install os-hw-probe plugin under Menu->System->Firmware->Plugins. Install on TrueNAS ------------------ For TrueNAS 12 and newer: pkg add https://pkg.freebsd.org/FreeBSD:12:amd64/latest/All/lscpu-1.2.0.txz https://pkg.freebsd.org/FreeBSD:12:amd64/latest/All/hwstat-0.5.1.txz https://pkg.freebsd.org/FreeBSD:12:amd64/latest/All/hw-probe-1.6.b2.txz Alternatively you can enable FreeBSD repository and install the package from there: sed 's/enabled: yes/enabled: no/' /usr/local/etc/pkg/repos/local.conf sed 's/enabled: no/enabled: yes/' /usr/local/etc/pkg/repos/FreeBSD.conf pkg install hw-probe Probe your computer: hw-probe -all -upload Install on FreeNAS ------------------ For FreeNAS 11.x: pkg add https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/lscpu-1.2.0.txz https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/hwstat-0.5.1.txz https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/hw-probe-1.6.b2.txz Alternatively you can enable FreeBSD repository and install the package from there: sed 's/enabled: yes/enabled: no/' /usr/local/etc/pkg/repos/local.conf sed 's/enabled: no/enabled: yes/' /usr/local/etc/pkg/repos/FreeBSD.conf pkg install hw-probe Probe your computer: hw-probe -all -upload Install on pfSense ------------------ For pfSense 2.5.x: pkg add https://pkg.freebsd.org/FreeBSD:12:amd64/latest/All/lscpu-1.2.0.txz https://pkg.freebsd.org/FreeBSD:12:amd64/latest/All/hwstat-0.5.1.txz https://pkg.freebsd.org/FreeBSD:12:amd64/latest/All/hw-probe-1.6.b2.txz For pfSense 2.4.x: pkg add https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/lscpu-1.2.0.txz https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/hwstat-0.5.1.txz https://pkg.freebsd.org/FreeBSD:11:amd64/latest/All/hw-probe-1.6.b2.txz Alternatively you can enable FreeBSD repository and install the package from there: sed 's/enabled: no/enabled: yes/' /usr/local/etc/pkg/repos/pfSense.conf pkg install hw-probe Probe your computer: /usr/local/bin/hw-probe -all -upload Install on XigmaNAS ------------------- Install package: pkg install hw-probe Probe your computer: /usr/local/bin/hw-probe -all -upload Install on other BSD -------------------- Get the tool: curl -s http://bsd-hardware.info/hw-probe > hw-probe On first run the tool will ask to install missed dependencies (perl, dmidecode, smartmontools, lscpu, curl). You can install them manually or automatically with the help of the following option: perl hw-probe -install-deps Probe your computer: perl hw-probe -all -upload Easy way to Contribute ---------------------- Everyone can contribute to the database even without having BSD installed on their computers by writing [helloSystem Live image](https://github.com/helloSystem/ISO/releases) to a USB stick once and then probing all the computers around w/o the need to install or modify anything! Just do: * Download and write the [helloSystem Live image](https://github.com/helloSystem/ISO/releases) to any USB stick * Plug it to any computer * Power on the computer, enter the Boot Menu and select the USB stick * Connect to WiFi or just plug the Ethernet cable * From the menu, launch the __Hardware Probe__ utility and follow the on-screen instructions Now you can probe all your computers around by booting from this USB stick! The same can be done with the help of [NomadBSD Live USB image](https://www.nomadbsd.org/download.html). In this case follow the [FreeBSD instructions](#install-on-freebsd) on it to install and run hw-probe. Note that at first start NomadBSD will run the setup wizard to prepare the USB stick. Run without Installing ---------------------- From Github: curl -s https://raw.githubusercontent.com/linuxhw/hw-probe/master/hw-probe.pl | perl From upstream (mirror): curl -s http://bsd-hardware.info/hw-probe | perl Enjoy! hw-probe-1.6.2/INSTALL.md000066400000000000000000000323521417672225000147060ustar00rootroot00000000000000INSTALL HOWTO ============= HW Probe 1.6 (Sep 21, 2021) This file explains how to install and setup environment for the tool in your computer. Just find the name of your Linux distribution or BSD variant on this page. See more info in the [README.md](README.md). Contents -------- * [ Run without Installing ](#run-without-installing) * [ Command line to Run ](#command-line-to-run) * [ Install on Ubuntu ](#install-on-ubuntu) * [ Install on Debian ](#install-on-debian) * [ Install on BSD ](#install-on-bsd) * [ Install on Fedora ](#install-on-fedora) * [ Install on Manjaro ](#install-on-manjaro) * [ Install on Arch Linux ](#install-on-arch-linux) * [ Install on CentOS ](#install-on-centos) * [ Install on Alpine ](#install-on-alpine) * [ Install on ArcoLinux ](#install-on-arcolinux) * [ Install on blackPanther ](#install-on-blackpanther) * [ Install on Chrome OS ](#install-on-chrome-os) * [ Install on Clear Linux ](#install-on-clear-linux) * [ Install on ClearOS ](#install-on-clearos) * [ Install on EasyOS ](#install-on-easyos) * [ Install on Endless ](#install-on-endless) * [ Install on Gentoo ](#install-on-gentoo) * [ Install on Hefftor ](#install-on-hefftor) * [ Install on Mageia ](#install-on-mageia) * [ Install on NixOS ](#install-on-nixos) * [ Install on OpenMandriva ](#install-on-openmandriva) * [ Install on openSUSE ](#install-on-opensuse) * [ Install on OpenVZ ](#install-on-openvz) * [ Install on Oracle Linux ](#install-on-oracle-linux) * [ Install on PCLinuxOS ](#install-on-pclinuxos) * [ Install on Puppy ](#install-on-puppy) * [ Install on QTS ](#install-on-qts) * [ Install on RHEL ](#install-on-rhel) * [ Install on ROSA ](#install-on-rosa) * [ Install on Slackware ](#install-on-slackware) * [ Install on Solus ](#install-on-solus) * [ Install on Void Linux ](#install-on-void-linux) * [ Install from Source ](#install-from-source) Run without Installing ---------------------- You can probe your computer by [AppImage](README.md#appimage), [Docker](README.md#docker), [Snap](README.md#snap), [Flatpak](README.md#flatpak) or [Live CD/USB](README.md#live-cd) without the need to install anything on your host. Command line to Run ------------------- sudo -E hw-probe -all -upload Install on Ubuntu ----------------- On Ubuntu and Ubuntu based Linux distributions (Kubuntu, Lubuntu, Xubuntu, Linux Mint, Zorin, Pop!_OS, elementary OS, KDE neon, Peppermint, Linuxfx, Linux Lite, HamoniKR, WindowsFX, Trisquel, Makulu Linux, GalliumOS, etc.). ###### Ubuntu package The package is available in Ubuntu 20.04 or newer and its derivatives (https://packages.ubuntu.com/focal/hw-probe): sudo add-apt-repository universe sudo apt-get update sudo apt-get install hw-probe --no-install-recommends For older Ubuntu versions try package from Ubuntu 20.04: [hw-probe_1.5-1_all.deb](http://mirrors.kernel.org/ubuntu/pool/universe/h/hw-probe/hw-probe_1.5-1_all.deb) ###### Upstream package Download Debian package [hw-probe_1.5-1_all.deb](https://github.com/linuxhw/hw-probe/releases/download/1.5/hw-probe_1.5-1_all.deb) and install: sudo add-apt-repository universe sudo apt-get update sudo apt-get install ./hw-probe_1.5-1_all.deb --no-install-recommends ###### Snap The [Snap package](README.md#snap) is also available to install and run easily on Ubuntu without the need to install any Deb packages to your system. Install on Debian ----------------- On Debian and Debian based Linux distributions (Kali, LMDE, MX Linux, antiX, Devuan, PureOS, Parrot, Pardus, deepin, BunsenLabs, SolydXK, SparkyLinux, Q4OS, Tails, Raspbian, BigLinux, siduction, Nitrux, Kaisen, etc.). Enable sudo by https://wiki.debian.org/sudo if not enabled. ###### Debian package The package is available in Debian 11 Bullseye or newer and its derivatives (https://packages.debian.org/bullseye/hw-probe): sudo apt install hw-probe --no-install-recommends ###### Unstable package sudo apt-get install debian-archive-keyring sudo sh -c 'echo deb http://deb.debian.org/debian unstable main > /etc/apt/sources.list.d/debian-sid.list' sudo apt-get update sudo apt-get install --no-install-recommends hw-probe sudo rm -f /etc/apt/sources.list.d/debian-sid.list sudo apt-get update ###### Upstream package Download Deb package [hw-probe_1.5-1_all.deb](https://github.com/linuxhw/hw-probe/releases/download/1.5/hw-probe_1.5-1_all.deb) and install: sudo apt-get update sudo dpkg -i ./hw-probe_1.5-1_all.deb sudo apt-get install -f --no-install-recommends Install on BSD -------------- On FreeBSD and derivatives (GhostBSD, NomadBSD, FuryBSD, TrueOS, PC-BSD, HardenedBSD, FreeNAS, TrueNAS, pfSense, OPNsense, XigmaNAS, DesktopBSD, ArisbluBSD, helloSystem, etc.), OpenBSD and derivatives (AdJ, FuguIta, etc.), NetBSD and derivatives (OS108, etc.), DragonFly and MidnightBSD. See [INSTALL.BSD.md](INSTALL.BSD.md). Install on Fedora ----------------- On Fedora 28 and newer: sudo dnf install hw-probe Install on Manjaro ------------------ On Manjaro 18 or newer and derivatives (Mabox, etc.): sudo pacman -S hw-probe Try `sudo pacman -Syu` if pacman can't find the package. Install on Arch Linux --------------------- On Arch Linux and derivatives (Artix, EndeavourOS, RebornOS, Garuda, KaOS, Archman, Bluestar, LaxerOS, etc.): ###### From AUR When using Live CD/USB you need to add `cow_spacesize=512M` boot option to have enough space. Install edid-decode dependency: pacman -Syu git binutils fakeroot make gcc git clone https://aur.archlinux.org/edid-decode-git.git cd edid-decode-git makepkg -sri Install hardware probe: git clone https://aur.archlinux.org/hw-probe.git cd hw-probe makepkg -sri ###### Upstream package Download package [hw-probe-1.5-ArchLinux-any.pkg.tar.xz](https://github.com/linuxhw/hw-probe/releases/download/1.5/hw-probe-1.5-ArchLinux-any.pkg.tar.xz) and install by pacman: sudo pacman -U ./hw-probe-1.5-ArchLinux-any.pkg.tar.xz Install on CentOS ----------------- On CentOS 8, CentOS 7 and CentOS 6: sudo yum install epel-release sudo yum install hw-probe ###### Old systems If installation from EPEL is not possible. On early CentOS 7 installations: curl https://raw.githubusercontent.com/linuxhw/hw-probe/master/hw-probe.pl | sudo dd of=/usr/bin/hw-probe sudo chmod +x /usr/bin/hw-probe sudo yum install -y http://li.nux.ro/download/nux/dextop/el7/x86_64/libx86emu-1.1-2.1.x86_64.rpm sudo yum install -y http://li.nux.ro/download/nux/dextop/el7/x86_64/hwinfo-20.2-5.3.x86_64.rpm sudo yum install -y curl dmidecode smartmontools hdparm lm_sensors usbutils pciutils mcelog On early CentOS 6 installations: curl https://raw.githubusercontent.com/linuxhw/hw-probe/master/hw-probe.pl | sudo dd of=/usr/bin/hw-probe sudo chmod +x /usr/bin/hw-probe sudo yum install -y http://mirror.ghettoforge.org/distributions/gf/el/6/gf/x86_64/libx86emu-1.1-1.gf.el6.x86_64.rpm sudo yum install -y http://mirror.ghettoforge.org/distributions/gf/el/6/gf/x86_64/hwinfo-20.2-1.gf.el6.x86_64.rpm sudo yum install -y curl dmidecode smartmontools hdparm lm_sensors usbutils pciutils mcelog Install on Alpine ----------------- sudo apk add --no-cache -X http://dl-cdn.alpinelinux.org/alpine/edge/testing hw-probe Install on ArcoLinux --------------------- Pre-installed on ArcoLinux v20.11.9 and newer. Install on blackPanther ----------------------- On blackPanther OS 16.2 and newer: installing hw-probe This command will install all the dependencies as well. Install on Chrome OS -------------------- Open settings, turn on support for Linux and open the Linux Terminal. Now use [AppImage](README.md#appimage) or install the [Flatpak](README.md#flatpak). Install on Clear Linux ---------------------- See https://clearlinux.org/software/flathub/hardware-probe sudo swupd bundle-add desktop flatpak install flathub org.linux_hardware.hw-probe flatpak run org.linux_hardware.hw-probe -all -upload Install on ClearOS ------------------ sudo yum-config-manager --enable clearos-centos sudo yum-config-manager --enable clearos-epel sudo yum install hw-probe Install on EasyOS ----------------- Update local database by Menu > Setup > PETget Package Manager > Configure package manager > Update now. Install `perl-base`, `libhd`, `hwinfo`, `util-linux` and `smartmontools` by Menu > Setup > PETget Package Manager. Open the console: curl https://raw.githubusercontent.com/linuxhw/hw-probe/master/hw-probe.pl | dd of=/usr/bin/hw-probe chmod +x /usr/bin/hw-probe Install on Endless ------------------ Search for "Hardware Probe" program in the App Center. See https://flathub.org/apps/details/org.linux_hardware.hw-probe Install on Gentoo ----------------- On Gentoo and Gentoo based Linux distributions (CloudReady, Calculate, Funtoo, Redcore, LiGurOS, etc.): sudo emerge --ask sys-apps/hw-probe ###### Bobwya repository With [app-eselect/eselect-repository](https://wiki.gentoo.org/wiki/Eselect/Repository) installed: sudo eselect repository enable bobwya sudo emerge --ask sys-apps/hw-probe ###### Manual sudo emerge --ask sys-apps/hwinfo sudo emerge --ask sys-apps/pciutils sudo emerge --ask sys-apps/usbutils sudo emerge --ask sys-apps/dmidecode curl https://raw.githubusercontent.com/linuxhw/hw-probe/master/hw-probe.pl | sudo dd of=/usr/bin/hw-probe sudo chmod +x /usr/bin/hw-probe Install on Hefftor ------------------ For Hefftor 2021-01 and newer: sudo pacman -Syu hw-probe Install on Mageia ----------------- ###### Upstream package For Mageia 5 and newer: su urpmi https://github.com/linuxhw/hw-probe/releases/download/1.5/hw-probe-1.5-Mageia5.noarch.rpm edid-decode Install on NixOS ---------------- Use [Docker](README.md#docker) or [Flatpak](README.md#flatpak). Install on OpenMandriva ----------------------- Pre-installed on OpenMandriva Lx 4.0 and newer. Install on openSUSE ------------------- Select and install an RPM package for your openSUSE distribution and derivatives (GeckoLinux, etc.): https://software.opensuse.org/package/hw-probe openSUSE Leap 15.1: sudo zypper addrepo https://download.opensuse.org/repositories/hardware/openSUSE_Leap_15.1/ hardware sudo zypper install hw-probe openSUSE Tumbleweed: sudo zypper addrepo https://download.opensuse.org/repositories/hardware/openSUSE_Tumbleweed/ hardware sudo zypper install hw-probe Install on OpenVZ ----------------- On OpenVZ 8 and OpenVZ 7: sudo yum install epel-release sudo yum install hw-probe Install on Oracle Linux ----------------------- On Oracle Linux 7: sudo yum-config-manager --add-repo=http://download.fedoraproject.org/pub/epel/7/x86_64/ sudo yum install epel-release sudo yum install hw-probe On Oracle Linux 8 use [AppImage](README.md#appimage). Install on PCLinuxOS -------------------- Use [AppImage](README.md#appimage). Install on Puppy ---------------- On Puppy 7 and newer (XenialPup64, BionicPup64, etc.): Update local database by Menu > Setup > Puppy Package Manager > Configure > Update database > Update now. Install `perl-base`, `hwinfo`, `util-linux` and `smartmontools` by Menu > Setup > Puppy Package Manager. curl https://raw.githubusercontent.com/linuxhw/hw-probe/master/hw-probe.pl | sudo dd of=/usr/bin/hw-probe sudo chmod +x /usr/bin/hw-probe Install on QTS -------------- Use [Docker](README.md#docker). Install on RHCOS ---------------- Use [Docker](README.md#docker). Install on RHEL --------------- On RHEL 6-8 and RHEL based Linux distributions (CentOS, AlmaLinux, Rocky Linux, Scientific Linux, Springdale Linux, etc.): sudo yum install epel-release sudo yum install hw-probe Install on ROSA --------------- Pre-installed on ROSA Fresh R4 and newer. Install on Sabayon ------------------ Use [AppImage](README.md#appimage). Install on Slackware -------------------- On Slackware and Slackware based Linux distributions (Porteus, etc.). Use [AppImage](README.md#appimage), [Docker](README.md#docker) or [Flatpak](README.md#flatpak). Install on Solus ---------------- Use [AppImage](README.md#appimage) or [Flatpak](README.md#flatpak). Install on Void Linux --------------------- Use [AppImage](README.md#appimage) or [Flatpak](README.md#flatpak). Install on VzLinux ------------------ On VzLinux 8: sudo dnf install epel-release sudo dnf install hw-probe Install from Source ------------------- This command will install the `hw-probe` program in the `PREFIX/bin` system directory: sudo make install prefix=PREFIX [/usr, /usr/local, ...] To uninstall: sudo make uninstall prefix=PREFIX ###### Requires * Perl 5 * perl-Digest-SHA * perl-Data-Dumper * hwinfo (https://github.com/openSUSE/hwinfo or https://pkgs.org/download/hwinfo) * curl * dmidecode * smartmontools (smartctl) * pciutils (lspci) * usbutils (lsusb) * edid-decode ###### Recommends * libwww-perl (to use instead of curl) * mcelog * hdparm * systemd-tools (systemd-analyze) * acpica-tools * drm_info * mesa-demos * memtester * sysstat (iostat) * cpuid * rfkill * xinput * vainfo * inxi * vulkan-utils * i2c-tools * opensc ###### Suggests * hplip (hp-probe) * sane-backends (sane-find-scanner) * pnputils (lspnp) Enjoy! hw-probe-1.6.2/LICENSE.md000066400000000000000000000000411417672225000146500ustar00rootroot00000000000000LGPL-2.1-or-later OR BSD-4-Clausehw-probe-1.6.2/LICENSES/000077500000000000000000000000001417672225000144565ustar00rootroot00000000000000hw-probe-1.6.2/LICENSES/BSD-4-Clause000066400000000000000000000032211417672225000163620ustar00rootroot00000000000000Copyright (c) 2014-2020 Andrey Ponomarenko. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed by Andrey Ponomarenko. 4. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.hw-probe-1.6.2/LICENSES/LGPL-2.1-or-later000066400000000000000000000636361417672225000171760ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! hw-probe-1.6.2/Makefile000066400000000000000000000004121417672225000147060ustar00rootroot00000000000000prefix ?= /usr tool = hw-probe tool_dir = $(DESTDIR)$(prefix)/bin .PHONY: all all: echo "Nothing to build." install: mkdir -p $(tool_dir) install -m 755 $(tool).pl $(tool_dir)/$(tool) uninstall: rm -f $(tool_dir)/$(tool) clean: echo "Nothing to clean up." hw-probe-1.6.2/NEWS.md000066400000000000000000000416641417672225000143620ustar00rootroot00000000000000Contents -------- * [ HW PROBE 1.6 ](#hw-probe-16) * [ HW PROBE 1.6 BETA ](#hw-probe-16-beta) * [ HW PROBE 1.5 ](#hw-probe-15) * [ HW PROBE 1.4 ](#hw-probe-14) * [ HW PROBE 1.3 ](#hw-probe-13) * [ HW PROBE 1.2 ](#hw-probe-12) * [ HW PROBE 1.1 ](#hw-probe-11) * [ HW PROBE 1.0 ](#hw-probe-10) HW PROBE 1.6 ------------ Released on Sep 21, 2021. In this release we have properly tested and fixed support for almost all *BSD systems, expanded support for more Linux systems, implemented probing of HP Smart Array and improved decorating of possibly significant data in collected logs. LHWM — Linux/BSD Hardware Monitoring feature is publicly available. Changes since 1.6 BETA: ### New Features * Support for HP Smart Array * Introduced 'fixed' status of the device * Improve decorating of possibly significant data in logs * Automatically generate and upload report by using systemd timer * Display size of unknown RAM module(s) as extra device in the list * Add outgoing http/https proxy support * Identify Kubuntu, Xubuntu, Lubuntu, Ubuntu Budgie and Ubuntu Mate * Probe for ofwdump (BSD) * Probe for sndstat (BSD) * Collect system build number (BSD) * Support for helloSystem * Probe for neofetch * Identify OPNsense, TrueNAS, XigmaNAS, ArisbluBSD and LibertyBSD (BSD) * Identify FFS filesystem (BSD) * Identify wm (BSD) * Collect `pkg_info -qP` on OpenBSD (BSD) * Probe for getprop (Android) * Identifying of video driver (BSD) * Identifying of LMDE and CryptoDATA * Probe for /var/log/messages if dmesg output is incomplete * Probe for drm_info * Probe for /var/run/dmesg.boot (BSD) * Identify Trinity and Unity DEs * Identify more Synaptics fingerprint readers * Add -show-dmesg option * Detect computer form-factor on OpenBSD ### Bug Fixes * Final fixes for LHWM — Linux/BSD Hardware Monitoring * Do not probe for systemctl by default * Disable automatic upload if no arguments are passed * Fix identifying of partition scheme * Fix identifying of LightDM * Fix identifying of OS version * Fix identifying of drives and batteries * Fix decorating of MMC s/n (BSD) * Decorate user name in systemctl log * Fix identifying of GhostBSD version * Fix identifying of memory modules, drives and monitors * Fix identifying of processor microarchitecture * Fix identifying of small memory modules * Fix identifying of notebook computer type (BSD) * Fix counting of NICs (BSD) * Fix identifying of computer form-factor * Fix identifying of DE * Fix identifying of HWaddr * Fix identifying of Synaptics fingerprint readers * Fix decorating of UUID in efibootmgr log * Fix identifying of computer type * Fix identifying of Linux distribution * Fix identifying of CD-ROMs * Fix identifying of CPU model * Change memory modules IDs * Update list of processor microarchitectures * Fix collector of Xorg log * Fix identifying of window managers (BSD) * Do not hang on empty floppy drives (BSD) * Fix probe of acpidump (BSD) * Fix anonymization of audit log in dmesg * Fix anonymization of grub.cfg * Fix anonymization of private paths * Fix identifying of PhoenixOS, siduction and NixOS * Add -m option to inxi probe * Fix identifying of Devuan * Fix identifying of video driver (BSD) * Hide private strings in ifconfig (BSD) * Fix status of network devices * Do not handle large boot logs * Fix collecting of SMART attributes from NVMe drives (BSD) * Fix identifying of NomadBSD * Do not require hwstat and lscpu on unknown BSD systems * Do not require dmidecode on non-x86 systems (pfSense) * Identify kind of network device properly (BSD) * Fix -save option to make a probe first * Fix identifying of motherboard * Fix identifying of graphics card * Set status of webcam to default if driver is missed (BSD) * Identify CPU by sysctl (BSD) * Identify partitioning scheme by fdisk (BSD) ### Other * Added Debian 11 Live images with hw-probe preinstalled * Update install instructions for Linux and BSD HW PROBE 1.6 BETA ----------------- Released on May 29, 2020 (0e0162f). In this release we add support for BSD systems (FreeBSD, OpenBSD, NetBSD, DragonFly, MidnightBSD, GhostBSD, NomadBSD, FreeNAS, pfSense, OS108, etc.), improve identification of hardware devices on board and fix several security issues in collected logs. ### New Features * Support for BSD systems (FreeBSD, OpenBSD, NetBSD, DragonFly, MidnightBSD, GhostBSD, NomadBSD, FreeNAS, pfSense, OS108, etc.) * Dual license: LGPL-2.1-or-later or BSD-4-Clause * Probe for monitor DDC by ddcutil * Probe for display manager * Probe for locale language * Support for edid-decode 2020 * Improve identifying of RAM modules * Improve identifying of hard drives * Improve identifying of Synaptics fingerprint readers * Improve identifying of drives * Improve identifying of OS * Improve identifying of computer type * Improve identifying of monitor model * Improve identifying of DE and display server * Handle (fix) large probes in a local .tmp_XXX directory instead of /tmp ### Bug Fixes * Fix security issues in df and dmesg * Hide partial UUIDs in logs * Hide private strings in efibootmgr and systemctl logs * Fix identifying of hard drive size * Fix identifying of MMC drives * Do not parse inappropriate X11 logs to identify graphics card status * Fix identifying of OS in Flatpak probes (Chrome OS, Elementary, Fedora and CentOS) * Fix identifying of unknown mobile broadband devices * Hide more UUIDs * Fix leak of username in audit dmesg log, Xorg log and systemctl log * Make sure hostname is removed from Xorg log * Fix duplicated PCI devices by SysFS ID * Identify vendor of NVMe drives properly * Fix IDs of unknown SSD drives * Hide /snap/XXX paths * Hide UUIDs in efibootmgr * Fix Dockerfile ### Other * Update install instructions * AppImage: add ddcutil, update edid-decode * Flatpak: add developer_name to appdata * Use sudo -E to make probes to preserve DE name * AppImage: always use built-in smartctl and ddcutil * Identify probes via termux * Snap&Flatpak: speedup build * Snap&Flatpak: update acpica to 20200110 and hwinfo to 21.68 HW PROBE 1.5 ------------ Released on Jan 15, 2020 (200fbb5). In this release we significantly improved anonymization of probes, added quick run-time tests for several devices and implemented more detailed identification of hardware devices on board. **Summary:** significantly better anonymization of probes, support for MegaRAID and Adaptec RAID, simple run-time tests for memory/HDD/CPU, enabling/disabling of particular probes, better identification of devices/statuses, importing probes by inventory ID, identification of hardware/OS properties, hardware monitoring (Beta), support for universal packages. ### New Features * Add LHWM options (Linux Hardware Monitoring) - COMING SOON! * Support for MegaRAID (collect SMART attributes of all connected drives) * Options to enable/disable logs in addition to current log level * Added simple tests for memory, HDD and CPU * Measure speed of all drives by default if `-check-hdd` option is specified * Use `sudo -E` to preserve environment variables * Improve anonymization of logs * Hash all UUIDs * Do not save uploaded data locally by default * Clarify privacy policy * Add `-limit-check-hdd` option to limit number of drives to check * Add `-minimal`/`-maximal` options to easily change logging level * Add `-confirm-upload-of-hashed-ids` alias for `-upload` option * Import probes by inventory ID * Require Email to generate inventory ID * Display platform devices (for phones, routers, etc.) * Display MMC drives * Display real number of equal devices on board * Probe for MegaRAID (by `storcli`, `megacli` and `megactl`) * Probe for Adaptec RAID (by `arcconf`) * Probe for `/lib/firmware` in the maximal log-level mode * Collect `df -Th` * Collect `hddtemp` * Collect `bundle-list` on Clear Linux OS * Collect packages list on Slackware and Solus * Collect DE name, display server and system language * Collect `systemd-analyze` summary * Collect `nvme smart-log` * Collect EDID if `edid-decode` is not installed * Collect output of `opensc-tool` for chipcards * Collect `Xorg.0.log` in XWayland (latest Ubuntu) * Collect `/var/log/gpu-manager.log` * Collect `/etc/system-release` if available * Collect `/etc/lsb-release` if available * Identify filesystem * Identify monitor(s) by X11 log if proprietary driver is used * Identify DE and display server * Identify kind of network controllers * Identify monitor ratio by resolution if physical size is missed * Identify pixel density of a monitor * Identify microarch and microcode of CPU * Identify video memory size * Identify total space and used space * Identify screen area and ratio * Identify subvendor and submodel * Identify status of a battery * Identify boot mode (EFI or BIOS) * Identify nomodeset * Identify total and used RAM * Identify dual boot * Identify CPU op-modes * Identify OpenVZ, Pop!_OS and KDE neon distributions * Identify MX Linux properly * Identify RAM vendor by JEDEC id * Identify RAM vendor by model prefix * Identify SecureBoot by `dmesg` * Identify form-factor by hard drive model * Identify status of network devices properly * Identify status for more device types * Improve identifying of RAM modules, hard drives, monitors, batteries, scanners, DVB cards and fingerprint readers * Improve identifying of computer type and form-factor * Improve identifying of SoC vendor and model * Improve identifying of hard drives * Improve identifying of monitors * Improve identifying of RAM modules * Count NICs and monitors * Count sockets, cores and threads * Get missed hard drive size from `lsblk` * Guess drive kind if missed * Support for more Synaptics fingerprint readers * Recursively apply status of device to low-level devices * Detect status of devices: graphics cards, wifi cards, ethernet cards, bluetooth cards, sound cards, modems, storage controllers, monitors and batteries * Detect status for more devices: chipcards, fingerprint readers, card readers, dvb cards, web cameras and tv cards * Allow to run from `STDIN` and w/o any options * `sudo` is not required for importing of probes anymore * Extend list of invalid MAC addresses * Improve output of -show option * Added -show-devices option * Access tokens are obsolete * Print devices list in JSON * Show probe log by a new option * Add -save option to make offline probes * Send probe by `libwww-perl` in case of curl failure ### Bug Fixes * Fix analysis of Adaptec RAID * Fix identifying of hardware ID (ignore USB network controllers) * Fix identifying of graphics drivers * Fix identifying of SecureBoot * Fix identifying of video card status * Fix identifying of processor model * Fix identifying of unknown RAM modules * Fix identifying of operability status for desktop graphics cards and USB wireless cards * Fix identifying of monitor resolution * Fix identifying of OS name * Fix identifying of product name * Fix identifying of device drivers in use * Fix identifying of vendor/model for desktops and servers * Detect status of graphics cards properly if Xorg log is not available * Fix status of bridge devices * Fix status of network cards in case of multiple ethernet interfaces * Fix status of secondary graphics cards * Fix status of graphics cards on Gentoo * Fix counting of duplicated devices on board * Fix collecting of `Xorg.0.log`, `xorg.conf` and `xorg.conf.d` configs * Fix EDID parser * Fix motherboard naming * Fix naming of unknown memory modules * Fix IDs of unknown memory modules and batteries * Do not display batteries of peripheral devices * Remove `avahi`, `lsinitrd`, `pstree` and `top` from maximal log level * Probe for `fstab` in the default log level on ROSA Linux * Fix error handling in the `-fix` option * Do not try to run `smartctl` on cdroms * Move `fstab` log from the default logging level to maximal * Move `modinfo` to the maximal log level * Move `alsactl` to maximal logging level * Move `sensors`, `cpuid`, `cpuinfo` and `lscpu` to minimal set of logs * Move `findmnt` and `mount` to maximal set of logs * Do not collect `pstree` and `numactl` by default * Move `sensors`, `meminfo`, `cpuid` and `cpuinfo` probes up * Hide inet6 addr in `ifconfig` and `ip` outputs * Hide lvm volume groups in `boot.log`, `lsblk` and `dev` * Hide paths in `grub` config * Hide comments in `fstab` * Hide local paths in `df`, `lsblk`, `findmnt`, `mount`, `fstab` and `boot.log` * Hide IPs in `dmesg`, `df`, `findmnt`, `mount` and `fstab` * Hide labels in `lsblk` output * Hide hostname in `dmesg` output * Hide all serial strings in the output of `hwinfo` and `usb-devices` * Skip hiding of commonly used terms * Security fixes in `dmesg`, `xorg.log`, `dev`, `systemctl`, `systemd-analyze`, `fdisk` and `lsblk` logs * Decorate occasional hostname in `boot.log` * Decorate LABEL in `fstab` * Fix incompatibility with `Perl 5.8` * Fix incomplete `lspci`/`lsusb` reports * Fix probes offline view * Move `hwinfo --framebuffer` probe to maximal log level * Remove `hwinfo --zip` probe * Do not remove small `lsblk` and `efibootmgr` logs * Fix minimal logging level * Remove spec chars from `boot.log` * Truncate large `boot.log` (F29, Ubuntu 18) * Drop `curl --http1.0` option * Compress probes by `xz -9` * Run `mcelog` on `x86*` only * Clear `modinfo` output * Compacting of `modinfo` log * Truncate large logs * Properly detect `hwaddr` * Clear empty logs * Use `IO::Interface` if `ip` and `ifconfig` commands are not available * Use `POSIX::uname` if `uname` command is not available * Do not use `POSIX` module * Do not dump `lspci`/`lsusb` errors * Remove spec chars from device names * Rename `-get-inventory-id` option to `-generate-inventory` * Fix `glxgears` test * Fix collected packages list on Arch Linux * Order the list of installed RPM packages ### Other * Add install instructions for Alpine, Arch Linux, blackPanther OS, CentOS 6/7/8, Debian, Fedora, Manjaro, openSUSE, OpenVZ 7, Puppy Linux and RHEL 6/7/8. * Improve install instructions for Ubuntu, Manjaro, Gentoo and Puppy * Update `Dockerfile` * Support for old tgz compressed probes * Protect `dmesg` log * Remove error messages from `dmidecode` log * Support for the new Perl `inxi` * Added `-high-compress` option for better compression of archive * Added `-hwinfo-path` option * Code review by H.Merijn Brand - Tux HW PROBE 1.4 ------------ Released on Apr 14, 2018 (3a59093). Most significant change in this release is the anonymization of probes on the client-side. Previously "private data" (like IPs, MACs, serials, hostname, username, etc.) was removed on the server-side. But now you do not have to worry how server will handle your "private data", since it's not uploaded at all. You can now upload probes from any computers and servers w/o the risk of security leak. **Summary:** improved privacy, faster probing, probe USB drives, probe MegaRAID, probe via sudo, improved detection of hardware, Deb package. ### New Features 1. Remove private information from probe (hostname, IPs, MACs, serials, etc.) on the client side 2. Up to 3 times faster probing of hardware 3. Allow to run the tool via `sudo` 4. Improved detection of LCD monitors, motherboards and drives 5. Collect SMART info from drives connected by USB 6. Initial support for probing drives in MegaRAID 7. Collect info about MMC controllers 8. Get EDID hex dump from `xrandr` output 9. Added Debian/Ubuntu package 10. Collecting logs in C locale 11. Added `-identify-monitor` and `-fix-edid` private options 12. Probe for `mcelog`, `slabtop`, `cpuid` and `/proc/scsi` 13. Added probe of packages list on Arch by pacman 14. Improved `lsblk` and `iostat` probes 15. Print warning if X11-related logs are not collected 16. Renamed `-group` option to `-inventory-id` 17. Renamed `-get-group` option to `-get-inventory-id` 18. Update Docker image to Alpine 3.7 19. Require `perl-Digest-SHA` 20. Change license to LGPL-2.1+ ### Bug Fixes 1. Fixed `glxgears` test 2. Do not read monitor vendor names from `pnp.ids` file 3. Remove empty logs from probes 4. Fixed detection of HWid 5. Fixed notebook model names 6. Do not probe for `blkid` (use `lsblk` instead) 7. Do not probe for `mount` (use `findmnt` instead) HW PROBE 1.3 ------------ Released on Dec 3, 2017 (d192aee). ### New Features 1. Docker image for HW Probe to run anywhere 2. Detecting NVMe drives 3. Create offline collections of probes with `-import` option 4. Collecting logs in C.UTF-8 locale 5. Added probes: vulkaninfo, iostat, vainfo, uptime, memtester, cpuinfo, i2cdetect, numactl and lsinitrd 6. Made `-dump-acpi` and `-decode-acpi` public options 7. Improved support for Alpine Linux ### Bug Fixes 1. Fixed detection of computer vendor/model 2. Fixed detection of HWid 3. Fixed collecting of X11 logs 4. Fixed xdpyinfo probe HW PROBE 1.2 ------------ Released on Mar 9, 2017 (c5f178b). 1. Use `ip addr` command to detect hwaddr if `ifconfig` command is not available 2. Fixed `hdparm` and `smartctl` logs HW PROBE 1.1 ------------ Released on Sep 28, 2016 (144b0b7). 1. Use secure HTTPS connection to upload probes 2. Detect release of a Linux distribution 3. Detect real Mac-address 4. Carefully detect devices on board HW PROBE 1.0 ------------ Released on Nov 29, 2015 (4db41d1). This is a first public release of the tool, that was used internally for testing hardware compatibility of Linux distributions since 2014. hw-probe-1.6.2/OBS/000077500000000000000000000000001417672225000136745ustar00rootroot00000000000000hw-probe-1.6.2/OBS/PKGBUILD000066400000000000000000000013361417672225000150230ustar00rootroot00000000000000# Maintainer: Andrey Ponomarenko pkgname=hw-probe pkgver=1.5 pkgrel=1 pkgdesc="Check operability of computer hardware and find drivers" arch=('any') url="https://github.com/linuxhw/hw-probe" license=('LGPLv2.1+') source=("$pkgname-$pkgver.tar.gz") sha256sums=('8bb7d6ff272c1412e26fcfd86e9df5c3e34e1584552404b930c281b8498b25ea') depends=('perl>=5' 'curl' 'perl-libwww' 'hwinfo' 'dmidecode' 'pciutils' 'usbutils' 'smartmontools' 'hdparm' 'net-tools' 'mesa-demos' 'glew' 'lm_sensors' 'lsb-release') optdepends=('acpica' 'sysstat' 'iw' 'ethtool' 'alsa-utils' 'efibootmgr') package() { cd "$srcdir"/$pkgname-$pkgver install -dm755 "$pkgdir"/usr DESTDIR="$pkgdir" make install prefix=/usr } hw-probe-1.6.2/OBS/_service000066400000000000000000000000641417672225000154160ustar00rootroot00000000000000 hw-probe-1.6.2/OBS/appimage.yml000066400000000000000000000207501417672225000162060ustar00rootroot00000000000000app: hw-probe build: packages: - tar - gcc - make - flex - bison - gcc-c++ - automake - Mesa-libGL-devel - glew-devel - glu-devel - libusb-1_0-devel - libudev-devel - libkmod-devel - libuuid-devel - glib2-devel - libXrandr-devel - zlib-devel script: # edid-decode - tar -xf $BUILD_SOURCE_DIR/edid-decode-20200211.tar.xz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/edid-decode-20200211 - sed -i -e 's/ -g / -s /' Makefile - CPPFLAGS='-std=c++0x' make - make install DESTDIR=$BUILD_APPDIR # ddcutil - tar -xf $BUILD_SOURCE_DIR/ddcutil-20200218.tar.xz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/ddcutil-20200218 - ./configure --prefix=/usr ZLIB_LIBS="-lz" - sed -i -e 's/ -g / -s /' Makefile - make - install -D ./src/ddcutil $BUILD_APPDIR/usr/bin/ddcutil # dmidecode - tar -xf $BUILD_SOURCE_DIR/dmidecode-3.2.tar.xz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/dmidecode-3.2 - sed -i -e 's/ -O2/ -s -O2/' Makefile - make - make install prefix=/usr DESTDIR=$BUILD_APPDIR # lm_sensors - tar -xf $BUILD_SOURCE_DIR/lm-sensors-3-6-0.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/lm-sensors-3-6-0 - sed -i -e 's/ -g/ -s/' Makefile - make install BUILD_STATIC_LIB=0 DEBUG=0 PREFIX=/usr DESTDIR=$BUILD_APPDIR # libkmod - tar -xf $BUILD_SOURCE_DIR/kmod-12.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/kmod-12 - ./configure --disable-debug --disable-python --disable-logging --disable-tools --disable-test-modules --disable-manpages --prefix=/usr - sed -i -e 's/ -g / -s /' Makefile - make - make install DESTDIR=$BUILD_APPDIR # usbutils - tar -xf $BUILD_SOURCE_DIR/usbutils-007.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/usbutils-007 - cp -f $BUILD_SOURCE_DIR/usb.ids . - ./configure --prefix=/usr - sed -i -e 's/ -g / -s /' Makefile - make - make install DESTDIR=$BUILD_APPDIR - sed -i -e 's|/usr|././|g' $BUILD_APPDIR/usr/bin/lsusb # pciutils - tar -xf $BUILD_SOURCE_DIR/pciutils-3.6.2.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/pciutils-3.6.2 - cp -f $BUILD_SOURCE_DIR/pci.ids . - make install PREFIX=/usr DESTDIR=$BUILD_APPDIR SHARED=no LIBKMOD=yes HWDB=no ZLIB=no DNS=no - sed -i -e 's|/usr|././|g' $BUILD_APPDIR/usr/sbin/lspci # acpica-unix - tar -xf $BUILD_SOURCE_DIR/acpica-unix-20200110.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/acpica-unix-20200110 - make - make install DESTDIR=$BUILD_APPDIR # hdparm - tar -xf $BUILD_SOURCE_DIR/hdparm-9.58.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/hdparm-9.58 - make - make install DESTDIR=$BUILD_APPDIR # smartmontools - tar -xf $BUILD_SOURCE_DIR/smartmontools-7.1.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/smartmontools-7.1 - NOCONFIGURE=1 NO_CONFIGURE=1 sh autogen.sh - ./configure --with-nvme-devicescan --prefix=/usr - sed -i -e 's/ -g / -s /' Makefile - make - make install DESTDIR=$BUILD_APPDIR # libx86emu - tar -xf $BUILD_SOURCE_DIR/libx86emu-2.4.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/libx86emu-2.4 - echo '2.4' > VERSION - rm -f git2log - sed -i -e 's/ -g / -s /' Makefile - make - make install DESTDIR=$BUILD_APPDIR # mesa-demos - tar -xf $BUILD_SOURCE_DIR/mesa-demos-8.1.0.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/mesa-demos-8.1.0 - ./configure --prefix=/usr - sed -i -e 's/-lGLEW//' Makefile src/xdemos/Makefile - make - cp -fr ./src/xdemos/{glxgears,glxinfo} $BUILD_APPDIR/usr/bin/ # hwinfo - tar -xf $BUILD_SOURCE_DIR/hwinfo-21.68.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/hwinfo-21.68 - echo '21.68' > VERSION - rm -f git2log - sed -i -e 's/ -g / -s /' Makefile.common - CFLAGS="-I$BUILD_APPDIR/usr/include" LDFLAGS="-L$BUILD_APPDIR/usr/lib64 -L$BUILD_APPDIR/usr/lib -lx86emu" LD_LIBRARY_PATH="$BUILD_APPDIR/usr/lib64:$BUILD_APPDIR/usr/lib" make - make install DESTDIR=$BUILD_APPDIR # hw-probe - tar -xf $BUILD_SOURCE_DIR/hw-probe-1.5-AI.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/hw-probe-1.5-AI - make install prefix=$BUILD_APPDIR/usr # create Perl5 directory - mkdir -p $BUILD_APPDIR/usr/lib/perl5 # perl-URI - tar -xf $BUILD_SOURCE_DIR/URI-1.74.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/URI-1.74 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-HTTP-Message - tar -xf $BUILD_SOURCE_DIR/HTTP-Message-6.18.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/HTTP-Message-6.18 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-Net-HTTP - tar -xf $BUILD_SOURCE_DIR/Net-HTTP-6.18.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/Net-HTTP-6.18 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-Try-Tiny - tar -xf $BUILD_SOURCE_DIR/Try-Tiny-0.30.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/Try-Tiny-0.30 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-LWP-MediaTypes - tar -xf $BUILD_SOURCE_DIR/LWP-MediaTypes-6.02.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/LWP-MediaTypes-6.02 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-HTTP-Date - tar -xf $BUILD_SOURCE_DIR/HTTP-Date-6.02.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/HTTP-Date-6.02 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-TimeDate - tar -xf $BUILD_SOURCE_DIR/TimeDate-2.30.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/TimeDate-2.30 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # libwww-perl - tar -xf $BUILD_SOURCE_DIR/libwww-perl-6.35.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/libwww-perl-6.35 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-parent - tar -xf $BUILD_SOURCE_DIR/parent-0.237.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/parent-0.237 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-Time-Local - tar -xf $BUILD_SOURCE_DIR/Time-Local-1.28.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/Time-Local-1.28 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/SITELIB/* $BUILD_APPDIR/usr/lib/perl5/ # perl-Data-Dumper - tar -xf $BUILD_SOURCE_DIR/Data-Dumper-2.161.tar.gz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/Data-Dumper-2.161 - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - cp -fr ./INST/usr/lib/perl5/*/* $BUILD_APPDIR/usr/lib/perl5/ # perl-base - tar -xf $BUILD_SOURCE_DIR/perl-5.28.2.tar.xz -C $BUILD_SOURCE_DIR - cd $BUILD_SOURCE_DIR/perl-5.28.2 - sh Configure -de -Dprefix=/ - sed -i -e 's/ -lnsl / /' Makefile - make - install -D ./perl $BUILD_APPDIR/usr/bin/perl - cd lib && cat $BUILD_SOURCE_DIR/PERL5_BASE | while read i; do mkdir -p $BUILD_APPDIR/usr/lib/perl5/`dirname $i`; cp -fr $i $BUILD_APPDIR/usr/lib/perl5/$i; done # meta info - mkdir -p $BUILD_APPDIR/usr/share/metainfo/ - cp -f $BUILD_SOURCE_DIR/hw-probe.appdata.xml $BUILD_APPDIR/usr/share/metainfo/ - cp -f $BUILD_SOURCE_DIR/hw-probe.desktop $BUILD_APPDIR/ - cp -f $BUILD_SOURCE_DIR/hw-probe.png $BUILD_APPDIR/ # remove unused files - cd $BUILD_APPDIR # header files - rm -fr usr/include # binaries - rm -fr usr/bin/{lsusb.py,acpibin,acpiexamples,acpiexec,acpihelp,acpinames,acpisrc,usbhid-dump,sensors-conf-convert} - rm -fr usr/sbin/{convert_hd,update-usbids.sh,check_hd,mk_isdnhwdb,getsysinfo,fancontrol,pwmconfig,update-pciids,isadump,isaset,ownership,setpci,vpddecode,sensors-detect,update-smart-drivedb,smartd} # configs - rm -fr usr/lib/{pkgconfig,systemd,libkmod.la} - rm -fr usr/lib64/pkgconfig - rm -fr etc/{sensors.d,smartd*,zypp} - rm -fr usr/share/{hwinfo,man,doc,pkgconfig,cmake,ddcutil,smartmontools,usb.ids.gz} - rm -fr usr/etc # other - rm -fr var share usr/man - rm -fr usr/lib/perl5/libwww/*.pod # strip binaries - find . -type f | perl -lne 'print if -B and -x' | xargs strip hw-probe-1.6.2/OBS/debian.changelog000066400000000000000000000004471417672225000167740ustar00rootroot00000000000000hw-probe (1.5-1) stable; urgency=low * Update to 1.5 -- Andrey Ponomarenko Fri, 17 Jan 2020 22:55:00 +0300 hw-probe (1.4-1) stable; urgency=low * Initial Package on OBS -- Andrey Ponomarenko Fri, 20 Jul 2018 16:05:00 +0300hw-probe-1.6.2/OBS/debian.control000066400000000000000000000033101417672225000165150ustar00rootroot00000000000000Source: hw-probe Section: utils Priority: optional Maintainer: Andrey Ponomarenko Build-Depends: debhelper (>=9), perl-base (>=5) Standards-Version: 3.9.6 Homepage: https://github.com/linuxhw/hw-probe Package: hw-probe Architecture: all Depends: perl-base (>=5), libwww-perl, libdigest-sha-perl, curl, hwinfo, dmidecode, pciutils, usbutils, smartmontools, hdparm, lm-sensors, x11-utils, mesa-utils, lsb-release, acpica-tools Recommends: mcelog, edid-decode, memtester, pnputils, sysstat, upower, fdisk, alsa-utils, cpuid, ethtool, i2c-tools, wireless-tools, iw, vainfo, vdpauinfo, vulkan-utils, x11-xserver-utils, xinput Description: Check operability of computer hardware and find drivers A tool to check operability of computer hardware and upload result to the Linux hardware database. . Probe — is a snapshot of your computer hardware state and system logs. The tool checks operability of devices by analysis of logs and returns a permanent url to view the probe of the computer. . The tool is intended to simplify collecting of logs necessary for investigating hardware related problems. Just run one simple command in the console to check your hardware and collect all the system logs at once: . sudo -E hw-probe -all -upload . By creating probes you contribute to the HDD/SSD Desktop-Class Reliability Test study: https://github.com/linuxhw/SMARThw-probe-1.6.2/OBS/debian.rules000066400000000000000000000001521417672225000161700ustar00rootroot00000000000000#!/usr/bin/make -f DH_VERBOSE = 1 DPKG_EXPORT_BUILDFLAGS = 1 include /usr/share/dpkg/default.mk %: dh $@ hw-probe-1.6.2/OBS/hw-probe.appdata.xml000066400000000000000000000042521417672225000175550ustar00rootroot00000000000000 org.linux_hardware.hw-probe CC-BY-3.0 LGPL-2.1+ Hardware Probe Check operability of computer hardware and find drivers Linux Hardware Project

A tool to probe for hardware, check operability and find drivers with the help of Linux Hardware Database.

Probe — is a snapshot of your computer hardware state. The tool checks operability of devices by analysis of logs and returns a permanent url to view the probe of the computer.

The probes are intended to simplify collecting of logs necessary for investigating hardware related problems. Just run one simple command to check hardware and collect all the system logs at once:

sudo -E hw-probe -all -upload

If some of hardware devices don't work due to a missed driver then the tool will suggest a proper Linux kernel version according to the LKDDb or third-party drivers.

By creating a probe, you contribute to the HDD/SSD desktop-class reliability study: https://github.com/linuxhw/SMART

Private info is not collected.

System org.linux_hardware.hw-probe.desktop https://github.com/linuxhw/build-stuff/releases/download/1.4/image-2.png https://github.com/linuxhw/build-stuff/releases/download/1.4/image-3.png https://github.com/linuxhw/build-stuff/releases/download/1.4/image-1.png https://github.com/linuxhw/hw-probe Linux Hardware hw-probe
hw-probe-1.6.2/OBS/hw-probe.desktop000066400000000000000000000003571417672225000170170ustar00rootroot00000000000000[Desktop Entry] Name=Hardware Probe Comment=Probe for hardware, check operability and find drivers Exec=hw-probe -appimage Icon=hw-probe Terminal=true Type=Application StartupNotify=true Categories=System; Keywords=HW Probe;Hardware;Probe;hw-probe-1.6.2/OBS/hw-probe.dsc000066400000000000000000000004331417672225000161120ustar00rootroot00000000000000Format: 1.0 Source: hw-probe Version: 1.5-1 Binary: hw-probe Maintainer: Andrey Ponomarenko Architecture: any Build-Depends: debhelper (>= 4.1.16) DEBTRANSFORM-TAR: hw-probe-1.5.tar.gz Files: d4c886e88ec13c245d6d45c88d2f0b80 113996 hw-probe-1.5.tar.gzhw-probe-1.6.2/OBS/hw-probe.spec000066400000000000000000000034161417672225000162770ustar00rootroot00000000000000Summary: Check operability of computer hardware and find drivers Name: hw-probe Version: 1.5 Release: 1 Group: Development/Other BuildArch: noarch License: LGPLv2.1+ URL: https://github.com/linuxhw/hw-probe Source0: hw-probe-%{version}.tar.gz Requires: perl Requires: perl-libwww-perl Requires: curl Requires: hwinfo Requires: dmidecode Requires: pciutils Requires: usbutils Requires: smartmontools Requires: hdparm Requires: sysstat Requires: util-linux %ifarch %ix86 x86_64 Requires: mcelog %endif %if 0%{?suse_version} || 0%{?sle_version} Requires: sensors Requires: lsb-release Requires: Mesa-demo-x Requires: acpica %endif %if 0%{?fedora} Requires: lm_sensors Requires: redhat-lsb-core Requires: mesa-demos Requires: acpica-tools %endif %define debug_package %{nil} %description A tool to check operability of computer hardware and upload result to the Linux hardware database. Probe — is a snapshot of your computer hardware state and system logs. The tool checks operability of devices by analysis of logs and returns a permanent url to view the probe of the computer. The tool is intended to simplify collecting of logs necessary for investigating hardware related problems. Just run one simple command in the console to check your hardware and collect all the system logs at once: sudo -E hw-probe -all -upload By creating probes you contribute to the HDD/SSD Desktop-Class Reliability Test study: https://github.com/linuxhw/SMART %prep %setup -q -n hw-probe-%{version} chmod 0644 README.md %build # Nothing to build yet %install mkdir -p %{buildroot}%{_prefix} make install prefix=%{_prefix} DESTDIR=%{buildroot} %clean rm -rf %{buildroot} %files %defattr(-,root,root,-) %doc README.md %{_bindir}/%{name} hw-probe-1.6.2/README.md000066400000000000000000000303161417672225000145330ustar00rootroot00000000000000HW PROBE 1.6 ============ Hardware Probe Tool (hw-probe) — a tool to probe for hardware, check operability and find drivers with the help of Linux hardware database: https://linux-hardware.org For BSD users: https://bsd-hardware.info Contents -------- * [ About ](#about) * [ Install ](#install) * [ Usage ](#usage) * [ Review ](#review) * [ AppImage ](#appimage) * [ Docker ](#docker) * [ Live CD/USB ](#live-cd) * [ Snap ](#snap) * [ Flatpak ](#flatpak) * [ Inventory ](#inventory) * [ Monitoring ](#monitoring) * [ Periodic run ](#periodic-run) * [ Offline view ](#offline-view) * [ ACPI dump ](#acpi-dump) * [ Operability ](#operability) * [ Disable logs ](#disable-logs) * [ Privacy ](#privacy) * [ License ](#license) About ----- Probe — is a snapshot of your computer's hardware state and logs. The tool checks operability of devices by analysis of logs and returns a permanent url to view the probe of the computer. Share your probes and logs with Linux/BSD developers in order to debug and fix problems on your computer. Simplify inventory of hardware in your company. Please read more in [our blog](https://github.com/linuxhw/Blog/blob/master/Linux_Hardware_Blog.pdf). If some of your computer devices doesn't work due to a missed driver then the tool will suggest a proper Linux kernel version according to the LKDDb or third-party drivers. Sample probe: https://linux-hardware.org/?probe=b394035f90 You can create a probe of your computer with the help of [AppImage](#appimage), [Docker](#docker), [Snap](#snap), [Flatpak](#flatpak), [Live CD/USB](#live-cd) or RPM/Deb package. By creating probes you contribute to the "HDD/SSD Desktop-Class Reliability Test" study: https://github.com/linuxhw/SMART Install ------- You can probe your computer by [AppImage](#appimage), [Docker](#docker), [Snap](#snap), [Flatpak](#flatpak) or [Live CD/USB](#live-cd). Also you can install a native package (RPM, Deb, Pkg, etc.) for your Linux distribution or install from source. See install instructions in the [INSTALL.md](INSTALL.md) file. See install instructions for BSD in the [INSTALL.BSD.md](INSTALL.BSD.md) file. Usage ----- Create a probe: sudo -E hw-probe -all -upload Review ------ You can adjust device statuses in your probe and leave comments. Look for big green REVIEW button on the probe page. Look for **'Export template to forum'** link at the bottom of the probe page to generate BBCode review template to post on your favorite forum. Please consider to post your reviews to [Linux Hardware Review](https://forum.linux-hardware.org/) forum. AppImage -------- The portable app that runs anywhere, no need to install anything. Just download [hw-probe-1.5-149-x86_64.AppImage](https://github.com/linuxhw/hw-probe/releases/download/1.5/hw-probe-1.5-149-x86_64.AppImage) and run the following command in terminal to probe your computer: chmod +x ./hw-probe-1.5-149-x86_64.AppImage sudo -E ./hw-probe-1.5-149-x86_64.AppImage -all -upload You may need to install `fuse-libs` or `libfuse2` package if it is not pre-installed in your Linux distribution to run appimages. Also try [old AppImage](https://github.com/linuxhw/hw-probe/releases/download/1.4/hw-probe-1.4-135-x86_64.AppImage) if you have troubles to run the latest image (e.g. on ancient Linux versions). ###### Supported systems The app runs on all 64-bit Linux distributions with `Glibc >= 2.14` including: * Ubuntu 12.04 and newer * Linux Mint 13 and newer * Debian 8 and newer * openSUSE 12.0 and newer * Manjaro 0.8 and newer * MX Linux 14 and newer * ROSA Linux R1 and newer * elementary OS 0.2 and newer * Fedora 15 and newer (need to add `fuse-libs` package on Fedora 15, 16 and 17) * RHEL 7 and newer * CentOS 7 and newer * Solus 3 and newer * Puppy Linux 6.0 and newer (Tahr64, XenialPup64, BionicPup64, etc.) * Clear Linux of any version * Arch Linux of any version * EndeavourOS 2019 and newer * Pop!_OS 17 and newer * Mageia 2 and newer * Alt Linux 7 and newer * Gentoo 12 and newer * Sabayon 13 and newer * Slackware 14.2 and newer * OpenMandriva 3.0 and newer Docker ------ You can easily create a probe on any Linux distribution without installing the tool with the help of the Docker image: sudo -E docker run -it \ -v /dev:/dev:ro \ -v /lib/modules:/lib/modules:ro \ -v /etc/os-release:/etc/os-release:ro \ -v /var/log:/var/log:ro \ --privileged --net=host --pid=host \ linuxhw/hw-probe -all -upload You may need to run `xhost +local:` before docker run to collect X11 info (xrandr, xinput, etc.). Docker hub repository: https://hub.docker.com/r/linuxhw/hw-probe/ Live CD ------- If the tool is not pre-installed in your system or you have troubles with installing the tool or its dependencies (e.g. hwinfo is not available in the repository) then try one of the following Live images with hw-probe pre-installed: [Debian](https://cdimage.debian.org/debian-cd/current-live/amd64/iso-hybrid/), [ArcoLinux](https://sourceforge.net/projects/arcolinux-community-editions/files/) or [OpenMandriva](https://sourceforge.net/projects/openmandriva/files/release/). Write the image to USB or CD drive, boot from it on your computer and create a probe (see [Usage](#usage)). Snap ---- Install the universal Linux package: sudo snap install hw-probe The `hw-probe` command should become available on the command line after installation. If not, try: export PATH=$PATH:/snap/bin Connect `block-devices` interface to check SMART attributes of drives: sudo snap connect hw-probe:block-devices :block-devices Now you can create computer probes: sudo -E hw-probe -all -upload Note: You need a Snap runtime (`snapd` package) and `/snap` symlink to `/var/lib/snapd/snap` (by `sudo ln -s /var/lib/snapd/snap /snap`) in your system to install and run snaps (pre-installed on Ubuntu 16.04 and newer). ###### Snap Store The app is available in the Snap Store: https://snapcraft.io/hw-probe This is a strict snap that runs in a sandbox with limited functionality. Please enable `Access to disk block devices` in `Permissions` in order to check SMART attributes of your drives. ###### Supported systems See list of supported Linux distributions and installation instructions here: https://snapcraft.io/docs/installing-snapd The list of supported Linux distributions includes: * Ubuntu 14.04 and newer * Debian 9 and newer * Fedora 26 and newer * Solus 3 and newer * Zorin 12.3 and newer Flatpak ------- Add a remote: flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo Install universal package: flatpak install flathub org.linux_hardware.hw-probe Now you can create computer probes: flatpak run org.linux_hardware.hw-probe -all -upload Run it as root if you want to check your hard drives health. ###### App Center Find the `Hardware Probe` application in your App Center (GNOME Software), install it and click on the desktop icon to create a probe. Enable Flatpak plugin (`gnome-software-plugin-flatpak` package for Debian/Ubuntu) and install https://dl.flathub.org/repo/flathub.flatpakrepo if needed. ![image](https://user-images.githubusercontent.com/2480569/103484839-12564480-4df2-11eb-8c57-d6ee6ef48e2b.png) ###### Flathub The app is available in the Flathub: https://flathub.org/apps/details/org.linux_hardware.hw-probe ###### Supported systems Out of the box: * Endless OS 3 and newer * Linux Mint 18.3 and newer * Fedora 27 and newer * CentOS 7.6 GNOME and newer * Pop!_OS 20.04 and newer Need to setup Flatpak (https://flatpak.org/setup/): * elementary OS 5 and newer * Pop!_OS 18.04 and newer * Solus 3 and newer * Clear Linux of any version * Mageia 6 and newer * openSUSE Leap 15 and newer * RHEL 7.6 and newer * Arch Linux * Chrome OS Inventory --------- Since hw-probe 1.5. Request inventory ID: hw-probe -generate-inventory -email YOUR@EMAIL Mark your probes by this ID: sudo -E hw-probe -all -upload -i ID Find your computers by the inventory ID on this page: https://linux-hardware.org/?view=computers The Email is needed to get notifications if hardware failures are detected on your computer in future probes. Monitoring ---------- LHWM — Linux Hardware Monitoring (c) allows you to monitor most kinds of hardware-related changes (operating system failures, configuration changes and degradation of hardware components) on all your Linux servers or personal stations with E-mail notifications. The service protects your cluster from unexpected hardware failures by regular hardware probing and monitoring of system logs for failures with the help of the Linux-Hardware.org knowledge base. All you need is to generate your personal [inventory ID](#inventory) (if you don't have it yet) and start monitoring of each server by one simple command line: sudo -E hw-probe -start -i INVENTORY_ID The command will add a daily cron job to make a probe of the server and you'll be notified by E-mail in the case of hardware failures or important hardware-related changes detected. Periodic run ------------ If your distribuition is running under systemd and you want to generate and upload hw-probe report periodically, please install: cp -a periodic/hw-probe.{service,timer} $(systemdsystemunitdir)/ Normally systemd units dir is located at `/usr/lib/systemd/system`. You may want to get systemd unit dir by running `pkg-config --variable=systemdsystemunitdir systemd` Enable hw-probe.timer by running: systemctl enable --now hw-probe.timer This timer will execute one time per month a hw-probe.service that will generate and upload report to the database. User may edit hw-probe.timer and change OnCalendar value to execute hw-probe report on different time period (yearly, semiannually, quarterly, etc.). Values lower than month are STRONGLY not recommended. Offline view ------------ Since hw-probe 1.5. Save your probes HTML view to a directory DIR for offline use: hw-probe -import ./DIR -inventory-id ID ACPI dump --------- Dump and decode ACPI table: sudo -E hw-probe -all -upload -dump-acpi -decode-acpi NOTE: `acpica-tools` package should be installed Operability ----------- The tool checks operability of devices on board by analysis of collected log files. | Status | Meaning | |----------|---------| | works | Driver is found and operates properly (passed static or dynamic tests) | | limited | Works, but with limited functionality | | fixed* | Works, fixed by user | | detected | Device is detected, driver is found, but not tested yet | | failed | Driver is not found or device is broken | | malfunc | Error operation of the device or driver | *The 'fixed' status is manually assigned by users during [probe review](#review). You can perform additional operability sanity tests by the following command: sudo -E hw-probe -all -check -upload The following tests are executed: * graphics test by `glxgears` for both integrated and discrete graphics cards (requires `mesa-demos` package to be installed) * drive read speed test by `hdparm` for all HDDs and SSDs * CPU performance test by `dd` and `md5sum` * RAM memory test by `memtester` Execution time is about 1 min for average modern desktop hardware. You can execute particular tests using appropriate options: `-check-graphics`, `-check-hdd`, `-check-cpu` and `-check-memory`. Disable logs ------------ You can disable collecting of unwanted logs by the `-disable A,B,C,...` option. For example, to disable collecting of `xdpyinfo` and `xorg.conf` run: sudo -E hw-probe -all -upload -disable xdpyinfo,xorg.conf Privacy ------- We do our best to decorate all private information (including the username, machine's hostname, IP addresses, MAC addresses, UUIDs and serial numbers) before uploading to the database. Be aware that this may fail in certain edge cases. The tool uploads 32-byte prefix of salted SHA512 hash of MAC addresses and serial numbers to properly identify unique computers and hard drives. UUIDs are decorated in the same way, but formatted like regular UUIDs in order to save readability of logs. All the data is uploaded securely via HTTPS. License ------- This work is dual-licensed under LGPL 2.1 (or any later version) and BSD-4-Clause. You can choose between one of them if you use this work. `SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-4-Clause` Enjoy! hw-probe-1.6.2/flatpak/000077500000000000000000000000001417672225000146735ustar00rootroot00000000000000hw-probe-1.6.2/flatpak/PERL5_BASE000066400000000000000000000242631417672225000162460ustar00rootroot00000000000000./attributes.pm ./auto/attributes/attributes.so ./auto/Cwd/Cwd.so ./auto/Fcntl/Fcntl.so ./auto/File/Glob/Glob.so ./auto/Hash/Util/Util.so ./auto/IO/IO.so ./auto/List/Util/Util.so ./AutoLoader.pm ./auto/POSIX/POSIX.so ./auto/re/re.so ./auto/Socket/Socket.so ./base.pm ./bytes_heavy.pl ./bytes.pm ./Carp/Heavy.pm ./Carp.pm ./Config_git.pl ./Config_heavy.pl ./Config.pm ./constant.pm ./Cwd.pm ./DynaLoader.pm ./Errno.pm ./Exporter/Heavy.pm ./Exporter.pm ./Fcntl.pm ./feature.pm ./fields.pm ./File/Basename.pm ./File/Copy.pm ./File/Glob.pm ./FileHandle.pm ./File/Path.pm ./File/Spec.pm ./File/Spec/Unix.pm ./File/Temp.pm ./Getopt/Long.pm ./Hash/Util.pm ./integer.pm ./IO/File.pm ./IO/Handle.pm ./IO/Pipe.pm ./IO.pm ./IO/Seekable.pm ./IO/Select.pm ./IO/Socket/INET.pm ./IO/Socket/IP.pm ./IO/Socket.pm ./IO/Socket/UNIX.pm ./IPC/Open2.pm ./IPC/Open3.pm ./lib.pm ./List/Util.pm ./locale.pm ./overloading.pm ./overload.pm ./parent.pm ./POSIX.pm ./re.pm ./Scalar/Util.pm ./SelectSaver.pm ./Socket.pm ./strict.pm ./Symbol.pm ./Text/ParseWords.pm ./Text/Tabs.pm ./Text/Wrap.pm ./Tie/Hash.pm ./unicore/Heavy.pl ./unicore/lib/Age/NA.pl ./unicore/lib/Age/V11.pl ./unicore/lib/Age/V20.pl ./unicore/lib/Age/V30.pl ./unicore/lib/Age/V31.pl ./unicore/lib/Age/V32.pl ./unicore/lib/Age/V40.pl ./unicore/lib/Age/V41.pl ./unicore/lib/Age/V50.pl ./unicore/lib/Age/V51.pl ./unicore/lib/Age/V52.pl ./unicore/lib/Age/V60.pl ./unicore/lib/Age/V61.pl ./unicore/lib/Age/V70.pl ./unicore/lib/Alpha/Y.pl ./unicore/lib/Bc/AL.pl ./unicore/lib/Bc/AN.pl ./unicore/lib/Bc/BN.pl ./unicore/lib/Bc/B.pl ./unicore/lib/Bc/CS.pl ./unicore/lib/Bc/EN.pl ./unicore/lib/Bc/ES.pl ./unicore/lib/Bc/ET.pl ./unicore/lib/Bc/L.pl ./unicore/lib/Bc/NSM.pl ./unicore/lib/Bc/ON.pl ./unicore/lib/Bc/R.pl ./unicore/lib/Bc/WS.pl ./unicore/lib/BidiC/Y.pl ./unicore/lib/BidiM/Y.pl ./unicore/lib/Blk/NB.pl ./unicore/lib/Bpt/C.pl ./unicore/lib/Bpt/N.pl ./unicore/lib/Bpt/O.pl ./unicore/lib/Cased/Y.pl ./unicore/lib/Ccc/A.pl ./unicore/lib/Ccc/AR.pl ./unicore/lib/Ccc/ATAR.pl ./unicore/lib/Ccc/B.pl ./unicore/lib/Ccc/BR.pl ./unicore/lib/Ccc/DB.pl ./unicore/lib/Ccc/NK.pl ./unicore/lib/Ccc/NR.pl ./unicore/lib/Ccc/OV.pl ./unicore/lib/Ccc/VR.pl ./unicore/lib/CE/Y.pl ./unicore/lib/CI/Y.pl ./unicore/lib/CompEx/Y.pl ./unicore/lib/CWCF/Y.pl ./unicore/lib/CWCM/Y.pl ./unicore/lib/CWKCF/Y.pl ./unicore/lib/CWL/Y.pl ./unicore/lib/CWT/Y.pl ./unicore/lib/CWU/Y.pl ./unicore/lib/Dash/Y.pl ./unicore/lib/Dep/Y.pl ./unicore/lib/Dia/Y.pl ./unicore/lib/DI/Y.pl ./unicore/lib/Dt/Com.pl ./unicore/lib/Dt/Enc.pl ./unicore/lib/Dt/Fin.pl ./unicore/lib/Dt/Font.pl ./unicore/lib/Dt/Init.pl ./unicore/lib/Dt/Iso.pl ./unicore/lib/Dt/Med.pl ./unicore/lib/Dt/Nar.pl ./unicore/lib/Dt/Nb.pl ./unicore/lib/Dt/NonCanon.pl ./unicore/lib/Dt/Sqr.pl ./unicore/lib/Dt/Sub.pl ./unicore/lib/Dt/Sup.pl ./unicore/lib/Dt/Vert.pl ./unicore/lib/Ea/A.pl ./unicore/lib/Ea/H.pl ./unicore/lib/Ea/Na.pl ./unicore/lib/Ea/N.pl ./unicore/lib/Ea/W.pl ./unicore/lib/Ext/Y.pl ./unicore/lib/GCB/CN.pl ./unicore/lib/GCB/EX.pl ./unicore/lib/GCB/LV.pl ./unicore/lib/GCB/LVT.pl ./unicore/lib/GCB/SM.pl ./unicore/lib/GCB/XX.pl ./unicore/lib/Gc/Cf.pl ./unicore/lib/Gc/Cn.pl ./unicore/lib/Gc/C.pl ./unicore/lib/Gc/LC.pl ./unicore/lib/Gc/Ll.pl ./unicore/lib/Gc/Lm.pl ./unicore/lib/Gc/Lo.pl ./unicore/lib/Gc/L.pl ./unicore/lib/Gc/Lu.pl ./unicore/lib/Gc/Mc.pl ./unicore/lib/Gc/Me.pl ./unicore/lib/Gc/Mn.pl ./unicore/lib/Gc/M.pl ./unicore/lib/Gc/Nd.pl ./unicore/lib/Gc/Nl.pl ./unicore/lib/Gc/No.pl ./unicore/lib/Gc/N.pl ./unicore/lib/Gc/Pd.pl ./unicore/lib/Gc/Pe.pl ./unicore/lib/Gc/Pf.pl ./unicore/lib/Gc/Pi.pl ./unicore/lib/Gc/Po.pl ./unicore/lib/Gc/P.pl ./unicore/lib/Gc/Ps.pl ./unicore/lib/Gc/Sc.pl ./unicore/lib/Gc/Sk.pl ./unicore/lib/Gc/Sm.pl ./unicore/lib/Gc/So.pl ./unicore/lib/Gc/S.pl ./unicore/lib/Gc/Z.pl ./unicore/lib/Gc/Zs.pl ./unicore/lib/GrBase/Y.pl ./unicore/lib/Hex/Y.pl ./unicore/lib/Hst/NA.pl ./unicore/lib/IDC/Y.pl ./unicore/lib/Ideo/Y.pl ./unicore/lib/IDS/Y.pl ./unicore/lib/In/2_0.pl ./unicore/lib/In/2_1.pl ./unicore/lib/In/3_0.pl ./unicore/lib/In/3_1.pl ./unicore/lib/In/3_2.pl ./unicore/lib/In/4_0.pl ./unicore/lib/In/4_1.pl ./unicore/lib/In/5_0.pl ./unicore/lib/In/5_1.pl ./unicore/lib/In/5_2.pl ./unicore/lib/In/6_0.pl ./unicore/lib/In/6_1.pl ./unicore/lib/In/6_2.pl ./unicore/lib/In/6_3.pl ./unicore/lib/In/7_0.pl ./unicore/lib/Jg/Ain.pl ./unicore/lib/Jg/Alef.pl ./unicore/lib/Jg/Beh.pl ./unicore/lib/Jg/Dal.pl ./unicore/lib/Jg/FarsiYeh.pl ./unicore/lib/Jg/Feh.pl ./unicore/lib/Jg/Gaf.pl ./unicore/lib/Jg/Hah.pl ./unicore/lib/Jg/Lam.pl ./unicore/lib/Jg/NoJoinin.pl ./unicore/lib/Jg/Qaf.pl ./unicore/lib/Jg/Reh.pl ./unicore/lib/Jg/Sad.pl ./unicore/lib/Jg/Seen.pl ./unicore/lib/Jg/Waw.pl ./unicore/lib/Jg/Yeh.pl ./unicore/lib/Jt/C.pl ./unicore/lib/Jt/D.pl ./unicore/lib/Jt/R.pl ./unicore/lib/Jt/T.pl ./unicore/lib/Jt/U.pl ./unicore/lib/Lb/AI.pl ./unicore/lib/Lb/AL.pl ./unicore/lib/Lb/BA.pl ./unicore/lib/Lb/BB.pl ./unicore/lib/Lb/CJ.pl ./unicore/lib/Lb/CL.pl ./unicore/lib/Lb/CM.pl ./unicore/lib/Lb/EX.pl ./unicore/lib/Lb/GL.pl ./unicore/lib/Lb/ID.pl ./unicore/lib/Lb/IS.pl ./unicore/lib/Lb/NS.pl ./unicore/lib/Lb/OP.pl ./unicore/lib/Lb/PO.pl ./unicore/lib/Lb/PR.pl ./unicore/lib/Lb/QU.pl ./unicore/lib/Lb/SA.pl ./unicore/lib/Lb/XX.pl ./unicore/lib/Lower/Y.pl ./unicore/lib/Math/Y.pl ./unicore/lib/NFCQC/M.pl ./unicore/lib/NFCQC/Y.pl ./unicore/lib/NFDQC/N.pl ./unicore/lib/NFDQC/Y.pl ./unicore/lib/NFKCQC/N.pl ./unicore/lib/NFKCQC/Y.pl ./unicore/lib/NFKDQC/N.pl ./unicore/lib/NFKDQC/Y.pl ./unicore/lib/Nt/Di.pl ./unicore/lib/Nt/None.pl ./unicore/lib/Nt/Nu.pl ./unicore/lib/Nv/0.pl ./unicore/lib/Nv/10000.pl ./unicore/lib/Nv/1000.pl ./unicore/lib/Nv/100.pl ./unicore/lib/Nv/10.pl ./unicore/lib/Nv/11.pl ./unicore/lib/Nv/1_2.pl ./unicore/lib/Nv/12.pl ./unicore/lib/Nv/1_3.pl ./unicore/lib/Nv/13.pl ./unicore/lib/Nv/1_4.pl ./unicore/lib/Nv/14.pl ./unicore/lib/Nv/15.pl ./unicore/lib/Nv/16.pl ./unicore/lib/Nv/17.pl ./unicore/lib/Nv/1_8.pl ./unicore/lib/Nv/18.pl ./unicore/lib/Nv/19.pl ./unicore/lib/Nv/1.pl ./unicore/lib/Nv/20.pl ./unicore/lib/Nv/2_3.pl ./unicore/lib/Nv/2.pl ./unicore/lib/Nv/300.pl ./unicore/lib/Nv/30.pl ./unicore/lib/Nv/3_4.pl ./unicore/lib/Nv/3.pl ./unicore/lib/Nv/40.pl ./unicore/lib/Nv/4.pl ./unicore/lib/Nv/50000.pl ./unicore/lib/Nv/5000.pl ./unicore/lib/Nv/500.pl ./unicore/lib/Nv/50.pl ./unicore/lib/Nv/5.pl ./unicore/lib/Nv/60.pl ./unicore/lib/Nv/6.pl ./unicore/lib/Nv/70.pl ./unicore/lib/Nv/7.pl ./unicore/lib/Nv/80.pl ./unicore/lib/Nv/8.pl ./unicore/lib/Nv/900.pl ./unicore/lib/Nv/90.pl ./unicore/lib/Nv/9.pl ./unicore/lib/PatSyn/Y.pl ./unicore/lib/Perl/Alnum.pl ./unicore/lib/Perl/Assigned.pl ./unicore/lib/Perl/Blank.pl ./unicore/lib/Perl/Graph.pl ./unicore/lib/Perl/_PerlAny.pl ./unicore/lib/Perl/_PerlCh2.pl ./unicore/lib/Perl/_PerlCha.pl ./unicore/lib/Perl/_PerlFol.pl ./unicore/lib/Perl/_PerlIDC.pl ./unicore/lib/Perl/_PerlIDS.pl ./unicore/lib/Perl/_PerlPr2.pl ./unicore/lib/Perl/_PerlPro.pl ./unicore/lib/Perl/_PerlQuo.pl ./unicore/lib/Perl/PerlWord.pl ./unicore/lib/Perl/PosixPun.pl ./unicore/lib/Perl/Print.pl ./unicore/lib/Perl/SpacePer.pl ./unicore/lib/Perl/Title.pl ./unicore/lib/Perl/Word.pl ./unicore/lib/Perl/XPosixPu.pl ./unicore/lib/QMark/Y.pl ./unicore/lib/SB/AT.pl ./unicore/lib/SB/CL.pl ./unicore/lib/SB/EX.pl ./unicore/lib/SB/FO.pl ./unicore/lib/SB/LE.pl ./unicore/lib/SB/LO.pl ./unicore/lib/SB/NU.pl ./unicore/lib/SB/SC.pl ./unicore/lib/SB/Sp.pl ./unicore/lib/SB/ST.pl ./unicore/lib/SB/UP.pl ./unicore/lib/SB/XX.pl ./unicore/lib/Sc/Arab.pl ./unicore/lib/Sc/Armn.pl ./unicore/lib/Sc/Beng.pl ./unicore/lib/Sc/Cprt.pl ./unicore/lib/Sc/Cyrl.pl ./unicore/lib/Sc/Deva.pl ./unicore/lib/Sc/Dupl.pl ./unicore/lib/Sc/Geor.pl ./unicore/lib/Sc/Gran.pl ./unicore/lib/Sc/Grek.pl ./unicore/lib/Sc/Gujr.pl ./unicore/lib/Sc/Guru.pl ./unicore/lib/Sc/Hang.pl ./unicore/lib/Sc/Han.pl ./unicore/lib/Sc/Hira.pl ./unicore/lib/Sc/Kana.pl ./unicore/lib/Sc/Knda.pl ./unicore/lib/Sc/Latn.pl ./unicore/lib/Sc/Limb.pl ./unicore/lib/Sc/Linb.pl ./unicore/lib/Sc/Mlym.pl ./unicore/lib/Sc/Mong.pl ./unicore/lib/Sc/Orya.pl ./unicore/lib/Sc/Sinh.pl ./unicore/lib/Sc/Taml.pl ./unicore/lib/Sc/Telu.pl ./unicore/lib/Scx/Arab.pl ./unicore/lib/Scx/Armn.pl ./unicore/lib/Scx/Beng.pl ./unicore/lib/Scx/Bopo.pl ./unicore/lib/Scx/Cakm.pl ./unicore/lib/Scx/Copt.pl ./unicore/lib/Scx/Cprt.pl ./unicore/lib/Scx/Cyrl.pl ./unicore/lib/Scx/Deva.pl ./unicore/lib/Scx/Dupl.pl ./unicore/lib/Scx/Geor.pl ./unicore/lib/Scx/Gran.pl ./unicore/lib/Scx/Grek.pl ./unicore/lib/Scx/Gujr.pl ./unicore/lib/Scx/Guru.pl ./unicore/lib/Scx/Hang.pl ./unicore/lib/Scx/Han.pl ./unicore/lib/Scx/Hira.pl ./unicore/lib/Scx/Kana.pl ./unicore/lib/Scx/Knda.pl ./unicore/lib/Scx/Latn.pl ./unicore/lib/Scx/Limb.pl ./unicore/lib/Scx/Linb.pl ./unicore/lib/Scx/Mlym.pl ./unicore/lib/Scx/Mong.pl ./unicore/lib/Scx/Mymr.pl ./unicore/lib/Scx/Orya.pl ./unicore/lib/Scx/Phlp.pl ./unicore/lib/Scx/Sind.pl ./unicore/lib/Scx/Sinh.pl ./unicore/lib/Scx/Syrc.pl ./unicore/lib/Scx/Tagb.pl ./unicore/lib/Scx/Takr.pl ./unicore/lib/Scx/Taml.pl ./unicore/lib/Scx/Telu.pl ./unicore/lib/Scx/Thaa.pl ./unicore/lib/Scx/Tirh.pl ./unicore/lib/Scx/Yi.pl ./unicore/lib/Scx/Zinh.pl ./unicore/lib/Scx/Zyyy.pl ./unicore/lib/Sc/Zinh.pl ./unicore/lib/Sc/Zyyy.pl ./unicore/lib/SD/Y.pl ./unicore/lib/STerm/Y.pl ./unicore/lib/Term/Y.pl ./unicore/lib/UIdeo/Y.pl ./unicore/lib/Upper/Y.pl ./unicore/lib/WB/EX.pl ./unicore/lib/WB/FO.pl ./unicore/lib/WB/HL.pl ./unicore/lib/WB/KA.pl ./unicore/lib/WB/LE.pl ./unicore/lib/WB/MB.pl ./unicore/lib/WB/ML.pl ./unicore/lib/WB/MN.pl ./unicore/lib/WB/NU.pl ./unicore/lib/WB/XX.pl ./unicore/lib/XIDC/Y.pl ./unicore/lib/XIDS/Y.pl ./unicore/To/Age.pl ./unicore/To/Bc.pl ./unicore/To/Bmg.pl ./unicore/To/Bpb.pl ./unicore/To/Bpt.pl ./unicore/To/Cf.pl ./unicore/To/Digit.pl ./unicore/To/Ea.pl ./unicore/To/Fold.pl ./unicore/To/GCB.pl ./unicore/To/Gc.pl ./unicore/To/Hst.pl ./unicore/To/Isc.pl ./unicore/To/Jg.pl ./unicore/To/Jt.pl ./unicore/To/Lb.pl ./unicore/To/Lc.pl ./unicore/To/Lower.pl ./unicore/To/Na1.pl ./unicore/To/NameAlia.pl ./unicore/To/NFCQC.pl ./unicore/To/NFDQC.pl ./unicore/To/NFKCCF.pl ./unicore/To/NFKCQC.pl ./unicore/To/NFKDQC.pl ./unicore/To/Nt.pl ./unicore/To/Nv.pl ./unicore/To/PerlDeci.pl ./unicore/To/SB.pl ./unicore/To/Sc.pl ./unicore/To/Scx.pl ./unicore/To/Tc.pl ./unicore/To/Title.pl ./unicore/To/Uc.pl ./unicore/To/Upper.pl ./unicore/To/WB.pl ./utf8_heavy.pl ./utf8.pm ./vars.pm ./warnings.pm ./warnings/register.pm ./XSLoader.pm hw-probe-1.6.2/flatpak/hw-probe.appdata.xml000066400000000000000000000045551417672225000205620ustar00rootroot00000000000000 org.linux_hardware.hw-probe CC-BY-3.0 BSD-2-Clause Hardware Probe Check operability of computer hardware and find drivers Linux Hardware Project

A tool to probe for hardware, check operability and find drivers with the help of Linux Hardware Database.

Probe — is a snapshot of your computer hardware state. The tool checks operability of devices by analysis of logs, uploads anonymized hardware info to the database and returns a permanent url to view the probe of the computer:

flatpak run org.linux_hardware.hw-probe -all -upload

Run as root if you want to check health of all your hard drives.

If some of hardware devices doesn't work due to a missed driver then the tool will suggest a proper Linux kernel version according to the LKDDb or third-party drivers.

System Utility org.linux_hardware.hw-probe.desktop https://github.com/linuxhw/build-stuff/releases/download/1.4/image-2.png https://github.com/linuxhw/build-stuff/releases/download/1.6/image-4.png https://github.com/linuxhw/build-stuff/releases/download/1.4/image-3.png https://github.com/linuxhw/build-stuff/releases/download/1.4/image-1.png https://github.com/linuxhw/hw-probe hw-probe Hardware Probe Tool 1.6 https://github.com/linuxhw/hw-probe/blob/master/NEWS.md#hw-probe-16
hw-probe-1.6.2/flatpak/hw-probe.desktop000066400000000000000000000003771417672225000200200ustar00rootroot00000000000000[Desktop Entry] Type=Application StartupNotify=true Name=Hardware Probe Comment=Probe for hardware, check operability and find drivers Icon=org.linux_hardware.hw-probe Exec=hw-probe Categories=Utility;Development;System; Keywords=HW Probe;Hardware;Probe; hw-probe-1.6.2/flatpak/hw-probe.sh000066400000000000000000000002051417672225000167470ustar00rootroot00000000000000#!/bin/sh if [ $# -eq 0 ]; then perl /app/bin/hw-probe-flatpak -flatpak else perl /app/bin/hw-probe-flatpak -flatpak "$@" fi hw-probe-1.6.2/flatpak/org.linux_hardware.hw-probe.yaml000066400000000000000000000507501417672225000231120ustar00rootroot00000000000000app-id: org.linux_hardware.hw-probe runtime: org.kde.Platform runtime-version: "5.15" sdk: org.kde.Sdk command: hw-probe finish-args: - --share=network - --device=all - --filesystem=host:ro - --filesystem=/var/log:ro - --filesystem=/sys:ro - --filesystem=/dev - --socket=wayland - --socket=x11 - --env=PATH=/usr/bin:/bin:/usr/sbin:/sbin:/app/bin:/app/sbin - --env=PERL5LIB=/app/share/perl5:/app/lib/x86_64-linux-gnu/perl-base:/app/lib/i386-linux-gnu/perl-base - --env=LD_LIBRARY_PATH=/app/lib/x86_64-linux-gnu/:/app/lib/i386-linux-gnu/:/app/lib64:/app/lib - --env=LC_ALL=C cleanup: - /include - /man - /share/doc - /share/man - /share/hwinfo - /share/pkgconfig - /share/usb.ids.gz - /share/smartmontools - /share/smartd.service - /share/PERL5_BASE - /share/automake* - /share/info - /share/aclocal* - /share/libtool - /sbin/check_hd - /sbin/convert_hd - /sbin/fancontrol - /sbin/getsysinfo - /sbin/isadump - /sbin/isaset - /sbin/mk_isdnhwdb - /sbin/ownership - /sbin/pwmconfig - /sbin/sensors-detect - /sbin/setpci - /sbin/update-pciids - /sbin/update-usbids.sh - /sbin/vpddecode - /sbin/smartd - /sbin/update-smart-drivedb - /lib64/pkgconfig - /lib/pkgconfig - /lib/debug - /lib/libltdl* - /bin/acpibin - /bin/acpiexamples - /bin/acpiexec - /bin/acpihelp - /bin/acpinames - /bin/acpisrc - /bin/kmod - /bin/lsusb.py - /bin/sensors-conf-convert - /bin/usbhid-dump - /bin/lex - /bin/automake* - /bin/aclocal* - /bin/libtool* - /etc/init.d - /etc/smartd_warning.d - /etc/sensors.d - /etc/smartd.conf - /etc/smartd_warning.sh - /var/lib - /lib/*.a - /lib/*.la - /usr modules: - name: automake buildsystem: simple build-commands: - ./configure --prefix=$FLATPAK_DEST - make -j $FLATPAK_BUILDER_N_JOBS - make install sources: - type: archive url: https://ftp.gnu.org/gnu/automake/automake-1.15.tar.xz sha256: 9908c75aabd49d13661d6dcb1bc382252d22cc77bf733a2d55e87f2aa2db8636 - name: libtool buildsystem: simple build-commands: - ./configure --prefix=$FLATPAK_DEST - make -j $FLATPAK_BUILDER_N_JOBS - make install sources: - type: archive url: https://ftp.gnu.org/gnu/libtool/libtool-2.4.6.tar.xz sha256: 7c87a8c2c8c0fc9cd5019e402bed4292462d00a718a7cd5f11218153bf28b26f - name: edid-decode buildsystem: simple build-commands: - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - make install DESTDIR=$FLATPAK_DEST bindir=/bin mandir=/share/man sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.4/edid-decode-20180622.tar.gz sha256: ab44c58a3712beca8ffa0ac937dc24d337cb0ecd18e703b4ddf3a10b0df35e1e - name: dmidecode buildsystem: simple build-commands: - sed -i -e 's/ -O2/ -s -O2/' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install prefix=/ DESTDIR=$FLATPAK_DEST sources: - type: archive url: https://download-mirror.savannah.gnu.org/releases/dmidecode/dmidecode-3.3.tar.xz sha256: 82c737a780614c38a783e8055340d295e332fb12c7f418b5d21a0797d3fb1455 - name: iproute2 buildsystem: simple build-commands: - ./configure --prefix=/ - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - install -D ./ip/ip $FLATPAK_DEST/sbin/ip sources: - type: archive url: https://mirrors.edge.kernel.org/pub/linux/utils/net/iproute2/iproute2-5.9.0.tar.xz sha256: a25dac94bcdcf2f73316c7f812115ea7a5710580bad892b08a83d00c6b33dacf - name: lm-sensors buildsystem: simple build-commands: - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install BUILD_STATIC_LIB=0 DEBUG=0 PREFIX=/ DESTDIR=$FLATPAK_DEST sources: - type: archive url: https://github.com/lm-sensors/lm-sensors/archive/V3-6-0.tar.gz sha256: 0591f9fa0339f0d15e75326d0365871c2d4e2ed8aa1ff759b3a55d3734b7d197 - name: libkmod buildsystem: simple build-commands: - ./configure --disable-debug --disable-python --disable-logging --disable-test-modules --disable-manpages --prefix=/ - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install DESTDIR=$FLATPAK_DEST - install -D ./tools/lsmod $FLATPAK_DEST/bin/lsmod sources: - type: archive url: https://cdn.kernel.org/pub/linux/utils/kernel/kmod/kmod-12.tar.xz sha256: c6189dd8c5a1e8d9224e8506bd188c0cd5dfa119fd6b7e5869b3640cbe8bf92f - name: libusb-1 buildsystem: simple build-commands: - NOCONFIGURE=1 sh autogen.sh - ./configure --disable-static --disable-udev --prefix=/ - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install DESTDIR=$FLATPAK_DEST sources: - type: archive url: https://github.com/libusb/libusb/archive/v1.0.22.tar.gz sha256: 3500f7b182750cd9ccf9be8b1df998f83df56a39ab264976bdb3307773e16f48 - name: usbutils buildsystem: simple build-commands: - sed -i -e 's/usbhid-dump//' Makefile.* - ./configure --prefix=/ LIBUSB_CFLAGS='-I'$FLATPAK_DEST'/include/libusb-1.0' LIBUSB_LIBS='-L'$FLATPAK_DEST'/lib64 -L'$FLATPAK_DEST'/lib -lusb-1.0' - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install DESTDIR=$FLATPAK_DEST - sed -i -e 's|/share/usb.ids|/var/tmp/P_USB|' $FLATPAK_DEST/bin/lsusb sources: - type: archive url: https://mirrors.edge.kernel.org/pub/linux/utils/usb/usbutils/usbutils-007.tar.xz sha256: 7593a01724bbc0fd9fe48e62bc721ceb61c76654f1d7b231b3c65f6dfbbaefa4 - name: pciutils buildsystem: simple build-commands: - make install PREFIX=/ DESTDIR=$FLATPAK_DEST SHARED=no LIBKMOD=no HWDB=no ZLIB=no DNS=no - sed -i -e 's|/share/pci.ids|/var/tmp/P_PCI|' $FLATPAK_DEST/sbin/lspci sources: - type: archive url: https://github.com/pciutils/pciutils/archive/v3.6.2.tar.gz sha256: d84d7096a71890f0ddddc50e88ac5a3bc7412bf48d8100fc15857a411564687d - name: acpica-unix buildsystem: simple build-commands: - make -j $FLATPAK_BUILDER_N_JOBS - make install DESTDIR=$FLATPAK_DEST PREFIX=/ sources: - type: archive url: https://acpica.org/sites/acpica/files/acpica-unix-20210730.tar.gz sha256: 4a0c14d5148666612aa0555c5179eaa86230602394fd1bc3d16b506fcf49b5de - name: hdparm buildsystem: simple build-commands: - make -j $FLATPAK_BUILDER_N_JOBS - make install DESTDIR=`pwd`/INST - install -D INST/sbin/hdparm $FLATPAK_DEST/sbin/hdparm sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.6/hdparm-9.62.tar.gz sha256: 2c0f9d75cdbeda928a25a128cd3d0b7120445ec0910c0b29d4c1038ed1be777f - name: smartmontools buildsystem: simple build-commands: - NOCONFIGURE=1 sh autogen.sh - ./configure --with-nvme-devicescan --prefix=/ --with-systemdsystemunitdir=/share - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install DESTDIR=$FLATPAK_DEST sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.5/smartmontools-7.2.tar.gz sha256: 5cd98a27e6393168bc6aaea070d9e1cd551b0f898c52f66b2ff2e5d274118cd6 - name: util-linux buildsystem: simple build-commands: - ./configure --prefix=/ - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS dmesg - make -j $FLATPAK_BUILDER_N_JOBS lscpu - find . -type f | perl -lne 'print if -B and -x' | xargs strip - install -D ./dmesg $FLATPAK_DEST/bin/dmesg - install -D ./lscpu $FLATPAK_DEST/bin/lscpu sources: - type: archive url: https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.37/util-linux-2.37.2.tar.xz sha256: 6a0764c1aae7fb607ef8a6dd2c0f6c47d5e5fd27aa08820abaad9ec14e28e9d9 - name: libx86emu buildsystem: simple build-commands: - echo '3.2' > VERSION - rm -f git2log - sed -i -e 's/ -g / -s /' Makefile - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install DESTDIR=`pwd`/INST - cp -fr INST/usr/* $FLATPAK_DEST/ sources: - type: archive url: https://github.com/wfeldt/libx86emu/archive/3.2.tar.gz sha256: 4faf853cc3776bc089fe01917acf56043feb42dc7bae91f60b974b2b00b1b0f3 - name: lex buildsystem: simple build-commands: - NOCONFIGURE=1 sh autogen.sh - ./configure - make -j $FLATPAK_BUILDER_N_JOBS - install -D src/flex $FLATPAK_DEST/bin/lex sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.4/flex-20181004.tar.gz sha256: bd7d248de7792dd2de2089a16b7ea60f94b2056e721e1f0f1b28083f4792e902 - name: perl-uri buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/E/ET/ETHER/URI-1.74.tar.gz sha256: a9c254f45f89cb1dd946b689dfe433095404532a4543bdaab0b71ce0fdcdd53d - name: perl-http-message buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/O/OA/OALDERS/HTTP-Message-6.26.tar.gz sha256: 6ce6c359de75c3bb86696a390189b485ec93e3ffc55326b6d044fa900f1725e1 - name: perl-net-http buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/O/OA/OALDERS/Net-HTTP-6.19.tar.gz sha256: 52b76ec13959522cae64d965f15da3d99dcb445eddd85d2ce4e4f4df385b2fc4 - name: perl-try-tiny buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/E/ET/ETHER/Try-Tiny-0.30.tar.gz sha256: da5bd0d5c903519bbf10bb9ba0cb7bcac0563882bcfe4503aee3fb143eddef6b - name: perl-lwp-mediatypes buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/G/GA/GAAS/LWP-MediaTypes-6.02.tar.gz sha256: 18790b0cc5f0a51468495c3847b16738f785a2d460403595001e0b932e5db676 - name: perl-http-date buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/G/GA/GAAS/HTTP-Date-6.02.tar.gz sha256: e8b9941da0f9f0c9c01068401a5e81341f0e3707d1c754f8e11f42a7e629e333 - name: perl-timedate buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/G/GB/GBARR/TimeDate-2.30.tar.gz sha256: 75bd254871cb5853a6aa0403ac0be270cdd75c9d1b6639f18ecba63c15298e86 - name: libwww-perl buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/E/ET/ETHER/libwww-perl-6.36.tar.gz sha256: 75c034ab4b37f4b9506dc644300697505582cf9545bcf2e2079e7263f675290a - name: perl-parent buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/C/CO/CORION/parent-0.238.tar.gz sha256: 38f58fdef3e28a194c9c8d0dc5d02672faf93c069f40c5bcb1fabeadbbc4d2d1 - name: perl-time-local buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/SITELIB/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/D/DR/DROLSKY/Time-Local-1.30.tar.gz sha256: c7744f6b2986b946d3e2cf034df371bee16cdbafe53e945abb1a542c4f8920cb - name: perl-data-dumper buildsystem: simple build-commands: - perl Makefile.PL - make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB - chmod 777 -R ./INST - find ./INST -type f | perl -lne 'print if -B and -x' | xargs strip - mkdir -p $FLATPAK_DEST/share/perl5/ - cp -fr ./INST/usr/lib/perl5/*/* $FLATPAK_DEST/share/perl5/ sources: - type: archive url: https://cpan.metacpan.org/authors/id/S/SM/SMUELLER/Data-Dumper-2.161.tar.gz sha256: 3aa4ac1b042b3880438165fb2b2139d377564a8e9928ffe689ede5304ee90558 - name: python3-sip buildsystem: simple build-commands: - python3 configure.py --sip-module PyQt5.sip -b ${FLATPAK_DEST}/bin -d ${FLATPAK_DEST}/lib/python3.8/site-packages -e ${FLATPAK_DEST}/include -v ${FLATPAK_DEST}/share/sip --stubsdir=${FLATPAK_DEST}/lib/python3.8/site-packages - make - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.6/sip-4.19.25.tar.gz sha256: b39d93e937647807bac23579edbff25fe46d16213f708370072574ab1f1b4211 - name: PyQt5 cleanup: - /bin/sip* - /include - /lib/python3.8/site-packages/*.pyi config-opts: - -disable-static - --enable-x11 buildsystem: simple build-commands: - find ${FLATPAK_DEST}/ -name "*qmake*" - python3 configure.py --confirm-license --no-docstrings --assume-shared --no-sip-files --no-designer-plugin --no-qml-plugin --no-tools --no-qsci-api --no-python-dbus --no-stubs --no-sip-files -d ${FLATPAK_DEST}/lib/python3.8/site-packages --sip=${FLATPAK_DEST}/bin/sip --sip-incdir=${FLATPAK_DEST}/include --stubsdir=${FLATPAK_DEST}/lib/python3.8/site-packages --disable=QtSensors --disable=QtWebEngine --disable=QtQuick --disable=QtQml --disable=QtTest --disable=QtWebChannel --disable=QtWebEngineCore --disable=QWebEngineWidgets --disable=QtQuickWidgets --disable=QtSql --disable=QtXmlPatterns --disable=QtMultimedia --disable=QtMultimediaWidgets --disable=QtLocation --disable=QtDesigner --disable=QtOpenGL --disable=QtBluetooth --disable=QtWebKit --disable=QtWebKitWidgets --disable=QtNfc --disable=QtPositioning --disable=QtNetwork --disable=QtSerialPort --disable=QtSvg --disable=QtX11Extras --disable=QtRemoteObjects --disable=QtDBus --disable=QtWebSockets --disable=QtPrintSupport --disable=QtHelp --disable=QtXml --disable=QtTextToSpeech - make -j $(nproc) - find . -type f -name "*.debug" | xargs rm -f - find . -type f | perl -lne 'print if -B and -x' | xargs strip - make install sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.6/PyQt5-5.15.4.tar.gz sha256: 2a69597e0dd11caabe75fae133feca66387819fc9bc050f547e5551bce97e5be - name: PyQt5_sip buildsystem: simple build-commands: - python3 setup.py install --root ${FLATPAK_DEST} sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.6/PyQt5_sip-12.9.0.tar.gz sha256: d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32 - name: hwinfo skip-arches: - aarch64 - arm buildsystem: simple build-commands: - echo '21.76' > VERSION - rm -f git2log - sed -i -e 's/ -g / -s /' Makefile.common - CFLAGS='-I'$FLATPAK_DEST'/include' LDFLAGS='-L'$FLATPAK_DEST'/lib64 -L'$FLATPAK_DEST'/lib -lx86emu' LD_LIBRARY_PATH=$FLATPAK_DEST'/lib64:'$FLATPAK_DEST'/lib' make - make install DESTDIR=`pwd`/INST - cp -fr INST/usr/* $FLATPAK_DEST/ sources: - type: archive url: https://github.com/openSUSE/hwinfo/archive/21.76.tar.gz sha256: 3011f7badfadce2e3f2d0201d8be87fdb92920a80b7df57e595a6c6cc2f4968d - name: hwinfo only-arches: - aarch64 - arm buildsystem: simple build-commands: - echo '21.76' > VERSION - rm -f git2log - sed -i -e 's/ -g / -s /' Makefile.common - make - make install DESTDIR=`pwd`/INST - cp -fr INST/usr/* $FLATPAK_DEST/ sources: - type: archive url: https://github.com/openSUSE/hwinfo/archive/21.76.tar.gz sha256: 3011f7badfadce2e3f2d0201d8be87fdb92920a80b7df57e595a6c6cc2f4968d - name: hw-probe buildsystem: simple build-commands: - make install DESTDIR=$FLATPAK_DEST prefix=/ - mv $FLATPAK_DEST/bin/hw-probe $FLATPAK_DEST/bin/hw-probe-flatpak - install -m 777 -D flatpak/hw-probe.sh $FLATPAK_DEST/bin/hw-probe - install -D flatpak/PERL5_BASE $FLATPAK_DEST/share/PERL5_BASE - install -D flatpak/hw-probe.appdata.xml $FLATPAK_DEST/share/metainfo/org.linux_hardware.hw-probe.appdata.xml - install -D flatpak/icon-256x256.png $FLATPAK_DEST/share/icons/hicolor/256x256/apps/org.linux_hardware.hw-probe.png - install -D flatpak/icon-128x128.png $FLATPAK_DEST/share/icons/hicolor/128x128/apps/org.linux_hardware.hw-probe.png - install -D flatpak/icon-64x64.png $FLATPAK_DEST/share/icons/hicolor/64x64/apps/org.linux_hardware.hw-probe.png - install -D flatpak/hw-probe.desktop $FLATPAK_DEST/share/applications/org.linux_hardware.hw-probe.desktop - install -D flatpak/usb.ids $FLATPAK_DEST/share/usb.ids - install -D flatpak/pci.ids $FLATPAK_DEST/share/pci.ids sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.6/hw-probe-1.6-AI.tar.gz sha256: 9260f02ca4528751309f61786e696d7abe6d3aae651bc692c4713d19fb7b534d - name: hw-probe-pyqt5-gui buildsystem: simple build-commands: - mkdir -p $FLATPAK_DEST/share/hw-probe-pyqt5-gui/ - mv Resources Hardware\ Probe $FLATPAK_DEST/share/hw-probe-pyqt5-gui/ - ln -s $FLATPAK_DEST/share/hw-probe-pyqt5-gui/Hardware\ Probe $FLATPAK_DEST/bin/hw-probe-pyqt5-gui - chmod 777 $FLATPAK_DEST/bin/hw-probe-pyqt5-gui sources: - type: archive url: https://github.com/linuxhw/build-stuff/releases/download/1.6/hw-probe-pyqt5-gui-1.6-AI.tar.gz sha256: 0e3528c78def70842b4638bb136a1c5dc8ddc3ee679b29b314906d95afb0a626 - name: perl-base buildsystem: simple build-commands: - sh Configure -de -Dprefix=/ - make -j $FLATPAK_BUILDER_N_JOBS - find . -type f | perl -lne 'print if -B and -x' | xargs strip - install -D ./perl $FLATPAK_DEST/bin/perl - cd lib && cat $FLATPAK_DEST/share/PERL5_BASE | while read i; do mkdir -p $FLATPAK_DEST/share/perl5/`dirname $i`; cp -fr $i $FLATPAK_DEST/share/perl5/$i; done sources: - type: archive url: https://www.cpan.org/src/5.0/perl-5.34.0.tar.xz sha256: 82c2e5e5c71b0e10487a80d79140469ab1f8056349ca8545140a224dbbed7ded hw-probe-1.6.2/hw-probe.pl000066400000000000000000020537341417672225000153470ustar00rootroot00000000000000#!/usr/bin/env perl ##################################################################### # Hardware Probe 1.6 # A tool to probe for hardware, check operability and find drivers # # WWW (Linux): https://linux-hardware.org # WWW (BSD): https://bsd-hardware.info # # Copyright (C) 2014-2022 Linux Hardware Project # # Written by Andrey Ponomarenko (ABI Laboratory, LSB Infrastructure, # AZOV Framework testing technology, IEEE certified software test # engineer, ROSA Linux distribution) # # LinkedIn: https://www.linkedin.com/in/andreyponomarenko # # PLATFORMS # ========= # Linux (Fedora, CentOS, RHEL, Ubuntu, Debian, Mint, MX, Arch, # Gentoo, ROSA, Mandriva, Clear Linux, Alpine ...) # # BSD (FreeBSD, OpenBSD, NetBSD, GhostBSD, NomadBSD, DragonFly, # MidnightBSD, FuryBSD, FreeNAS, pfSense, OPNsense, # XigmaNAS ...) # # REQUIRES (Linux) # ================ # Perl 5 # perl-Digest-SHA # perl-Data-Dumper # hwinfo (https://github.com/openSUSE/hwinfo) # curl # dmidecode # smartmontools (smartctl) # pciutils (lspci) # usbutils (lsusb) # edid-decode # # RECOMMENDS (Linux) # ================== # libwww-perl (if curl is missed) # mcelog # hdparm # systemd-tools (systemd-analyze) # acpica-tools # drm_info # mesa-demos # vulkan-utils # memtester # rfkill # sysstat (iostat) # cpuid # xinput # vainfo # inxi # i2c-tools # opensc # # LICENSE # ======= # This work is dual-licensed under LGPL 2.1 (or any later version) # and BSD-4-Clause. You can choose between one of them if you use # this work. # # LGPL-2.1-or-later # ================= # This library is free software: you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation, either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library. If not, see: # # https://www.gnu.org/licenses/ # # BSD-4-Clause # ============ # This is free software: you can redistribute it and/or modify it # under the terms of the BSD 4-Clause License. # # This software is distributed WITHOUT ANY WARRANTY; without even # the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR # PURPOSE. # # You should have received a copy of the BSD 4-Clause License along # with this library. If not, see: # # https://spdx.org/licenses/BSD-4-Clause.html # ##################################################################### use Getopt::Long; Getopt::Long::Configure ("posix_default", "no_ignore_case"); use File::Path qw(mkpath rmtree); use File::Temp qw(tempdir); use File::Copy qw(copy move); use File::Basename qw(basename dirname); use Cwd qw(abs_path cwd); my $TOOL_VERSION = "1.6"; my $URL = "https://linux-hardware.org"; my $URL_BSD = "https://bsd-hardware.info"; my $GITHUB = "https://github.com/linuxhw/hw-probe"; my $LOCALE = "C"; my $ORIG_DIR = cwd(); my $TMP_DIR = tempdir(CLEANUP=>1); my $TMP_LOCAL = ".tmp_".basename($TMP_DIR); my $SNAP_DESKTOP = (defined $ENV{"BAMF_DESKTOP_FILE_HINT"}); my $FLATPAK_DESKTOP = (grep { $_ eq "-flatpak" } @ARGV); my $BY_DESKTOP = 0; my @ARGV_COPY = @ARGV; my $CmdName = basename($0); if($CmdName=~/\A\d+\Z/) { # Run from STDIN $CmdName = "hw-probe"; } my $CmdExample = "sudo -E $CmdName"; my $GlobalSubject = "Linux"; if(isBSD($^O)) { $CmdExample = $CmdName; $GlobalSubject = "BSD"; } my $ShortUsage = "Hardware Probe $TOOL_VERSION A tool to probe for hardware, check operability and find drivers License: LGPL-2.1-or-later OR BSD-4-Clause Usage: $CmdExample [options] Example: $CmdExample -all -upload\n\n"; my %Opt; GetOptions("h|help!" => \$Opt{"Help"}, "v|version!" => \$Opt{"ShowVersion"}, "dumpversion!" => \$Opt{"DumpVersion"}, # Main "all!" => \$Opt{"All"}, "probe!" => \$Opt{"Probe"}, "logs!" => \$Opt{"Logs"}, "log-level=s" => \$Opt{"LogLevel"}, "minimal|mini|min!" => \$Opt{"Minimal"}, "maximal|maxi|max!" => \$Opt{"Maximal"}, "enable=s" => \$Opt{"Enable"}, "disable=s" => \$Opt{"Disable"}, "printers!" => \$Opt{"Printers"}, "scanners!" => \$Opt{"Scanners"}, "check!" => \$Opt{"Check"}, "check-graphics!" => \$Opt{"CheckGraphics"}, "check-hdd!" => \$Opt{"CheckHdd"}, "limit-check-hdd=s" => \$Opt{"LimitCheckHdd"}, "check-memory!" => \$Opt{"CheckMemory"}, "check-cpu!" => \$Opt{"CheckCpu"}, "id|name=s" => \$Opt{"PC_Name"}, "upload|confirm-upload-of-hashed-ids!" => \$Opt{"Upload"}, "hwinfo-path=s" => \$Opt{"HWInfoPath"}, "log!" => \$Opt{"ShowLog"}, "proxy=s" => \$Opt{"Proxy"}, # Inventory "inventory|inventory-id|i|group|g=s" => \$Opt{"Group"}, "generate-inventory|generate-inventory-id|get-inventory-id|get-group!" => \$Opt{"GenerateGroup"}, "email=s" => \$Opt{"Email"}, # Monitoring "start|start-monitoring!" => \$Opt{"StartMonitoring"}, "stop|stop-monitoring!" => \$Opt{"StopMonitoring"}, "remind-inventory!" => \$Opt{"RemindGroup"}, "monitoring!" => \$Opt{"Monitoring"}, # Other "src|source=s" => \$Opt{"Source"}, "save=s" => \$Opt{"Save"}, "fix=s" => \$Opt{"FixProbe"}, "show-devices!" => \$Opt{"ShowDevices"}, "show-host!" => \$Opt{"ShowHost"}, "show!" => \$Opt{"Show"}, "compact!" => \$Opt{"Compact"}, "verbose!" => \$Opt{"Verbose"}, "pci-ids=s" => \$Opt{"PciIDs"}, "usb-ids=s" => \$Opt{"UsbIDs"}, "sdio-ids=s" => \$Opt{"SdioIDs"}, "pnp-ids=s" => \$Opt{"PnpIDs"}, "list!" => \$Opt{"ListProbes"}, "save-uploaded!" => \$Opt{"SaveUploaded"}, "debug|d!" => \$Opt{"Debug"}, "dump-acpi!" => \$Opt{"DumpACPI"}, "decode-acpi!" => \$Opt{"DecodeACPI"}, "import=s" => \$Opt{"ImportProbes"}, # Private "docker!" => \$Opt{"Docker"}, "appimage!" => \$Opt{"AppImage"}, "snap!" => \$Opt{"Snap"}, "flatpak!" => \$Opt{"Flatpak"}, "from-gui!" => \$Opt{"FromGUI"}, "low-compress!" => \$Opt{"LowCompress"}, "high-compress!" => \$Opt{"HighCompress"}, "identify-drive=s" => \$Opt{"IdentifyDrive"}, "identify-monitor=s" => \$Opt{"IdentifyMonitor"}, "show-dmesg=s" => \$Opt{"ShowDmesg"}, "bsd!" => \$Opt{"ForBSD"}, "decode-acpi-from=s" => \$Opt{"DecodeACPI_From"}, "decode-acpi-to=s" => \$Opt{"DecodeACPI_To"}, "fix-edid!" => \$Opt{"FixEdid"}, "rm-log=s" => \$Opt{"RmLog"}, "truncate-log=s" => \$Opt{"TruncateLog"}, "install-deps!" => \$Opt{"InstallDeps"}, "nodeps!" => \$Opt{"SkipDeps"}, "rm-obsolete!" => \$Opt{"RmObsolete"}, "output=s" => \$Opt{"OutputDir"} ) or die "\n".$ShortUsage; if($#ARGV_COPY==-1) { # Run from STDIN if (-t STDIN) { $Opt{"ShowVersion"} = 1; } else { print "Executing hw-probe -all -upload\n\n"; $Opt{"All"} = 1; $Opt{"Upload"} = 1; } } elsif($#ARGV_COPY==0 and grep { $ARGV_COPY[0] eq $_ } ("-snap", "-flatpak")) { # Run by desktop file my $Gui = "hw-probe-pyqt5-gui"; if(checkCmd($Gui)) { print "Executing $Gui\n\n"; if($ARGV_COPY[0] eq "-flatpak") { system("HW_PROBE_FLATPAK=1 $Gui"); } else { system("HW_PROBE_SNAP=1 $Gui"); } exitStatus(0); } print "Executing hw-probe -all -upload\n\n"; $Opt{"All"} = 1; $Opt{"Upload"} = 1; if($SNAP_DESKTOP or $FLATPAK_DESKTOP) { # Desktop $BY_DESKTOP = 1; } } my $PROBE_DIR = "/root/HW_PROBE"; if($Opt{"Snap"}) { $PROBE_DIR = $ENV{"SNAP_USER_COMMON"}."/HW_PROBE"; } elsif($Opt{"Flatpak"}) { $TMP_DIR = "/var".$TMP_DIR; mkpath($TMP_DIR); $PROBE_DIR = $ENV{"XDG_DATA_HOME"}."/HW_PROBE"; } if($Opt{"OutputDir"}) { $PROBE_DIR = $Opt{"OutputDir"}; mkpath($PROBE_DIR); } my $LATEST_DIR = $PROBE_DIR."/LATEST"; my $TMP_PROBE_DIR = $LATEST_DIR."/".basename($TMP_DIR); my $TMP_PROBE = $TMP_PROBE_DIR."/hw.info"; my $PROBE_LOG = $PROBE_DIR."/LOG"; my ($DATA_DIR, $LOG_DIR, $TEST_DIR) = initDataDir($LATEST_DIR."/hw.info"); my $HelpMessage=" NAME: Hardware Probe ($CmdName) A tool to probe for hardware, check operability and find drivers DESCRIPTION: Hardware Probe ($CmdName) is a tool to probe for hardware, check its operability and upload result to the $GlobalSubject hardware database. By creating probes you contribute to the \"HDD/SSD Desktop-Class Reliability Test\" study: https://github.com/linuxhw/SMART USAGE: $CmdExample [options] EXAMPLE: $CmdExample -all -upload PRIVACY: Private information (including the username, machine's hostname, IP addresses, MAC addresses, UUIDs and serial numbers) is NOT uploaded to the database. The tool uploads 32-byte prefix of salted SHA512 hash of MAC addresses and serial numbers to properly identify unique computers and hard drives. UUIDs are decorated in the same way, but formatted like regular UUIDs in order to save readability of logs. All the data is uploaded securely via HTTPS. INFORMATION OPTIONS: -h|-help Print this help. -v|-version Print version info. -dumpversion Print the tool version ($TOOL_VERSION) and don't do anything else. GENERAL OPTIONS: -all Enable all probes. -probe Probe for hardware. Collect only hardware related logs. -logs Collect system logs. -log-level N Set the logging level to N. Available values: - minimal - default - maximal -minimal|-min Collect minimal number of logs. Equal to --log-level=min. -maximal|-max Collect maximal number of logs. Equal to --log-level=max. -enable LIST Comma separated list of logs to enable in addition to current log level. -disable LIST Comma separated list of logs to disable in current log level. Some logs cannot be disabled. For example, you can disable collecting of 'fstab', but you cannot disable logging of 'smartctl'. -printers Probe for printers. -scanners Probe for scanners. -check Check devices operability. -id|-name DESC Any description of the probe. -upload Upload result to the hardware database. You will get a permanent URL to view the probe. By use of this option you confirm uploading of 32-byte prefix of salted SHA512 hash of MAC addresses and serial numbers to prevent duplication of computers in the DB. -hwinfo-path PATH Path to a local hwinfo binary. -proxy ADDRESS:PORT Set outgoing http/https proxy using syntax: proxy.domain.local:3128 INVENTORY OPTIONS: -i|-inventory-id ID Mark the probe by inventory ID. -generate-inventory-id Generate new inventory ID. -email ADDR Email for node status notifications. MONITORING OPTIONS: -start Start monitoring of the node. -stop Stop monitoring of the node. -remind-inventory Remind node inventory ID. OTHER OPTIONS: -save DIR Save probe package to DIR. This is useful if you are offline and need to upload a probe later (with the help of -src option). -src|-source PATH A probe to upload. -fix PATH Update list of devices and host info in the probe using probe data. -show-devices Show devices list. -show Show host info and devices list. -show-host Show host info only. -verbose Use with -show option to show type and status of the device. -pci-ids PATH -usb-ids PATH -sdio-ids PATH -pnp-ids PATH Path to {pci,usb,sdio,pnp}.ids file to read missed device names. -list List executed probes (for debugging). -clean Do nothing. Obsolete option. -save-uploaded Save uploaded probes. -debug|-d Do nothing. Obsolete option. -dump-acpi Probe for ACPI table. -decode-acpi Decode ACPI table. -import DIR Import probes from the database to DIR for offline use. If you are using Snap or Flatpak package, then DIR will be created in the sandbox data directory. Provide inventory ID by -i option in order to import your inventory. DATA LOCATION: Probes info is saved in the $PROBE_DIR directory. "; # Hardware my %HW; my %HW_Count; my %LongID; my %DevBySysID; my %KernMod; my %WorkMod; my %WLanInterface; my %EthernetInterface; my %PermanentAddr; my %ExtraConnection; my %HDD; my %HDD_Info; my %MMC; my %MMC_Info; my %BlockCapacity; my $Board_ID; my $Bios_ID; my $CPU_ID; my $CDROM_ID; my %ComponentID; my %Monitor_ID; my %DeviceIDByNum; my %DeviceNumByID; my %DriveNumByFile; my %DeviceAttached; my %GraphicsCards; my %GraphicsCards_All; my %GraphicsCards_InUse; my %UsedNetworkDev; my %DevAttachedRecursive; my %DevAttachedRecursive_R; my %DevAttached; my %DevAttached_R; my %DrmAttached; my $SnapNoBlockDevices = 0; my $MIN_BAT_CAPACITY = 30; my @G_DRIVERS_INTEL = ("i915", "i915_bpo", "gma500_gfx"); my @G_DRIVERS = ("nvidia", "nouveau", "radeon", "amdgpu", "fglrx", @G_DRIVERS_INTEL); my %DriverVendor = ( "i915" => "8086", "nouveau" => "10de", "nvidia" => "10de", "radeon" => "1002", "amdgpu" => "1002", "fglrx" => "1002" ); foreach (@G_DRIVERS_INTEL) { $DriverVendor{$_} = "8086"; } my $PCI_DISK_BUS = "nvme"; # System my %Sys; # Settings my $Admin = ($>==0); # Fixing my $FixProbe_Pkg; my $FixProbe_Logs; my $FixProbe_Tests; # Probe my $RecentProbe; # PCI and USB IDs my %PciInfo = ("I"=>{}, "D"=>{}, "V"=>{}, "C"=>{}); $PciInfo{"V"} = { "8086" => "Intel", "17aa" => "Lenovo", "14a4" => "Lite-On", "1987" => "Phison", "144d" => "Samsung", "1b4b" => "SanDisk", "126f" => "Silicon Motion", "1c5c" => "SK hynix", "1179" => "Toshiba" }; my %UsbInfo; my %UsbVendor; my %UsbClass; # JEDEC IDS my %VendorJedec = ( "A Force" => ["7F7F7F7F7F7F7F02", "7F7F7F6DFFFFFFFF"], "ADATA" => ["04CB", "7F7F7F7FCB000000"], "Aeneon" => ["7F7F7F7F7F570000"], "AMD" => ["80010000830B"], "Apacer" => ["017A", "7F7A", "7A01"], "ASint" => ["06C1", "c106", "7F7F7F7F7F7FC100"], "ATP" => ["86E3"], "A-TECH" => ["0080000080AD"], "Avant" => ["7F7F7F7F7FF70000", "85F7", "F705"], "Carry" => ["070E"], "Catalyst" => ["314F000000000000"], "Centon" => ["7F7F7F1900000000"], "CFD" => ["0770000080AD"], "CSX" => ["855D", "7F7F7F7F7F5D0000"], "Corsair" => ["029E", "0215", "9E02", "7F7F9E0000000000", "009C36160000"], "Crucial" => ["1315", "059B", "859B", "9B85", "9B05", "0D9B", "09B8", "7F7F7F7F7F9B0000", "7F7F7F7F7F9BFFFF", "0000000000009B85", "859<", "009D36160000", "009C2B0C0000", "9B000D1000000000", "F7F7F7F7F7B90000", "9B"], "Dane-Elec" => ["7FDA"], "DERLAR" => ["8AA2"], "Elpida" => ["00FE", "01FE", "02FE", "FE02", "7F7FFE0000000000", "0000000000FE7F7F", "000000000000FE02", "000000000FE02"], "Essencore" => ["0898000080AD"], "EUDAR" => ["847C"], "EVGA" => ["08D9"], "Foxline" => ["88F2", "8ABA"], "G-Alantic" => ["08F7"], "G.Skill" => ["04CD", "CD04", "7F7F7F7FCD000000", "04=>", "=>04", "EC9D0B160000"], "GIGABYTE" => ["89F2"], "Golden Empire" => ["7F7F7F1300000000", "8A45", "8313000080AD"], "Goldenmars" => ["7F7F7F7F7F620000"], "GOODRAM" => ["075D", "7F7F7F7F7F7F7F5D", "5D07"], "Infineon" => ["C100", "C10", "C1494E46494E454F"], "Innodisk" => ["86F1"], "Itaucom" => ["7F7F310000000000"], "Hexon" => ["7F7F7F7F7FDC0000"], "High Bridge" => ["07E9"], "Hikvision" => ["0B2C"], "KANMEIQi" => ["0B29"], "KINGBOX" => ["7F7F7F7F51000000"], "KingFast" => ["897A"], "Kingmax" => ["7F7F7F2500000000", "7F7F7F2500000000", "8325000080AD", "83250000830B"], "Kingston" => ["0198", "7F98", "9804", "F789", "9806", "9805", "00000B160000", "009C162D0000", "009C23240000"], "KingTiger" => ["7F7F7F7F7F7F7F10"], "Kllisre" => ["89C2"], "Kreton" => ["85E3", "7F7F7F7F7FE30000"], "Lexar" => ["8A76", "8A7600000000", "8A7600008A76"], "MAXSUN" => ["89A2"], "MCI Computer" => ["7F7F640000000000"], "Melco" => ["7F7F7F8300000000"], "Micron" => ["002C", "00C2", "802C", "857F", "878A", "2C00", "C200", "2CFF", "2C80", "2C0", "C20", "2C", "08D0", "009C162C0000", "FFFFFFFFFFFFFF2C", "0000000000002C80", "0000000002C80", "2C080905DF3FF327", "2C1600000000", "00002C0F0000"], "Mougol" => ["4B0", "4B00000000000000"], "MTASE" => ["8AAE"], "Multilaser"=> ["08B6"], "Nanya" => ["830B", "030B", "0B83", "0B0D", "7F7F7F0B000000", "7F7F7F0B00000000", "F7F7F7B000000000", "0000000000000B83"], "Netlist" => ["7F7F7F1600000000"], "OCZ" => ["84B0", "7F7F7F7FB0000000"], "Patriot" => ["4D41", "8502", "7F7F7F7F7F020000"], "Pioneer" => ["0B89"], "PNY" => ["01BA", "7FBA", "BA01"], "Positivo Informatica" => ["7F7F7F7F16000000"], "pqi" => ["853E", "7F7F7F7F7F3E0000"], "PRINCETON" => ["7F7F7F8A00000000"], "PUSKILL" => ["8AAD"], "Qimonda" => ["7F7F7F7F7F510000", "5145", "F7F7F7F7F7150000", "80C1", "85517FB38551", "855180B38551"], "Qumo" => ["02B5"], "Ramaxel" => ["7F7F7F7F43000000", "0443", "04430000802C", "7F7F7F7F7F000000", "000000437F7F7F7F"], "Reboto" => ["0080000080CE"], "Samsung" => ["EC00", "00CE", "80CE", "00EC", "CE00", "CE80", "0CE", "EC0", "CE0", "000000000000CE80", "CE80", "CE30", "00000000000000CE", "CE01", "009C360B0000", "0000CE020000", "009C0B160000", "09B0", "090D", "000000000CE80", "7F7F7F7F3B000000"], "SanMax" => ["86E9"], "SemsoTai" => ["09C8"], "Sesame" => ["0B13"], "Silicon Power" => ["86D3", "7F7F7F7F7F7FD300"], "SiS" => ["7F7F7F7F7F7FA800"], "SK hynix" => ["00AD", "00DA", "DA00", "6F2B", "80AD", "AD00", "ADFF", "AD01", "AD80", "000000000000AD80", "00000000000000AD", "AD0", "DA0", "0AD8", "009C35230000", "009C2B160000", "0000AD010000", "0000000080AD", "08CD", "2E0400000000"], "Smart" => ["7F94", "000000000000947F", "0194000080CE"], "Smart Modular" => ["019400000A00"], "Super Talent" => ["004D415500000000", "8634000082B5", "7F7F7F7F7F7F3400"], "Swissbit" => ["7F7F7FDA00000000"], "TakeMS" => ["7F7F7F5800000000", "7F7F7F58FFFFFFFF"], "Team" => ["04EF", "EF04", "7F7F7F7FEF000000"], "Teikon" => ["079E", "9E07"], "Textorm" => ["8C97"], "TIMETEC" => ["8C26"], "Transcend" => ["014F", "7F4F"], "TwinMOS" => ["866B", "066B"], "Unifosa" => ["0707000002FE"], "Unigen" => ["7FCE"], "Uroad" => ["07DC"], "Veineda" => ["89D0"], "V-Color" => ["066D"], "V-GeN" => ["0A94", "8A94"], "Walton Chaintech" => ["05D6", "7F7F7F7F7FD60000"] # APOGEE ); my %JedecVendor; foreach my $V (sort keys(%VendorJedec)) { foreach (sort @{$VendorJedec{$V}}) { $JedecVendor{$_} = $V; } } my %VendorRam = ( "A Force" => ["1GX64V", "1GX64B", "128X64K", "256X64M", "25664Y", "51264V"], "ADATA" => ["AD7", "AM1", "EL7YG", "HYOPE"], "Aeneon" => ["AET"], "AMD" => ["AE32G", "AE34G", "AP34G", "AE38G", "AP38G", "AV34G", "R33", "R53", "R5S", "R7S", "R9S", "R73", "R74", "R93", "R94"], "Atermiter"=> ["Atermite"], "ATP" => ["AQ12M", "AQ28M", "AQ56M", "AW12P"], "A-TECH" => ["ATECH"], "Axiom" => ["51264Y"], "Apacer" => ["76.", "78.", "D12."], "Apotop" => ["S3A", "U3A"], "ASint" => ["B1YJ", "B2YJ", "B3KJ", "C1RE", "C2RE", "SSA", "SSY", "SSZ", "SLA", "SLB", "SLZ"], "ATLA" => ["AD3SHT"], "Avant" => ["F64", "H64", "J64", "W64"], "Catalyst" => ["02GN"], "Centon" => ["MICT"], "CFD" => ["D4N"], "Chun Well" => ["D4U"], "Corsair" => ["CMD", "CMH", "CMK", "CML", "CMR", "CMS", "CMT", "CMU", "CMV", "CMW", "CMX", "CMZ", "CM2X", "CM3X", "CM4X", "VS2G"], "Crucial" => ["BLS", "BLT", "BLE", "BL4G", "BL5", "BL8G", "BL16G", "BL32G", "BL256", "BLM8G", "BLM16G", "CB4G", "CB8G", "CB16G", "CT256", "CT512", "CT1024", "CT2048", "CT4G", "CT8G", "CT16G", "CT32G", "CT10", "CT12864", "CT2G", "RM256", "RM512", "ST256", "ST512", "ST1024", "ZC256", "RM1024"], "CSX" => ["V01L", "V01D"], "Dane-Elec" => ["SS3D106"], "Dexcom" => ["L23 06/11 DEXCOM"], "Dynet" => ["DNHMAU"], "DSL" => ["D3SH"], "Elpida" => ["EBJ"], "Eluktro" => ["MEM-12800-8GB-PRO"], "Essencore"=> ["KD48GS"], "Exceleram"=> ["E301", "E302", "E408", "E404", "E470", "EPH4"], "EVGA" => ["08G-D3", "16G-D4-2400-MR"], "Foxline" => ["FL1", "FL2"], "G-Alantic"=> ["D3SS"], "G.Skill" => ["F3-", "F4-"], "GeIL" => ["CL9-9", "CL9-10", "CL10-10", "CL10-11", "CL11-11", "CL11-12"], # Golden Empire "GIGABYTE" => ["AR36", "GP-GR"], "Gloway" => ["TYA", "TYP"], "Goldkey" => ["BKH", "GKE", "GKH"], "Goldenmars" => ["GMT"], "GOODRAM" => ["GL213", "GR32", "GR400", "GR667", "GR800", "GR1", "GR2", "GY1", "IRX", "IR1", "IR2"], "HBS" => ["HB2", "HB3"], "High Bridge" => ["HB3SU"], "Hikvision" => ["HKED"], "HMD" => ["HMD"], "HP" => ["7EH"], "Huananzhi" => ["HNM"], "Hypertec" => ["G2BT", "G2RT"], "ISD Technology Limited" => ["IMT41"], "Juhor" => ["JHD"], "KANMEIQi" => ["KAi-D"], "Kembona" => ["KBN"], "Kimtigo" => ["KT4G", "KT8G"], "KingFast" => ["KF"], "Kingmax" => ["FLF", "FLG", "FSF", "FSG", "GLAH", "GLLG", "GSLG4"], "Kingston" => ["KHX", "ACR", "ASU", "BRAP", "D3L16", "HP53", "KMK", "KN2M", "SNY", "TSB", "CL4-", "CL7-", "CL9-", "CL11-", "CL15-", "CL16-", "CL-17-", "1024636"], "KingTiger"=> ["KingTiger000000000", "KingTige"], "Klevv" => ["KD4"], "Kllisre" => ["KRE-"], "KomputerBay" => ["KB_8G", "KB8G"], "Kreton" => ["516230", "51631x", "51634x", "51731x"], "Lexar" => ["LD4"], "Magnum Tech" => ["MAGNUMTECH"], "MAXSUN" => ["MSD"], "MDT" => ["MDT"], "Memory Solution" => ["MS3S"], "Memox" => ["LN-SD"], "MemoWise" => ["MW0"], "Micron" => ["16G2", "16HTF", "16JSF", "16JT", "16KTF", "18HF", "36JS", "4ATF", "53E", "864AY", "8ATF", "8JSF", "8JTF", "4KTF", "8KTF", "MT5"], "Mushkin" => ["991769", "992017", "991529", "991558", "991713", "992070", "991705", "MB[A/B]"], "Multilaser" => ["MD401", "MD451", "MS301", "MS351"], "Nanya" => ["NT1", "NT2", "NT4", "NT8", "M2F", "M2N", "M2S"], "Neo Forza"=> ["NMGD", "NMS", "NMUD"], "Netlist" => ["NL8"], "Novatech" => ["N3D", "N3S"], "OCZ" => ["OCZ"], "Panasonic"=> ["CFW5W"], "Panram" => ["PUD"], "Patriot" => ["PSA", "PSD", "R6N", "1600EL", "1600LL", "1866EL", "186C0", "2000EL", "2133 CL11 Series", "2666 C15 Series", "2666 C16 Series", "2800 C16 Series", "3200 C16 Series"], "Pioneer" => ["APS"], "PNY" => ["64C0M", "4GBH", "8GBF1X", "8GBH2X", "8GBU1X", "64D0J", "16GF2X", "16GU1X"], "PQI" => ["BN109062", "MFPD"], "PSC" => ["AS8"], "Puskill" => ["PJ16"], "Qbex" => ["B9C40", "C2NA0"], "Qimonda" => ["64T1280", "64T64", "64T12", "72T256"], "Qumo" => ["QUM"], "Rahonix" => ["RXD"], "Ramaxel" => ["RMT", "RMN", "RMR", "RMS", "RMU"], "Ramos" => ["EMB", "EWB", "RMB"], "RyzerX" => ["RVR"], "Samsung" => ["M04", "M378", "M393", "M4 70T", "M471", "K4E", "K4F", "K4U", "Ltd:R00MM", "UBE"], "Sesame" => ["S939", "S949"], "SGS/Thomson" => ["SD-D2", "SD-D3"], "Silicon Power" => ["DBLT", "DBST", "DCLT", "DCST", "SP0", "ESRD"], "SK hynix" => ["HCN", "HMA", "HMT", "HMP", "HYMP", "H9CC", "H9HC", "DMT3", "MMXIV", "MPP", "4GBPC1333512", "4GBPC"], "Smart" => ["SF464", "SF472", "SF564", "SG56", "SH564", "SMS4"], "Strontium" => ["SRT"], "Super Talent" => ["SUPERTALENT02", "SUPERTALENT"], "Swissbit" => ["MEN02", "SEU"], "T-FORCE" => ["ZEUS"], "TakeMS" => ["TMS"], "Team" => ["Team-Eli", "Team--El", "Dark", "Vulcan"], "Teikon" => ["TMA", "TML", "TMT"], "Textorm" => ["TXS"], "Thermaltake" => ["R009", "R019"], "Transcend"=> ["JM1", "JM2", "JM320", "JM367", "JM667", "JM800", "TS1", "TS64", "TS128", "TS256", "TS512"], "TwinMOS" => ["9DEEB", "9DHTB", "9DETB", "8DP25KK", "8DE25KK", "7D-23KK", "M2GAO"], "Unifosa" => ["GU3", "GU5", "GU6", "HU5", "HU6"], "Unigen" => ["UG"], "Unknown" => ["GRPFD"], "Uroad" => ["WJD"], "V-Color" => ["TD4", "TL4", "VCOLOR"], "V-GeN" => ["D3R", "D4H", "D4R", "D4S"], "Veineda" => ["M08GD16P"], "Visipro" => ["T2G", "T4G86"], "Walton Chaintech" => ["AS2G", "AU2G", "AU4G"], # APOGEE "Wilk Elektronik" => ["IRP"], "ZIFEI" => ["ZFN"] # Shenzhen Zhifeng Weiye Tech ); my %RamVendor; foreach my $V (sort keys(%VendorRam)) { foreach (sort @{$VendorRam{$V}}) { $RamVendor{$_} = $V; } } my %DiskVendor = ( "AGI" => "AGI", "APS-SL" => "Pioneer", "AS25 1" => "ASENNO", "BT58" => "BAITITON", "C3-60G" => "SenDisk", "CSSD-MG4VT" => "CFD", "FASTDISK" => "FASTDISK", "FTM" => "Super Talent", "G2 series" => "Micro Center", "G3 Series" => "Myung", "Gen2A400" => "Anobit", "GH-SSD" => "Green House", "GKH84" => "Goldkey", "JAJS" => "Leven", "LIREN" => "Liren", "M2SCF-6M" => "ACPI", "MD0" => "Magnetic Data", "MD" => "MaxDigital", "MKN" => "Mushkin", "MSS4FV" => "acpi", "NFS" => "Neo Forza", "PH6-CE" => "Plextor", "RD-S" => "RECADATA", "RTOTJ" => "Union Memory", "SPCC" => "SPCC", "SSD2S240" => "Hypertec", "T650-120" => "Goldenfir", "TEAML5" => "Team", "Thinklife" => "Lenovo", "TRO-SSD7" => "Eluktro", "V-GEN" => "V-GeN", "V7 SSD" => "VSEVEN", "Vi550" => "Verbatim", "WL" => "WD MediaMax", "XUNZHE" => "XUNZHE", "Y6-" => "Yunhaitian", "ZALMAN" => "ZALMAN", "ZF18-64" => "Espada", "ZTSSD" => "ZOTAC" ); my %VendorDiskPrefix = ( "ADATA" => ["ASU800SS", "AXM", "AXN", "IM2P", "IM2S", "SP600"], "ADLINK" => ["SSO"], "Advantech"=> ["SQF"], "AMD" => ["R3S", "R5S"], "Apacer" => ["APSDM"], "Apple" => ["A45ACXBA9TA"], "ASMedia" => ["ASMT1"], "ATP" => ["ATP SATA"], "BIWIN" => ["C6308", "G2242", "M6305"], "BlueRay" => ["SDM", "Ultra M8V"], "BR" => ["BR 60G"], "Cactus" => ["CactusFlashCard"], "CFD" => ["CSSD-S6"], "China" => ["CS2246", "DEPOSM", "EHSA", "ESA3", "Mit-SSD512A", "MSATA", "OSSD", "RTMMB", "S41CF", "SH00", "SSD128GBS800", "T480", "TP00"], "Chiprex" => ["S10T", "S8M", "S9M"], "Corsair" => ["CSSD-F", "CSSD-V", "Force MP"], "Crucial" => ["CT", "FCCT", "M4-CT"], "ExeGate" => ["EX27"], "Faspeed" => ["H5-240G"], "Foxline" => ["FLD", "FLSSD"], "GK" => ["SM2244LT"], "GOODRAM" => ["GOODRAM", "IR_SSDPR", "IR-SSDPR", "IRIDIUM", "IRP-SSDPR", "IRP_SSDPR", "SSDPR"], "GS Nanotech" => ["GSP", "GSS"], "GSemi" => ["GSDSM"], "HCiPC" => ["P2MSM"], "HGST" => ["HUP", "HUS"], "Hikvision"=> ["HKVSN", "HS-SSD"], "Hitachi" => ["HDS", "HDT", "HUA", "HT"], "HP" => ["FB0", "FB1", "GB0", "GB1000EA", "GJ0", "MB1000", "MB2000", "VB0", "VK0"], "HP Phison" => ["PSSBN"], "HPE" => ["LK04", "LK16", "MB0", "MB8", "MB4000", "MK0", "MM1000", "MM2000", "MR00024", "VR00024", "VR00048"], "Hyundai" => ["C2S3T"], "IBM/Hitachi" => ["IC25", "IC35"], "Indilinx" => ["IND-S", "InM2"], "Innodisk" => ["DEM24", "DES25"], "Intel" => ["N18A", "SSDPAMM", "SSDSA2S", "SSDSC2"], "Intenso" => ["JAJ", "lntenso"], "Iod" => ["MST1001"], "IPLEX" => ["TITAN256"], "KingDian" => ["SSD-S400"], "KingSpec" => ["ACJ", "ACS", "CHA", "KSQ120", "NT-32", "P3-512", "SPK", "Q-90", "Q-180", "Q-360"], "Kingston" => ["EK60H", "HyperX", "KC600", "RBU-SN"], "KIOXIA" => ["KBG", "KXG"], "Kross Elegance" => ["KE-SSD"], "Lite-On" => ["NVMe CA5", "PH2", "PH3", "PH4"], "Mach Xtreme" => ["MXSSD"], "MARSHAL" => ["MAL"], "Micron" => ["MTF"], "Mcpoint" => ["MC240"], "MEMXPRO" => ["mSATA M3B"], "MyDigitalSSD" => ["BP5", "SC2 M2", "SB M2", "SB2"], "Nfortec" => ["ALCYON"], "NTC" => ["NTC "], "OCZ" => ["AGILITY", "D2C", "D2R", "DEN", "OCZ", "VTX3"], "OSCOO" => ["OSC"], "OWC" => ["Mercury Electra", "Neptune"], "Pacific Sun" => ["PSM-"], "Pasoul" => ["OASDX"], "Phison" => ["P-SSD1800", "S10C", "S11-512G"], "Phytium" => ["S1200C"], "PNY" => ["69D03", "SSD2SC"], "Ramaxel" => ["RDM", "RTITF", "RTN"], "S3+" => ["S3SSD"], "Samsung" => ["MBG4", "MZM", "MZ7", "SG9"], "SanDisk" => ["CF Card", "DB40", "sandisk", "SDCFHS", "SDSA6MM", "SU04G", "SU08G", "TE2"], "Seagate" => ["2E256-TU2", "OOS500G", "OOS1000G", "OOS2000G", "ST", "ST_", "XA1920", "XF1230", "ZA1"], "SK hynix" => ["HFS", "SHGS"], "SNR" => ["SNR-ML"], "Solid" => ["SSD0240S00", "SSD0256S01"], "Terabit" => ["T50S3"], "Timetec" => ["35TT"], "Toshiba" => ["MG0", "Q200 EX", "SSD0256XQ", "THNSF"], "Transcend"=> ["TS", "USDU1"], "TREKSTOR" => ["TREKSTOR"], "Tronos" => ["TN240G"], "UMIS" => ["RPFTJ"], "Varro" => ["BULLDOZER"], "Wicgtyp" => ["M900-128"], "WDC" => ["HBS3A", "WD", "WDC WD10"], "Xinsujie" => ["XSJ"], "XPG" => ["SX8200"], "XUM" => ["HX128GSSD", "HX240GSSD", "HX256GSSD"], "Yeyian" => ["VALK"], "Zheino" => ["CHN", "CHN "], "ZTC" => ["ZTC-MS", "ZTC-SM"] ); my $ALL_DRIVE_VENDORS = "ADATA|A\-DATA|addlink|AFOX|Advantech|AEGO|AMD|Anobit|Aoluska|Apacer|Apple|ASUS|Aura|Avant|AVEXIR|Axiom|AXIOMTEK Corp\.|Bamba|BHT|BIOSTAR|BIWIN|BLUERAY|BRAVEEAGLE|Centerm|Chiprex|CLOVER|Colorful|Corsair|Crucial|CWDISK|Dahua|Dell|DEPO|DERLAR|DeTech|DGM|DOGFISH|DOGGO|DREVO|DRVEO|ELSKY|EMTEC|Espada|ExcelStor Technology|EZCOOL|e2e4|Faspeed|FASTDISK|FCS|FLEXXON|Fordisk|FORESEE|Foxline|FUJITSU|GALAX|Galaxy|Geil|GelL|Getrich|GIGABYTE|Gigastone|GLOWAY|Goldendisk|Goldenfir|Golden memory|Golden\-Memory|Goldkey|GOODRAM|Gost|GOWE|Hajaan|HECTRON|HEORIADY|HGST|Hitachi|Hoodisk|HP|HYPERDISK|Hyundai|i-FlashDisk|IBM-Hitachi|IBM|imation|Indilinx|INDMEM|Innodisk|InnoLite|INNOVATION[^\x00-\x7F]+IT|INTEL|INTENSO|JAMESDONKEY|JASTER|JD|JIAWEI|KDATA|Kimtigo|KINGBANK|Kingchuxing|KingDian|KingFast|KINGMAX|KingPower|KINGRICH|Kingsand|KINGSHARE|King Share|KingSpec|Kingspeed|Kingston|KIOXIA-EXCERIA|KLEVV|KLLISRE|KODAK|Kston|LDLC|LDNDISK|LenovoSPEED UP|Lenovo|Leven|LEXAR|Lite-On|LITEON|LITEONIT|LONDISK|LuminouTek|Magnetic Data|MARSHAL|MARVELL|Maximus|Maxmemroy|Maxtor|MediaMax|MENGMI|MicroData|MicroDream|Micron|Microtech|MidasForce|minisforum|MIXZA|Mushkin|Myung|Neo Forza|Netac|OCZ|OEM|ORICO|ORTIAL|OWC|oyunkey|PALIT|Patriot|PHINOCOM|Phison|Pichau|Platinet|PLEXTOR|PNY|PRETEC|Protectli|Qianghe|QNIX|QUANTUM|QUMO|Radeon|Ramaxel|Ramsta|RCESSD|Reeinno|RunCore|RZX|Samsung Electronics|SAMSUNG|SandForce|SanDisk|SATADOM|Seagate|SenDisk|ShanDianZhe|Shinedisk|SILICONMOTION|Silicon Motion|SK hynix|SMART|Smartbuy|SMI|Solidata|SPCC|SSSTC|Star Drive|SUNEAST|SuperMicro|SuperSSpeed|SuperTalent|Synology|T\-CREATE|T\-FORCE|TAISU|takeMS|TAMMUZ|TEAM|Teclast|TEUTONS|TEXTORM|TCSUNBOW|TEKET|THU|tigo|TopSunligt|TOSHIBA|Transcend|TurXun|TUSUNBOW|TwinMOS|UDinfo|UMAX|UMIS|UNIC2|V-Gen|Vaseky|VENO SCORP|Verbatim|VBOX|ViperTeq|VisionTek|WDC|Wdstars|Western Digital|Wintec|Wolf Aure|Xinhaike|XPG|XrayDisk|XSTAR|XUNZHE|YMTC|Zheino|ZhiTai|ZOTAC|ZOZT|2\-Power"; my @DRIVE_ADD_SIZE = ("OCZ", "ADATA", "A-DATA", "PATRIOT", "SPCC", "SAMSUNG", "CORSAIR", "HYPERDISK", "TOSHIBA"); my %DiskModelVendor = ( "SSD PLUS 480GB" => "SanDisk", "ULTIMATE CF CARD" => "Silicon Power" ); my %VendorDiskModel = ( "Apacer" => ["8GB SATA Flash Drive", "16GB SATA Flash Drive", "32GB SATA Flash Drive", "64GB SATA Flash Drive", "128GB SATA Flash Drive", "256GB SATA Flash Drive", "480GB SATA Flash Drive", "SATA Flash Drive"], "Blackpcs" => ["AS201 SSD"], "China" => ["128MB ATA Flash Disk", "240G SATA III SSD", "256GB PCS 2.5-inch SSD", "256GB QLC SATA SSD", "256GB SATA SSD", "BK-32GB MSATA SSD", "BK-64GB MSATA SSD", "CF", "CIE M8 M350 128GB W", "CNCTION", "DHMSR64GD81BC1QC", "EK V100", "Generic S050 Hard drive", "GM016", "GM16", "GM128", "GSDSL128TY2AAQGCX", "IM3D L06B B0KB", "JDa He SATA DISK", "JWX 16GB MSATA", "Kston128GB", "M.2 2280-1TB SSD", "M.2 2280 SATA SSD", "L06B B0KB", "M.2 SSD", "M10C", "Mit-SSD128A", "MLC", "mSATA-64GB SSD", "Msata", "NGFF 2242 32GB SSD", "NGFF 2280 256GB SSD", "NGFF 2280 1TB SSD", "OOS250G", "PATA SSD", "QST8-512", "R580", "REVOLUTIONS500_256", "S3 SSD", "Solid", "TPH00800640GB 0", "W2EM120GDTA-S71AAB-2Q4-SP", "W800SH 512GB SSD", "XJH"], "EVM" => ["512GB EVM SSD"], "Greenliant" => ["32GB ArmourDrive"], "Innodisk" => ["M.2 (S80) 3TE7"], "Integral" => ["V Series SATA SSD"], "Micron" => ["P400m100-MTFDDAK100MAN 118032953"], "Phison" => ["PS3108S8", "SSDS30256XQC800134237", "S11-256G-PHISON-SSD-B3"] ); foreach my $V (sort keys(%VendorDiskPrefix)) { foreach (sort @{$VendorDiskPrefix{$V}}) { $DiskVendor{$_} = $V; } } foreach my $V (sort keys(%VendorDiskModel)) { foreach (sort @{$VendorDiskModel{$V}}) { $DiskModelVendor{$_} = $V; } } # http://standards-oui.ieee.org/oui.txt my %IeeeOui = ( "0014ee" => "WDC", "000c50" => "Seagate", "0004cf" => "Seagate", "00080d" => "Toshiba", "000039" => "Toshiba", "001b44" => "SanDisk", "000cca" => "HGST", "0024e9" => "Samsung", "002538" => "Samsung", "0026b7" => "Kingston", "00000e" => "Fujitsu", "5cd2e4" => "Intel", "002303" => "Lite-On", "6479a7" => "Phison", "ace42e" => "SK hynix", "dc663a" => "Apacer" ); my %SerialVendor = ( "WD" => "WDC", "OCZ" => "OCZ", "PNY" => "PNY" ); my %FirmwareVendor = ( "MZ4O" => "Toshiba", "N1126F" => "Intenso", "S0222A0" => "Patriot", "SFDM104B" => "Apacer", "SFPS881A" => "China", "S0918A0" => "China", "S1211A0" => "Intenso", "S5FAM017" => "Phison", "T0722A0" => "Netac", "T0910A0" => "Intenso", "T0929A0" => "Intenso", "T1209A0" => "GOODRAM" ); my %MicroCode = ( "SandyBridge" => ["0x206a7"], "Westmere" => ["0x20655"] ); my %MicroCodeMicroArch; foreach my $MicroArch (sort keys(%MicroCode)) { foreach (sort @{$MicroCode{$MicroArch}}) { $MicroCodeMicroArch{$_} = $MicroArch; } } my %MicroArchFamily = ( "AMD" => { # AuthenticAMD "Geode" => { "5" => ["*"] }, "K6" => { "6" => ["*"] }, "K7" => { "7" => ["*"] }, "K8 Hammer" => { "15" => ["*"] }, "K10" => { "16" => ["*"] }, "K8 & K10 hybrid" => { "17" => ["*"] }, "K10 Llano" => { "18" => ["*"] }, "Bobcat" => { "20" => ["*"] }, "Bulldozer" => { "21" => ["1"] }, "Piledriver" => { "21" => ["2", "16", "19"] }, "Steamroller" => { "21" => ["48", "56"] }, "Excavator" => { "21" => ["96", "101", "112"] }, "Jaguar" => { "22" => ["0"] }, "Puma" => { "22" => ["48"] }, "Zen" => { "23" => ["1", "17", "32"] }, "Zen 2" => { "23" => ["49", "96", "113"] }, "Zen+" => { "23" => ["8", "24"] }, "Zen 3" => { "25" => ["33", "80"] } }, "Intel" => { # GenuineIntel "TigerLake" => { "6" => ["140"] }, "IceLake" => { "6" => ["126"] }, "CometLake" => { "6" => ["165", "166"] }, "KabyLake" => { "6" => ["142", "158"] }, "Goldmont plus" => { "6" => ["122"] }, "CannonLake" => { "6" => ["102"] }, "Skylake" => { "6" => ["78", "85", "94"] }, "Goldmont" => { "6" => ["92", "95"] }, "Broadwell" => { "6" => ["61", "71", "79", "86"] }, "Silvermont" => { "6" => ["55", "76", "77"] }, "Haswell" => { "6" => ["60", "63", "69", "70"] }, "IvyBridge" => { "6" => ["58", "62"] }, "Bonnell" => { "6" => ["28", "38", "54"] }, "SandyBridge" => { "6" => ["42", "45"] }, "Westmere" => { "6" => ["37", "44", "47"] }, "Nehalem" => { "6" => ["26", "30", "46"] }, "Penryn" => { "6" => ["23", "29"] }, "Core" => { "6" => ["15", "22"] }, "P6" => { "6" => ["7", "8", "9", "11", "13", "14"] }, "NetBurst" => { "15" => ["1", "2", "3", "4", "6"] } } ); my %MicroArchModel = ( "AMD" => { "Zen" => [ "Ryzen 5 PRO 2500U w/ Radeon Vega Mobile Gfx", "Ryzen 7 1700 Eight-Core Processor" ], "Zen+" => [ "Ryzen 7 2700 Eight-Core Processor", "Ryzen 7 2700X Eight-Core Processor" ], "Zen 2" => [ "Ryzen 5 3600 6-Core Processor" ], }, "Intel" => { "Haswell" => [ "Core i3-4150 CPU @ 3.50GHz" ], "SandyBridge" => [ "Core i5-2430M CPU @ 2.40GHz" ] } ); my %FamilyMicroArch; foreach my $MVendor (sort keys(%MicroArchFamily)) { foreach my $MicroArch (sort keys(%{$MicroArchFamily{$MVendor}})) { foreach my $Family (sort keys(%{$MicroArchFamily{$MVendor}{$MicroArch}})) { foreach (sort @{$MicroArchFamily{$MVendor}{$MicroArch}{$Family}}) { $FamilyMicroArch{$MVendor}{$Family}{$_} = $MicroArch; } } } } my %ModelMicroArch; foreach my $MVendor (sort keys(%MicroArchModel)) { foreach my $MicroArch (sort keys(%{$MicroArchModel{$MVendor}})) { foreach my $Model (sort @{$MicroArchModel{$MVendor}{$MicroArch}}) { $ModelMicroArch{$MVendor}{$Model} = $MicroArch; } } } my $DEFAULT_VENDOR = "China"; my %DistSuffix = ( "res7" => "rels-7", "res6" => "rels-6" ); my %DistPackage = ( "centos-release-5" => "centos-5", "centos-release-6" => "centos-6" ); my @DE_Package = ( [ "budgie-desktop", "Budgie" ], [ "ukui-desktop", "UKUI" ], [ "pantheon-xsession-settings", "Pantheon" ], [ "gnustep ", "GNUstep" ], [ "kdesktop-trinity", "Trinity" ], [ "manjaro-cinnamon-settings", "Cinnamon" ], [ "cinnamon-session", "Cinnamon" ], [ "deepin-manjaro", "Deepin" ], [ "ubuntudde-dde", "Deepin" ], [ "deepin-desktop-base", "Deepin" ], [ "manjaro-mate-settings", "MATE" ], [ "manjaro-lxde-settings", "LXDE" ], [ "task-lxde", "LXDE" ], [ "manjaro-lxqt-extra-settings", "LXQt" ], [ "task-lxqt", "LXQt" ], [ "manjaro-xfce", "XFCE" ], [ "manjaro-kde-settings", "KDE5" ], [ "plasma5-workspace", "KDE5" ], [ "plasma-desktop-5", "KDE5" ], [ "plasma-desktop 5", "KDE5" ], [ "task-plasma5", "KDE5" ], [ "plasma-workspace 4:5", "KDE5" ], [ "plasma5-plasma-workspace", "KDE5" ], [ "mate-session-manager", "MATE" ], [ "lxqt-session", "LXQt" ], [ "plasma-desktop 4:4", "KDE4" ], [ "kde-settings-plasma", "KDE4" ], [ "task-kde4", "KDE4" ], [ "drakconf-kde4", "KDE4" ], [ "kdebase4-workspace", "KDE4" ], [ "unity-session", "Unity" ], [ "gnome-flashback", "GNOME Flashback" ], [ "manjaro-gnome-assets", "GNOME" ], [ "gnome-session", "GNOME" ], [ "manjaro-awesome-settings", "Awesome" ], [ "manjaro-fluxbox-settings", "FluxBox" ], [ "i3-manjaro", "i3" ], [ "i3-wm", "i3" ], [ "manjaro-i3-settings", "i3" ], [ "xfce4-settings", "XFCE" ], # 3b85d1aeb4 XFCE before GNOME [ "task-xfce", "XFCE" ], [ "xfce4-session", "XFCE" ], [ "gnome-desktop", "GNOME" ], [ "openbox-lxde-session", "Openbox" ], [ "manjaro-openbox-settings", "Openbox" ], [ "enlightenment", "Enlightenment" ], [ "lxde", "LXDE" ], # BSD [ "x11/lumina", "Lumina" ], [ "x11/plasma5-plasma-desktop", "KDE5" ], [ "x11/cde", "CDE" ], [ "x11-wm/openbox", "Openbox" ], [ "x11-wm/awesome", "AwesomeWM" ], [ "x11-wm/i3", "i3" ], [ "x11-wm/i3-gaps", "i3" ], [ "x11-wm/fluxbox", "Fluxbox" ], [ "x11-wm/twm", "TWM" ], [ "x11-wm/marco", "Marco" ], [ "x11-wm/stumpwm", "StumpWM" ], [ "x11-wm/windowmaker", "Window Maker" ], [ "x11-wm/compton", "Compton" ], [ "x11-wm/picom", "Picom" ], [ "dwm", "DWM" ], [ "2bwm", "2bwm" ], ); my @DisplayServer_Package = ( [ "x11-server-xwayland", "Wayland" ], [ "xorg-server-xwayland", "Wayland" ], [ "xorg-x11-server-Xwayland", "Wayland" ], [ "xwayland", "Wayland" ], [ "x11-server-xorg", "X11" ], [ "xorg-x11-server-Xorg", "X11" ], [ "xserver-xorg", "X11" ], [ "xorg-x11-server", "X11" ] ); my %DisplayManager_Fix = ( "LIGHTDM" => "LightDM", "SLIM" => "SLiM", "KDE" => "KDM", "LY" => "Ly", "ENTRANCED" => "Entrance" ); my @ALL_DISPLAY_MANAGERS = qw(lightdm tdm sddm xdm gdm gdm3 slim kdm ldm lxdm cdm entranced mdm nodm pcdm wdm xenodm ly); my @DisplayManager_Package = (); foreach my $DM (@ALL_DISPLAY_MANAGERS) { push(@DisplayManager_Package, [$DM, uc($DM)]); } my %ChassisType = ( 1 => "Other", 2 => "Unknown", 3 => "Desktop", 4 => "Low Profile Desktop", 5 => "Pizza Box", 6 => "Mini Tower", 7 => "Tower", 8 => "Portable", 9 => "Laptop", 10 => "Notebook", 11 => "Hand Held", 12 => "Docking Station", 13 => "All In One", 14 => "Sub Notebook", 15 => "Space-saving", 16 => "Lunch Box", 17 => "Main Server Chassis", 18 => "Expansion Chassis", 19 => "Sub Chassis", 20 => "Bus Expansion Chassis", 21 => "Peripheral Chassis", 22 => "RAID Chassis", 23 => "Rack Mount Chassis", 24 => "Sealed-case PC", 25 => "Multi-system", 26 => "CompactPCI", 27 => "AdvancedTCA", 28 => "Blade", 29 => "Blade Enclosing", 30 => "Tablet", 31 => "Convertible", 32 => "Detachable", 33 => "IoT Gateway", 34 => "Embedded PC", 35 => "Mini PC", 36 => "Stick PC" ); my $DESKTOP_TYPE = "desktop|nettop|all in one|box|space\-saving|mini|tower|bus expansion"; my $SERVER_TYPE = "server|rack|blade"; my $MOBILE_TYPE = "notebook|laptop|portable|tablet|convertible|detachable|docking|stick|hand"; my $HID_BATTERY = "wacom|wiimote|hidpp_|controller_|hid\-|steam-controller|power_supply\/bms"; # SDIO IDs my %SdioInfo; my %SdioVendor; # SDIO IDs (Additional) my %AddSdioInfo; my %AddSdioVendor; # PNP IDs my %PnpVendor; my %SdioType = ( "01" => "uart", "02" => "bluetooth", "03" => "bluetooth", "04" => "gps", "05" => "camera", "06" => "phs", "07" => "network", "08" => "ata", "09" => "bluetooth" ); # Fix monitor vendor my %MonVendor = ( "ACI" => "Ancor Communications", # ASUS "ADI" => "ADI", "ADT" => "Advantech", "AGN" => "AG Neovo", "AIC" => "Arnos Instruments", # AG Neovo "ALB" => "Alba", "ALC" => "Alches", "AMH" => "AMH", "AMI" => "Amitech", "AMR" => "JVC", "AMT" => "AMT International", # AMTRAN? "AMW" => "AMW", "AOC" => "AOC", "AOP" => "AOpen", "APP" => "Apple Computer", "ARG" => "Alba", "ARM" => "Armaggeddon", "ASB" => "Prestigio", # ASBIS "ASM" => "Aosiman", "ATE" => "Megavision", "ATV" => "Ativa", "AVG" => "Avegant", "BAL" => "Balance", "BBK" => "BBK", "BBY" => "Insignia", "BEK" => "Beko", "BKM" => "Beike", "BLS" => "BUBALUS", "BMM" => "Proview", "BNQ" => "BenQ", "BOE" => "BOE", "BRA" => "Braview", "BSE" => "Bose", "BTC" => "RS", "BUF" => "Buffalo", "CAS" => "CASIO", "CCE" => "CCE", "CHH" => "Changhong Electric", "CIS" => "Cisco", "CLX" => "Claxan", "CMI" => "InnoLux Display", "CMN" => "Chimei Innolux", "CMO" => "Chi Mei Optoelectronics", "CND" => "CND", "COB" => "COBY", "COR" => "CPT", # Chunghwa Picture Tubes "COS" => "NVISION", "CPT" => "CPT", "CPQ" => "Compaq Computer", "CTL" => "CTL", "CTX" => "CTX", "CYS" => "Aosiman", "DIC" => "Dinner", "DNS" => "DNS", "DON" => "DENON", "DOS" => "Dostyle", "DSG" => "DSGR", "DSL" => "DisplayLink", "DTB" => "DTEN Board", "DUS" => "VOXICON", "DVA" => "GE", "DVM" => "RoverScan", "DWE" => "Daewoo", "EGA" => "Elgato", "EHJ" => "Epson", "ELE" => "Element", "ELO" => "Elo Touch", "ENM" => "ENMAR", "ENV" => "Envision Peripherals", "EPI" => "Envision", "EST" => "Estecom", "EQD" => "EQD", "EXN" => "Extron", "FAC" => "Yuraku", "FDR" => "Founder", "FLU" => "Fluid", "FSN" => "D&T", "FUJ" => "Fujitsu", "FUS" => "Fujitsu Siemens", "GAM" => "GAOMON", "GBA" => "GABA", "GBT" => "GIGABYTE", "GEC" => "Gechic", "GMI" => "XGIMI", "GRN" => "Green House", "GRU" => "Grundig", "GSM" => "Goldstar", "GSV" => "G-Story", "GWD" => "GreenWood", "HAI" => "Haier", "HAN" => "Cbox", "HAR" => "Haier", "HAT" => "Huion", "HCD" => "ViewSonic", "HCM" => "HCL", "HED" => "Hedy", "HEI" => "Hyundai", "HII" => "Higer", "HIS" => "Hisense", "HKC" => "HKC", "HRE" => "Haier", "HSG" => "Hannspree", "HSL" => "Hansol", "HVR" => "HVR", # VR Headsets "HWP" => "HP", "HPC" => "Erisson", "HPN" => "HP", "HRT" => "Hercules", "HSE" => "Hisense", "HUG" => "Hugon", "HUN" => "Huion", "HUY" => "HUYINIUDA", "HWV" => "HUAWEI", "HXF" => "BlueCase", "HXV" => "iQual", "HYC" => "Pixio", "IBM" => "IBM", "ICB" => "Pixio", "ICP" => "IC Power", "IGM" => "Videoseven", "IMP" => "Impression", # V7 "INC" => "INCA", "INL" => "InnoLux Display", "INN" => "PRISM+", "INZ" => "Insignia", "ITA" => "Easy Living", "ITR" => "INFOTRONIC", "IVM" => "Iiyama", "IVO" => "InfoVision", "JDI" => "JDI", # Japan Display Inc. "JEN" => "Jean", "JVC" => "JVC", "JXC" => "JXC", # Shenzhen JingXingCheng "KDM" => "Korea Data Systems", "KIV" => "Kivi",, "KMR" => "Kramer", "KGN" => "Kogan", "KOA" => "Konka", "KOS" => "KOIOS", "KTC" => "KTC", "LDL" => "LDLC", "LGD" => "LG Display", "LGP" => "LG Philips", "LHC" => "Denver", "LNX" => "Lanix", "LPL" => "LG Philips", "LTN" => "Lite-On", "LRN" => "Doffler", "MAC" => "MacroSilicon", "MAX" => "Belinea", "MBB" => "MAIBENBEN", "MCE" => "Metz", "MEC" => "Medion Akoya", "MEI" => "Panasonic", "MEK" => "MEK", "MEL" => "Mitsubishi", "MJI" => "Marantz", "MP_" => "Monoprice", "MPC" => "Monoprice", "MSC" => "Syscom", "MSH" => "Microsoft", "MSI" => "MSI", "MS_" => "Sony", "MST" => "MStar", "MTC" => "Mitac", "MTX" => "Matrox", "MUL" => "Multilaser", "MUS" => "Mecer", "MZI" => "Digital Vision", "NCI" => "NECCI", "NCP" => "PANDA", # Nanjing CEC Panda "NEC" => "NEC", "NFC" => "NFREN", "NIK" => "Niko", "NLK" => "MStar", "NOA" => "NOA VISION", "NRC" => "AOC", "NSO" => "Neso", "NVD" => "Nvidia", "NVI" => "NVISION", "NVT" => "Novatek", "OCM" => "oCOSMO", "ONK" => "Onkyo", "ONN" => "ONN", "OPT" => "Optoma", "ORN" => "Orion", "OTM" => "Optoma", "OTS" => "AOC", "OTT" => "Ottagono", "OWC" => "OWC", "PCK" => "SENSY", "PEA" => "Pegatron", "PEB" => "Proview", "PEG" => "PEGA", "PGE" => "GNR", "PGS" => "Princeton", "PIO" => "Pioneer", "PKB" => "Packard Bell", "PKR" => "Parker", "PLC" => "Philco", "PLN" => "Planar", "PLT" => "PiLot", "PNR" => "Planar", "PNS" => "Pixio", "PRE" => "Prestigio", "PRT" => "Princeton", "PTH" => "TVS", "PTS" => "Plain Tree Systems", "QBL" => "QBell", "QDS" => "Quanta Display", "QMX" => "Gericom", "QSM" => "Qushimei", "QUN" => "Lenovo", "RDS" => "KDS", "REC" => "Reconnect", "RJT" => "Ruijiang", "RKU" => "Roku", "ROL" => "Rolsen", "RUB" => "Rubin", "RZR" => "Razer", "SAN" => "Sanyo", "SCE" => "Sun", "SCN" => "Scanport", "SEE" => "SEEYOO", "SHP" => "Sharp", "SII" => "Skyworth", "SNN" => "SUNNY", "SNY" => "Sony", "SPT" => "Sceptre Tech", "SPV" => "Sunplus", "SRD" => "Haier", "STC" => "Sampo", "STI" => "Semp Toshiba", "STK" => "S2-Tek", "SUN" => "Sun", "SVA" => "SVA", "SVR" => "Sensics", "SYL" => "Sylvania", "SYN" => "Olevia", "SZM" => "Mitac", "TAR" => "Targa Visionary", "TAT" => "Tatung", "TCL" => "TCL", "TEO" => "TEO", "TEU" => "Relisys", "TLX" => "Tianma XM", "TNJ" => "Toppoly", "TOP" => "TopView", "TPV" => "Top Victory", "TRL" => "Royal Information", "TSD" => "TechniMedia", "UMC" => "UMC", "UPS" => "UpStar", "VBX" => "VirtualBox", "VES" => "Vestel Elektronik", "VIT" => "Vita", "VJK" => "HannStar", "VLV" => "Valve", "VSC" => "ViewSonic", "VSN" => "Videoseven", "VTK" => "Viotek", "WAC" => "Wacom", "WAM" => "Pixio", "WIM" => "Wimaxit", "WNX" => "Wincor Nixdorf", "WTC" => "Waytec", "XER" => "Xerox", "XMD" => "Xiaomi", "XMI" => "Mi", "XSC" => "Immer", "XVS" => "XVision", "XYE" => "Xiangye", "YAK" => "Yakumo", "YLT" => "Panasonic", "YMH" => "Yamaha", "ZRN" => "Zoran" ); my %VendorMon = ( "Acer" => ["ABO", "ACR", "API"], "Achieva Shimian" => ["ACB", "ACH"], "ASUS" => ["ASU", "AUS", "WWW"], "AU Optronics"=> ["AUO", "DMO"], "COMPAL" => ["CPL", "WOR"], "Dell" => ["DEL", "LNK"], "Eizo" => ["EIZ", "ENC"], "ELSA" => ["ELA", "ELS"], "eMachines" => ["EMA", "EMI"], "Gateway" => ["GTW", "GWY"], "HannStar" => ["HSD", "HSP"], "Hitachi" => ["HEC", "HIT", "HTC"], "Hyundai ImageQuest" => ["HIQ", "IQT"], "KAZUK" => ["KAZ"], "Lacie" => ["LAC", "LCA"], "Lenovo" => ["LCS", "LEN", "LEO", "QUA", "QWA"], "Medion" => ["MEA", "MEB", "MED"], "Nixeus" => ["NIX", "NTI"], "Philips" => ["PFL", "PFT", "PHI", "PHL", "PHP", "PHT"], "Polaroid" => ["MKN", "POL"], "Positivo" => ["NON", "POS"], "Samsung" => ["SAM", "SDC", "SEC", "SEM", "STN", "_YM"], "Seiki" => ["KDD", "SEK"], "Thomson" => ["PKV", "TMN", "TTE"], "Toshiba" => ["LCD", "TOS", "TSB"], "Vizio" => ["IZI", "VIZ", "VZO"], "Westinghouse" => ["WDE", "WDT", "WEH", "WET"] ); foreach my $V (sort keys(%VendorMon)) { foreach (sort @{$VendorMon{$V}}) { $MonVendor{$_} = $V; } } # Repair vendor of some motherboards and mmc devices # It is needed for catalog of public reports on github my %VendorModels = ( "Acer" => [ "ZA10_KB" ], "ASRock" => [ "4CoreDual-VSTA", "4CoreDual-SATA2", "4Core1600-GLAN", "4Core1600-D800", "4CoreN73PV-HD720p", "775XFire-RAID", "775XFire-RAID", "775VM800", "775Twins-HDTV", "775i945GZ", "775i65GV", "775i65PE", "775i48", "939Dual-SATA2", "939NF6G-VSTA", "945GCM-S", "ALiveDual-eSATA2", "ALiveNF4G-DVI", "ALiveNF6P-VSTA", "ALiveNF6G-GLAN", "ALiveNF7G-HDready", "ALiveSATA2-GLAN", "AM2NF6G-VSTA", "G31M-S", "K8NF4G-SATA2", "K8Upgrade-NF3", "K8Upgrade-VM800", "P4VM900-SATA2", "P4VM890", "P4Dual-915GL", "P4i48", "P4i65G", "P4i65GV", "P4VM8", "Wolfdale1333-GLAN", "Wolfdale1333-D667", "775Dual-VSTA", "775Dual-880Pro", "A780GXE/128M" ], "ECS" => [ "848P-A7", "965PLT-A", "H110M4-C2H", "K8M800-M2", "nForce4-A939", "nForce4-A754", "nForce", "nVidia-nForce", "RS480-M" ], "ASUSTek Computer" => [ "C51MCP51", "P5GD1-TMX/S", "RC410-SB450" ], "MSI" => [ "MS-7210", "MS-7030", "MS-7025", "MS-7210 100" ], "SiS Technology" => [ "SiS-661", "SiS-649", "SiS-648FX", "SiS-650GX" ], "Samsung" => [ "AWMB3R", "CJNB4R", "MAG2GC", "MCG8GA", "MCG8GC" ], "SanDisk" => [ "DF4032", "DF4064", "DF4128", "SDW64G", "SL32G" ], "SK hynix" => [ "HBG4a", "HBG4e", "HCG8e" ], "OEM" => [ "EIRD-SAM" ] ); my %VendorByModel; foreach my $V (sort keys(%VendorModels)) { foreach (sort @{$VendorModels{$V}}) { $VendorByModel{$_} = $V; } } my %PciClassType = ( "01" => "storage", "02" => "network", "03" => "graphics card", "04" => "multimedia", "04-00" => "video", "04-01" => "sound", "04-03" => "sound", "05" => "memory controller", "05-00" => "ram memory", "06" => "bridge", "07" => "communication controller", "07-03" => "modem", "08" => "system peripheral", "08-05" => "sd host controller", "09" => "input", "0a" => "docking station", "0b" => "processor", "0b-40" => "co-processor", "0c" => "serial bus controller", "0c-00" => "firewire controller", "0c-03" => "usb controller", "0c-02" => "ssa", "0c-05" => "smbus", "0c-06" => "infiniband", "0c-09" => "canbus", "0d" => "wireless controller", "0d-00" => "irda", "0d-11" => "bluetooth", "0e" => "intelligent controller", "0f" => "communications controller", "10" => "encryption controller", "11" => "signal processing", "12" => "processing accelerators" ); my %UsbClassType = ( "01" => "audio", "02" => "network", "02-02" => "modem", "03" => "human interface", "03-01-01" => "keyboard", "03-01-02" => "mouse", "05" => "physical interface", "06" => "imaging", "07" => "printer", "08" => "storage", "08-06-50" => "disk", "09" => "hub", "0a" => "cdc data", "0b" => "smartcard", "0d" => "content security", "0e" => "video", "dc" => "diagnostic", "e0" => "wireless", "e0-01-01" => "bluetooth", "ef" => "miscellaneous", "58" => "xbox" ); my %BatType = ( "lithium-ion" => "Li-ion", "LiIon" => "Li-ion", "lithium-polymer" => "Li-poly" ); my @WrongAddr = ( # MAC/clientHash(MAC) "00-00-00-00-00-00", "9B615E889BC3EDDF63600C8DAA6D56CC", "FF-FF-FF-FF-FF-FF", "2F847FFB96ED2B0B7C2AB39815DC6545", "00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00", "47D6D280AB9F429EB219C6991590CEBE", "DEFAULT", "ACA66517F781B3D0DC573F9992EC6E44", # Huawei modem "0C-5B-8F-27-9A-64", "F8AFE52EC893B5F610764246CE0EC5DD", # Qualcomm Atheros AR8151 "00-20-07-01-16-06", "2698F3BD50B6E7317C050EABCBFCDD61", # Realtek RTL8111/8168/8411 "00-0B-0E-0F-00-ED", "B65E4A84BDF8C8FAF775D824E93895E5", "ED-0B-00-00-E0-00", "C8725A03752162516AC1D2736D4BCA7D", "16A64DBFF00A86E93CBF2DBED01DB771", # Realtek RTL8169 "4A0B520A3AE049F53532F8A53170BD2B", # NVIDIA Ethernet Controller "04-4B-80-80-80-03", "390043493F55307CC32EBD5A69443418", "04-4B-80-80-80-04", "5CEE6D893998E9F34E1452DFD0AD4127", "04-4B-80-80-80-F0", "3EEAB05124DE1FB83AD0BEAD31CE981E", # DM9601 Fast Ethernet Adapter "00-E0-4C-53-44-58", "68856DC22FD7A072F83ABA8EA9CC770F", # AR8162 Fast Ethernet vs RTL810xE PCIe Fast Ethernet "D51C765DB99A8E48472B495E83DE44B0", # MCP67 Ethernet vs MCP77 Ethernet "1E82FF14DD3C1B43B1A8D94630C90260", # MCP51 Ethernet vs MCP55 Ethernet "385BFD77E97DC0FD5A18671518FF4251", # RTL-8100/8101L/8139 PCI Fast Ethernet vs AR8152 v2.0 Fast Ethernet "9F797A8831BF6EF57154EE9647731DFC", # ZTE Mobile Broadband Station vs ZXIC Mobile Boardband "D8CE7A717259ADA5053B10C1F7705ECD", # Huawei E398 LTE/UMTS/GSM Modem "58-2C-80-13-92-63", "7D2C0D14714C1351D47DDB71E5A5ED41", "00-1E-10-1F-00-00", "07DECBE266CF024E4BC6DA9960DECDD4", # Qualcomm Atheros Attansic L2 Fast Ethernet "00-13-74-00-5C-38", "9DD557B66D30EAD5D6175340584CB612", # Yota LU150 "00-09-3B-F0-1A-40", "F6E8320D9A80AEE615D4CFA2A7CF40BD", # ME936 LTE/HSDPA+ 4G modem "02-2C-80-13-92-63", "8D0D443BD07047D7664DDD7A7385642A", # Migrated devices "0B4855DFCBE7B2B60B64315E21AC59B8", "3A1ED114C0B16F7FDDA2430FBABC1D82", "86AE125EBD97E64A59E25B250F7B36DE", "00BFE151A76E569ADB46E0DD338B8656", "8AFE7BDBD8B60C9645EDA141A9757E0A", "2DDCA0957AD7C256C77DFC231D80491B", "BBF288DD430B105563756C4194B5142B", # Others "00-DD-00-00-00-00", "631A71585F7CE74AE0C6E575DD1F4B31", "88-88-88-88-87-88", "FD0368E31788DE08AEC3C0F414D65552", "00-00-00-00-00-05", "4291656957E4CF9952D94E3DEF386CBF", "00-FF-00-00-00-00", "779F2E940C240A44289BB71F86A99BE5", "00-00-00-00-00-30", "6A34F992175D0D2ACD794FB107791EBF", "00-00-00-00-00-10", "CB29E07B8A25732D808E4DF3B26718E2", "00-13-74-00-00-00", "E5A433E40C7D5C05E1F82A0C86983656", "00-11-22-33-44-55", "FCE26206D805FEA1EB06C7210F054356", "66-77-44-22-33-11", "87880BCC6946BC2190412EA03A6E9B37", "00-00-00-00-00-03", "C184F6B8763E7AE4985EF4E3AAAD9B32", "66-77-44-22-33-10", "356D3DDEDB928F49B5FFAEBF18BADC65", "00-0B-E0-F0-00-ED", "36E19104CCF3BF32183B47AF9B00FA68", "00-E0-12-34-56-78", "B79FC64470AF23CD8893C1A85520D5A9" ); my @ProtectedLogs = ( "acpidump", "acpidump_decoded", "arcconf", "biosdecode", "cpuid", "dev", "dmidecode", "dmi_id", "drm_info", "edid", "ethtool_p", "fdisk", "glxinfo", "hciconfig", "hdparm", "hwinfo", "ifconfig", "ip_addr", "lsb_release", "lsb-release", "lsblk", "lscpu", "lsmod", "lspci", "lspci_all", "lsusb", "mmcli", "opensc-tool", "os-release", "power_supply", "sensors", "smartctl", "smartctl_megaraid", "system-release", "upower", "usb-devices", "xrandr", "xrandr_providers", # *BSD "apm", "atactl", "camcontrol", "devinfo", "diskinfo", "geom", "gpart", "gpart_list", "hwstat", "kldstat", "mfiutil", "modstat", "neofetch", "ofwdump", "pciconf", "pcictl", "pcictl_n", "pcidump", "sysinfo", "usbconfig", "usbctl", "usbdevs", "x86info", # Android "getprop" ); my @ProtectFromRm = ( "dmesg", "dmesg.1" ); my %BusOrder = ( "NVME"=>"M", "IDE"=>"L", "SERIAL"=>"K", "SDIO"=>"J", "SCSI"=>"I", "PCMCIA"=>"H", "PARALLEL"=>"G", "PS/2"=>"F", "INT"=>"E", "SYS"=>"D", "EISA"=>"C", "USB"=>"B", "PCI"=>"A" ); my %TypeOrder = ( "storage"=>"D", "network"=>"C", "sound"=>"B", "graphics card"=>"A" ); my $ALL_CDROM_VENDORS = "AOPEN|ASUS|ASUSTek Computer|ATAPI|BENQ|CDEmu|COMBO|Compaq|Hewlett-Packard|Hitachi|HL-DT-ST|HP|JLMS|LG|Lite-On|LITEON|MAD DOG|MATSHITA|Memorex|MITSUMI|NEC Computers|Optiarc|PBDS|PHILIPS|PIONEER|PLDS|PLEXTOR|QSI|Samsung Electronics|Slimtype|Sony|TEAC|Toshiba|TSSTcorp|ZTE"; my $ALL_VENDORS = "Brother|Canon|Epson|HP|Hewlett\-Packard|Kyocera|Samsung|Xerox"; my $ALL_MON_VENDORS = "Acer|ADI|AGO|ALP|Ancor Communications Inc|AOC|Apple|Arnos Instruments|AU Optronics Corporation|AUS|BBY|BEK|BenQ|BOE Technology Group Co\., Ltd|Chi Mei Optoelectronics corp\.|CHI|CIS|CMN|CNC|COMPAL|COMPAQ|cPATH|CRO|CVTE|DELL|DENON, Ltd\.|Eizo|ELO|EQD|FNI|FUS|Gateway|GRUNDIG|HannStar Display Corp|HII|Hisense|HKC|HP|HPN|IBM|Idek Iiyama|ITR INFOTRONIC|IQT|KOA|Lenovo Group Limited|LGD|LG Electronics|LPL|Maxdata\/Belinea|MEB|Medion|Microstep|MS_ Nvidia|MSH|MST|MStar|NEC|NEX|Nvidia|OEM|ONKYO Corporation|Panasonic|Philips|Pioneer Electronic Corporation|PLN|Princeton Graphics|PRI|PKB|Samsung|Sangyo|Sceptre|SDC|Seiko\/Epson|SEK|SHARP|SONY|STN|TAR|Targa|Tech Concepts|TOSHIBA|Toshiba Matsushita Display Technology Co\., Ltd|UMC|Vestel|ViewSonic|VIZ|Wacom Tech|WDT"; my $ALL_MEM_VENDORS = "Ankowall|Atermiter|Axiom|BiNFUL|CFD|CompuStocx|DATEN|DERLAR|DeTech|DigiBoard|e2e4|HEXON|imation|JINSHA|KETECH|Kimtigo|KingBank|Kinlstuo|Kllisre|LEADMAX|MARKVISION|MINPO|MLLSE|MTASE|OSCOO|PLEXHD|Princeton|Ramsta|Reboto|RZX|Saikano|SemsoTai|SHARETRONIC|STARKORTIS|SUPER KINGSTEK|Team|Tigo|TIMETEC|TOP MEDIA|TRS Star|Vaseky|ZION"; my @KNOWN_BSD = ("clonos", "desktopbsd", "dragonfly", "freenas", "fuguita", "furybsd", "ghostbsd", "hardenedbsd", "hellosystem", "libertybsd", "midnightbsd", "nomadbsd", "opnsense", "os108", "pcbsd", "pfsense", "truenas", "trueos", "xigmanas", "arisblu"); my $KNOWN_BSD_ALL = join("|", @KNOWN_BSD); my $USE_DIGEST = 0; my $USE_DIGEST_ALT = "sha512sum"; my $USE_DUMPER = 0; my $USE_JSON_XS = 0; my $USE_IA = 0; my $HASH_LEN_CLIENT = 32; my $UUID_LEN_CLIENT = 32; my $SALT_CLIENT = "GN-4w?T]>r3FS/*_"; my $MAX_LOG_SIZE = 1048576; # 1Mb my @LARGE_LOGS = ("xorg.log", "xorg.log.1", "dmesg", "dmesg.1", "boot.log"); my $EMPTY_LOG_SIZE = 150; sub getSha512L($$) { my ($String, $Len) = @_; my $Hash = undef; if($USE_DIGEST) { $Hash = Digest::SHA::sha512_hex($String); } else { # No module installed $Hash = qx/echo -n \'$String\' | $USE_DIGEST_ALT 2>&1/; if($Hash=~/([\da-f]{128})/) { $Hash = $1; } else { return $String; } } return substr($Hash, 0, $Len); } sub clientHash(@) { my $Subj = shift(@_); my $Len = $HASH_LEN_CLIENT; if(@_) { $Len = shift(@_); } if(length($Subj)==$Len and $Subj=~/\A[\dA-F]+\Z/) { # Hash return $Subj; } return uc(getSha512L($Subj."+".$SALT_CLIENT, $Len)); } sub encryptSerialsInPaths($) { my $Content = $_[0]; my %DiskSer = (); while($Content=~/((\/|^)(ata|nvme|scsi)-[^\s]*_)(.+?)(\-part|[\s\n,])/mg) { $DiskSer{$4} = 1; } foreach my $Ser (sort keys(%DiskSer)) { my $Enc = clientHash($Ser); if($Enc eq $Ser) { next; } $Content=~s/_\Q$Ser\E\b/_$Enc/g; # /dev/disk/by-id/ata-Samsung_SSD_850_EVO_250GB_XXXXXXXXXXXXXXX } return $Content; } sub encryptSerials(@) { my $Content = shift(@_); my $Tag = shift(@_); my $Name = undef; if(@_) { $Name = shift(@_); } my $Lower = undef; if(@_) { $Lower = shift(@_); } my %Serials = (); while($Content=~/\Q$Tag\E\s*[:=]\s*"?([^"]+?)"?\s*\n/g) { $Serials{$1} = 1; } foreach my $Ser (sort keys(%Serials)) { if(grep {$Ser eq $_} ("Not Specified", "To Be Filled By O.E.M.", "No Asset Information", "None", "Not Available")) { next; } my $Enc = undef; if($Lower) { $Enc = clientHash(lc($Ser)); } else { $Enc = clientHash($Ser); } if(index($Ser, ":")!=-1 and index($Ser, ".")!=-1) { # 0000:00:1a.0 if($Name and grep { $Name eq $_ } ("hwinfo", "usb-devices")) { $Enc = "..."; } else { next; } } if($Enc eq $Ser) { next; } $Content=~s/(\Q$Tag\E\s*[:=]\s*"?)\Q$Ser\E("?\s*\n)/$1$Enc$2/g; if($Name and $Name eq "hwinfo") { $Content=~s/_\Q$Ser\E\b/_$Enc/g; # /dev/disk/by-id/ata-Samsung_SSD_850_EVO_250GB_XXXXXXXXXXXXXXX } } return $Content; } sub encryptUUIDs(@) { my $Content = shift(@_); my $Hash = undef; if(@_) { $Hash = shift(@_); } my %UUIDs = (); while($Content=~/([Xa-f\d]{8}-[Xa-f\d]{4}-[Xa-f\d]{4}-[Xa-f\d]{4}-[Xa-f\d]{12}|[a-zA-Z\d]{6}-[a-zA-Z\d]{4}-[a-zA-Z\d]{4}-[a-zA-Z\d]{4}-[a-zA-Z\d]{4}-[a-zA-Z\d]{4}-[a-zA-Z\d]{6}|[a-zA-Z\d]{64})/gi) { $UUIDs{$1} = 1; } foreach my $UUID (sort keys(%UUIDs)) { my $Enc = clientHash(lc($UUID), $UUID_LEN_CLIENT); $Enc = strToUUID($Enc); if($Hash) { $Enc=~s/\A([A-F\d]{5})/HASH_/g; } $Content=~s/\Q$UUID\E/$Enc/g; } %UUIDs = (); while($Content=~/[ \/]([a-fA-F\d]{4}-[a-fA-F\d]{4})\s/g) { $UUIDs{$1} = 1; } foreach my $UUID (sort keys(%UUIDs)) { my $Enc = clientHash(lc($UUID), $UUID_LEN_CLIENT); $Enc=~s/\A(\w{4})(\w{4}).+\Z/$1-$2/; $Content=~s/\Q$UUID\E/$Enc/g; } return $Content; } sub strToUUID($) { my $Str = $_[0]; $Str=~s/\A(\w{8})(\w{4})(\w{4})(\w{4})(\w{12})\Z/$1-$2-$3-$4-$5/; return $Str; } sub hideDevDiskUUIDs($) { return hideByRegexp($_[0], qr/([a-f\d]{8}\Q\x2d\E[a-f\d]{4}\Q\x2d\E[a-f\d]{4}\Q\x2d\E[a-f\d]{4}\Q\x2d\E[a-f\d]{12})/); } sub encryptWWNs($) { my $Content = $_[0]; my %WWNs = (); while($Content=~/\/wwn-0x(.+?)\W/g) { $WWNs{$1} = 1; } foreach my $WWN (sort keys(%WWNs)) { my $Enc = clientHash($WWN); $Content=~s/(wwn-0x)\Q$WWN\E/$1$Enc/g; # wwn-0xXXXXXXXXXXXXXXXX } return $Content; } sub hideWWNs($) { my $Content = $_[0]; $Content=~s/(LU WWN Device Id:\s*\w \w{6} )\w+(\n|\Z)/$1...$2/; $Content=~s/(IEEE EUI-64:\s*\w{6}\s)\w+(\n|\Z)/$1...$2/; return $Content; } sub hideTags($$) { my ($Content, $Tags) = @_; $Content=~s/(($Tags)\s*[:=]\s*).*?(\n|\Z)/$1...$3/g; return $Content; } sub hideAAC($) { my $Content = $_[0]; $Content=~s/(AAC\d+: serial ).+?(\n|\Z)/$1...$2/g; return $Content; } sub hideAudit($) { my $Content = $_[0]; $Content=~s/(acct\=)"[^"]*"/$1=XXX/g; $Content=~s/(hostname\=)[^\s]+ /$1... /g; return $Content; } sub hideEmail($) { my $Content = $_[0]; $Content=~s/([<\(])[^()<>\s]+\@[^()<>\s]+([\)>])/$1\XXX\@\XXX$2/g; $Content=~s/([\s\(\<\'\=]| at | to )[\w\.\-]+\@[\w\.\-]+\.[a-zA-Z]{2,}([\:\s\)\>]|\.\n)/$1\XXX\@\XXX$2/g; $Content=~s/ [\w\.\-]+\@[\w\-]+:/ \XXX\@\XXX:/g; # BSD return $Content; } sub hideDmesg(@) { my $Content = shift(@_); my $Hash = undef; if(@_) { $Hash = shift(@_); } if($Opt{"ShowDmesg"}) { $Content=~s/.+\] (audit|kauditd_printk_skb): .+(\n|\Z)//g; $Content=~s/.+ addr=\? terminal=\?.+(\n|\Z)//g; } $Content = hideTags($Content, "SerialNumber"); $Content = hideHostname($Content); $Content = hideIPs($Content); $Content = encryptMACs($Content); $Content = hidePaths($Content); $Content = hideAAC($Content); $Content = encryptUUIDs($Content, $Hash); $Content = hideAudit($Content); $Content = hideEmail($Content); $Content=~s/((SerialNumber|Ethernet address)\s*[:=]\s*).+/$1.../g; $Content=~s/(Serial Number).+/$1.../g; $Content=~s/(\s+s\/n\s+)[^\s]+/$1.../g; $Content=~s/(removable serial\.).+/$1.../g; $Content=~s/((serial|serial_number|serialno)\s*=\s*)[^\s]+/$1.../g; $Content=~s/( serial# ).+/$1.../g; $Content=~s/(- serial #).+/$1.../g; $Content=~s/( SN ).+?( MFG )/$1...$2/g; $Content=~s/( serial_number\().+(\))/$1...$2/g; $Content=~s/( Serial\t\t: )[^\s]+(\n|\Z)/$1...$2/g; $Content=~s/( serial number is | serial number: ).+/$1.../g; $Content=~s/((Autodisabling the use of server inode numbers on|CIFS: Attempting to mount)\s*).+/$1.../g; $Content=~s/( ssid=).+/$1.../g; $Content=~s/( set ssid ).+/$1.../g; $Content=~s/(\[assoc_ssid:).+?(\])/$1...$2/g; $Content=~s/( candidate:\s*)[^(\n]+/$1.../g; $Content=~s/( of user\s*).+/$1.../g; $Content=~s/[^\'\s]+(\s*Secure Boot Module Signature key:\s*)[^\'\s]+/...$1.../g; $Content=~s/(unit=[\w\-]+\@(dev-mapper|media)-)[^\s]+/$1.../g; $Content=~s/(rd.lvm.lv=)[^\s]+/$1.../g; $Content=~s/(Cryptography Setup for\s+)[^\s]+/$1.../g; $Content=~s/(BTRFS: device label\s+).+?(\s+devid)/$1...$2/g; $Content=~s/(volume group\s+)"[^\s\"]+?"/$1"..."/g; $Content=~s/(process) '[^\/].+?' (started with executable stack)/$1 '...' $2/g; $Content=~s/(Bluetooth: hci\d+: )[\w\-\.]+(\n|\Z)/$1...$2/g; $Content=~s/(dracut: Found )\/.+( on)/$1...$2/g; $Content=~s/(Invalid section header).+/$1 '...'/g; $Content=~s/(: dev-mapper-)[^\.:\n]+?\.(\w+:)/$1...$2/g; $Content=~s/( input: ).+?( \(AVRCP\))/$1...$2/g; $Content=~s/(property_set\(".+\.serialno", ").+?("\))/$1...$2/g; $Content=~s/(PropSet Error:\[.+\.serialno:).+?(\])/$1...$2/g; $Content=~s/(snd[-_](ca0106|emu10k1x).+? Serial ).+/$1.../g; $Content=~s/(CIFS:? VFS: \\\\)[^\s]+?( )/$1...$2/g; $Content=~s/(Mounting volume \').+?(\')/$1...$2/g; $Content=~s/(BAD_NETWORK_NAME: ).+/$1.../g; $Content=~s/(Set up automount ).+/$1.../g; $Content=~s/(\/run\/systemd\/generator\/(dev-mapper|media)-)[^\]\s\n,]+/$1.../g; $Content=~s/( server .+? in cell ).+?( )/$1...$2/g; $Content=~s/( for cell ).+( have expired )/$1...$2/g; $Content=~s/(dev-disk-by\\x2d(partuuid-|uuid-|id-wwn))[xa-fA-F\d\\]{12,48}(part\d+|)(\.)/$1...$4/g; $Content=~s/(dev-disk-by\\x2did-(ata|usb|nvme).+?_)[^_]+?(\\x2d.+?\.)/$1...$3/g; $Content=~s/( Checking was requested for )"[^\n]+?( but )/$1...$2/g; $Content=~s/(systemd-fstab-generator\[\d+\]: ).+/$1.../g; if(isBSD() or $Opt{"ForBSD"}) { $Content=~s/(> serial\.).+/$1.../g; $Content=~s/( serial ).+?( type )/$1...$2/g; $Content=~s/(nvme\d: .+, serial ).+/$1.../g; $Content=~s/(USBMIC Serial )\w+/$1.../g; $Content=~s/(uhidpp\d .+ serial ).+/$1.../g; } return $Content; } sub hideHostname($) { my $Content = $_[0]; $Content=~s/(Set hostname to\s+).+/$1.../g; $Content=~s/(Hostname set to\s+).+/$1.../g; return $Content; } sub hideHost($) { my $Content = $_[0]; $Content=~s/(Current Operating System:\s+[^\s]+)\s+[^\s]+/$1 NODE/g; return $Content; } sub hidePaths($) { my $Content = $_[0]; my @Paths = ("storage", "mount", "home", "media", "data", "shares", "vhosts", "mapper", "photos", "snap", "shm", "srv/nfs", "dev/serno", "serno", "exports", "usr/obj", "mnt"); if(isBSD()) { push(@Paths, "diskid", "ufsid"); } foreach my $Dir (@Paths) { $Content = hideByRegexp($Content, qr/\Q$Dir\E\/([^\s'")<\\]+)/); } return $Content; } sub hideLVM($) { my $Content = $_[0]; $Content = hideByRegexp($Content, qr/vg_(.+?)\b/); $Content = hideByRegexp($Content, qr/([^\s]+)--vg-[^\s]+/); return $Content; } sub hideIPs($) { my $Content = $_[0]; # IPv4 $Content=~s/\d+\.\d+\.\d+\.\d+/XXX.XXX.XXX.XXX/g; $Content=~s/(XXX\.XXX\.XXX\.XXX):\d+/$1:XXX/g; # IPv6 $Content=~s/[\da-f]+\:\:[\da-f]+\:[\da-f]+\:[\da-f]+\:[\da-f]+/XXXX::XXX:XXX:XXX:XXX/gi; $Content=~s/[\da-f]+\:[\da-f]+\:[\da-f]+\:[\da-f]+\:[\da-f]+\:[\da-f]+\:[\da-f]+\:[\da-f]+/XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX/gi; $Content=~s/[\da-f]+\:[\da-f]+\:[\da-f]+\:[\da-f]+::[\da-f]+/XXX:XXX:XXX:XXX::XXX/gi; $Content=~s/[\da-f]+\:[\da-f]+\:[\da-f]+::[\da-f]+/XXX:XXX:XXX::XXX/gi; return $Content; } sub hideUrls($) { my $Content = $_[0]; $Content=~s{[\w\-]+\.[\w\.\-]+\:\/[^\s]+}{XXX:/XXX}g; $Content=~s{(\w+\:\/+)[^\s]+}{$1\XXX}g; return $Content; } sub hideDf($) { my $Content = $_[0]; my $NewDf = ""; my @DfLines = split(/\n/, $Content); my $BSD = isBSD(); for (my $i = 0; $i <= $#DfLines; $i++) { my $L = $DfLines[$i]; if($i==0) { $NewDf .= $L."\n"; next; } my $HideLine = undef; if($BSD) { $HideLine = ($L!~/\A(Filesystem||build|cgroup|cgroup_root|clr_debug_fuse|dev|devfs|devtmpfs|fdescfs|freenas\-boot|\/(dev|home|run)|kernfs|linprocfs|map|none|overlay|procfs|ptyfs|run|serno|shm|tank|tmpfs|udev|zroot|\s+)/); } else { $HideLine = ($L!~/\A(Filesystem|cgroup|cgroup_root|clr_debug_fuse|dev|devtmpfs|\/(dev|home|run)|none|overlay|run|shm|tmpfs|udev|\s+)/); } if($HideLine and $L!~/\s\/\Z/) { $L = hideByRegexp($L, qr/\A([^\s]+)/); $L = hideByRegexp($L, qr/([^\s]+)\Z/); } $NewDf .= $L."\n"; } $Content = $NewDf; return $Content; } sub hidePass($) { my $Content = $_[0]; $Content=~s/.*password.*/XXXXXXXXXX/gi; return $Content; } sub hideMACs($) { my $Content = $_[0]; $Content=~s/[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}/XX:XX:XX:XX:XX:XX/gi; return $Content; } sub encryptMACs($) { my $Content = $_[0]; my @MACs = ($Content=~/[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}\:[\da-f]{2}/gi); if(isBSD()) { my @FwIp = ($Content=~/[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+\.[\da-f]+/gi); if(@FwIp) { push(@MACs, @FwIp); } } foreach my $MAC (@MACs) { my $Enc = lc($MAC); $Enc=~s/\:/-/g; $Enc = clientHash($Enc); $Content=~s/\Q$MAC\E/$Enc/gi; } return $Content; } sub hideByRegexp(@) { my ($Content, $Regexp) = @_; my $Subj = undef; if(@_) { $Subj = shift(@_); } my @Matches = ($Content=~/$Regexp/gi); my @Skip = ("apex", "bin/", "boot", "cdrom", "data", "live", "livecd", "live-rw", "tmpfs", "control", "shared", "start", "system", "utab", "vstorage"); foreach my $Match (sort {length($b)<=>length($a)} @Matches) { if(grep {$Match eq $_} @Skip) { next; } if(length($Match) <= 2) { next; } $Content = hideStr($Content, $Match); if($Subj and $Subj eq "systemd") { if($Match=~s/\x2d/-/g) { $Content = hideStr($Content, $Match); } } } return $Content; } sub hideStr($$) { my ($Content, $Str) = @_; my $Hide = "X" x length($Str); $Content=~s/\Q$Str\E/$Hide/g; return $Content; } sub decorateSystemd($) { my $Content = $_[0]; $Content = hideByRegexp($Content, qr/systemd-cryptsetup@(.+?)\.service/, "systemd"); return $Content; } sub exitStatus($) { my $St = $_[0]; if($Opt{"Flatpak"} and $TMP_DIR and -d $TMP_DIR) { rmtree($TMP_DIR); } if($TMP_PROBE_DIR and -d $TMP_PROBE_DIR) { rmtree($TMP_PROBE_DIR); } if($TMP_LOCAL and -d $TMP_LOCAL) { rmtree($TMP_LOCAL); } if($LATEST_DIR and not listDir($LATEST_DIR)) { rmtree($LATEST_DIR); } exit($St); } sub printMsg($$) { my ($Type, $Msg) = @_; if($Type!~/\AINFO/) { $Msg = $Type.": ".$Msg; } if($Type!~/_C\Z/) { $Msg .= "\n"; } if(grep { $Type eq $_ } ("ERROR", "WARNING")) { print STDERR $Msg; } else { print $Msg; } } sub checkModule(@) { my $Name = shift(@_); my $Local = 0; if(@_) { $Local = 1; } my @Dirs = @INC; if($Local) { push(@Dirs, "."); } foreach my $P (@Dirs) { my $Path = "$P/$Name"; if(-e $Path) { return $Path; } } return undef; } sub runCmd($) { my $Cmd = $_[0]; if($Opt{"ListProbes"}) { print "Executing: ".$Cmd."\n"; } my $AddPath = ""; if(isNetBSD()) { $AddPath = "PATH=\$PATH:/usr/sbin:/sbin:/usr/pkg/sbin "; } return `LC_ALL=$LOCALE $AddPath$Cmd`; } sub getOldProbeDir() { my $SubDir = "HW_PROBE"; my $Dir = undef; if(my $Home = $ENV{"HOME"}) { $Dir = $Home."/".$SubDir; } if($Dir and $Dir eq $PROBE_DIR) { $Dir = undef; if(my $SessUser = getUser()) { $Dir = "/home/".$SessUser."/".$SubDir; } } return $Dir; } sub generateGroup() { my $GroupURL = $URL."/get_group.php"; my $Log = ""; if(checkCmd("curl")) { my $CurlCmd = "curl -s -S -f -POST -F get=group -F email=".$Opt{"Email"}." -F tool_ver=\'$TOOL_VERSION\' -H \"Expect:\" $GroupURL"; # --http1.0 $Log = qx/$CurlCmd 2>&1/; } else { $Log = postRequest($GroupURL, { "get"=>"group", "email"=>$Opt{"Email"}, "tool_ver"=>$TOOL_VERSION }, "NoSSL"); } print $Log; if($?) { my $ECode = $?>>8; printMsg("ERROR", "failed to generate inventory id (group id), curl error code \"".$ECode."\""); exitStatus(1); } if($Log=~/(Group|Inventory) ID: (\w+)/) { my $ID = $2; my $GroupLog = "INVENTORY\n=========\n".localtime(time)."\nInventory ID: $ID\n"; if(-w $PROBE_LOG) { appendFile($PROBE_LOG, $GroupLog."\n"); } } } sub remindGroup() { my $GroupURL = $URL."/remind_group.php"; my $Log = ""; printMsg("INFO", "Please wait..."); if(checkCmd("curl")) { my $CurlCmd = "curl -s -S -f -POST -F hwaddr=".$Sys{"HWaddr"}." -H \"Expect:\" $GroupURL"; # --http1.0 $Log = qx/$CurlCmd 2>&1/; } else { $Log = postRequest($GroupURL, { "hwaddr"=>$Sys{"HWaddr"} }, "NoSSL"); } print $Log; if($?) { my $ECode = $?>>8; printMsg("ERROR", "failed to remind inventory id, curl error code \"".$ECode."\""); exitStatus(1); } } sub postRequest($$$) { my ($UploadURL, $Data, $SSL) = @_; require LWP::UserAgent; my $UAgent = LWP::UserAgent->new(parse_head => 0); if($Opt{"Proxy"}) { $UAgent->proxy([ [ 'http', 'https' ] => "http://".$Opt{"Proxy"} ]); } if($SSL eq "NoSSL" or not checkModule("Mozilla/CA.pm")) { $UploadURL=~s/\Ahttps:/http:/g; $UAgent->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00); } my $Res = $UAgent->post( $UploadURL, Content_Type => "form-data", Content => $Data ); my $Out = $Res->{"_content"}; if(not $Out) { return $Res->{"_headers"}{"x-died"}; } return $Out; } sub getRequest($$) { my ($GetURL, $SSL) = @_; require LWP::UserAgent; my $UAgent = LWP::UserAgent->new(parse_head => 0); if($SSL eq "NoSSL" or not checkModule("Mozilla/CA.pm")) { $GetURL=~s/\Ahttps:/http:/g; $UAgent->ssl_opts(verify_hostname => 0, SSL_verify_mode => 0x00); } $UAgent->agent("Mozilla/5.0 (X11; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.123"); my $Res = $UAgent->get($GetURL); my $Out = $Res->{"_content"}; if(not $Out) { return $Res->{"_headers"}{"x-died"}; } return $Out; } sub saveProbe($) { my $To = $_[0]; $To=~s{/+\Z}{}; my ($Pkg, $HWaddr) = createPackage(); if(not $Pkg) { return; } move($Pkg, $To); print "Saved to: $To/".basename($Pkg)."\n"; } sub uploadData() { my ($Pkg, $HWaddr) = createPackage(); if(not $Pkg) { return; } my $UploadURL = $URL."/upload_result.php"; my $Salt = getSha512L($SALT_CLIENT, 10); # upload package my @Cmd = ("curl", "-s", "-S", "-f", "-POST"); my %Data = (); @Cmd = (@Cmd, "-F file=\@".$Pkg); $Data{"file"} = [$Pkg]; @Cmd = (@Cmd, "-F hwaddr=$HWaddr"); $Data{"hwaddr"} = $HWaddr; if($Opt{"Debug"}) { @Cmd = (@Cmd, "-F debug=1"); $Data{"debug"} = "1"; } if($Opt{"Docker"}) { @Cmd = (@Cmd, "-F docker=1"); $Data{"docker"} = "1"; } if($Opt{"AppImage"}) { @Cmd = (@Cmd, "-F appimage=1"); $Data{"appimage"} = "1"; } if($Opt{"Snap"}) { @Cmd = (@Cmd, "-F snap=1"); $Data{"snap"} = "1"; } if($Opt{"Flatpak"}) { @Cmd = (@Cmd, "-F flatpak=1"); $Data{"flatpak"} = "1"; } if($Opt{"FromGUI"}) { @Cmd = (@Cmd, "-F from_gui"); $Data{"from_gui"} = "1"; } if($Opt{"PC_Name"}) { @Cmd = (@Cmd, "-F id='".$Opt{"PC_Name"}."'"); $Data{"id"} = $Opt{"PC_Name"}; } if($Opt{"Group"}) { @Cmd = (@Cmd, "-F group='".$Opt{"Group"}."'"); $Data{"group"} = $Opt{"Group"}; } if($Opt{"Monitoring"}) { @Cmd = (@Cmd, "-F monitoring=1"); $Data{"monitoring"} = "1"; } @Cmd = (@Cmd, "-F tool_ver=\'$TOOL_VERSION\'"); $Data{"tool_ver"} = $TOOL_VERSION; @Cmd = (@Cmd, "-F salt=\'$Salt\'"); $Data{"salt"} = $Salt; # fix curl error 22: "The requested URL returned error: 417 Expectation Failed" @Cmd = (@Cmd, "-H", "Expect:"); # @Cmd = (@Cmd, "--http1.0"); @Cmd = (@Cmd, $UploadURL); my $CurlCmd = join(" ", @Cmd); my $Log = runCmd("$CurlCmd 2>&1"); my $Err = $?; my $HttpsErr = 0; if(checkCmd("curl") and $Err and $Log=~/certificate|ssl/i) { $CurlCmd=~s/https/http/; $Log = runCmd("$CurlCmd 2>&1"); $Err = $?; $HttpsErr = 1; } if($Err) { if($Opt{"ListProbes"}) { printMsg("ERROR", "failed to upload by curl: $Log"); } if(isNetBSD()) { if(not -e "/etc/openssl/certs" or not listDir("/etc/openssl/certs")) { printMsg("ERROR", "'mozilla-rootcerts-openssl' package is not installed"); } } if(my $WWWLog = postRequest($UploadURL, \%Data, "NoSSL")) { if(index($WWWLog, "probe=")==-1) { print STDERR $WWWLog."\n"; printMsg("ERROR", "failed to upload data"); if(index($WWWLog, "Can't locate HTML/HeadParser.pm")!=-1) { printMsg("ERROR", "please add 'libhtml-parser-perl' or 'perl-HTML-Parser' package to your system"); } exitStatus(1); } $Log = $WWWLog; } else { my $ECode = $Err>>8; print STDERR $Log."\n"; printMsg("ERROR", "failed to upload data, curl error code \"".$ECode."\""); exitStatus(1); } } if($HttpsErr) { $Log=~s/https/http/; $URL=~s/https/http/; } $Log=~s/\s*Private access:\s*http.+?token\=(\w+)\s*/\n/; print $Log; $RecentProbe = undef; if($Log=~/probe\=(\w+)/) { $RecentProbe = $1; } # save uploaded probe and its ID if($RecentProbe) { if($Opt{"SaveUploaded"}) { my $NewProbe = $PROBE_DIR."/".$RecentProbe; if(-d $NewProbe) { printMsg("ERROR", "the probe with ID \'$RecentProbe\' already exists, overwriting ..."); unlink($NewProbe."/hw.info.txz"); } else { mkpath($NewProbe); } if($Opt{"Source"}) { copy($Pkg, $NewProbe); } else { move($Pkg, $NewProbe); } } my $Time = time; my $ProbeUrl = "$URL/?probe=$RecentProbe"; my $ProbeLog = "PROBE\n=====\nDate: ".localtime($Time)." ($Time)\n"; $ProbeLog .= "Probe URL: $ProbeUrl\n"; appendFile($PROBE_LOG, $ProbeLog."\n"); } } sub setupMonitoring() { my $MonitoringURL = $URL."/setup_monitoring.php"; my @Cmd = ("curl", "-s", "-S", "-f", "-POST"); my %Data = (); my $Enable = undef; my $Status = undef; if($Opt{"StartMonitoring"}) { $Enable = 1; $Status = "Enabled"; } elsif($Opt{"StopMonitoring"}) { $Enable = 0; $Status = "Disabled"; } @Cmd = (@Cmd, "-F group=".$Opt{"Group"}); $Data{"group"} = $Opt{"Group"}; @Cmd = (@Cmd, "-F hwaddr=".$Sys{"HWaddr"}); $Data{"hwaddr"} = $Sys{"HWaddr"}; @Cmd = (@Cmd, "-F enable=$Enable"); $Data{"enable"} = $Enable; my $Salt = getSha512L($SALT_CLIENT, 10); @Cmd = (@Cmd, "-F salt=$Salt"); $Data{"salt"} = $Salt; if($RecentProbe) { @Cmd = (@Cmd, "-F init_probe=$RecentProbe"); $Data{"init_probe"} = $RecentProbe; } @Cmd = (@Cmd, "-H \"Expect:\""); @Cmd = (@Cmd, $MonitoringURL); my $Log = ""; if(checkCmd("curl")) { my $CurlCmd = join(" ", @Cmd); $Log = qx/$CurlCmd 2>&1/; } else { $Log = postRequest($MonitoringURL, \%Data, "NoSSL"); } print "\n"; print $Log; print "\n"; if($?) { my $ECode = $?>>8; printMsg("ERROR", "failed to setup monitoring, curl error code \"".$ECode."\""); exitStatus(1); } if($Enable) { my $StatusUrl = undef; if($Log=~/(Status URL: .+)/) { $StatusUrl = $1; } if($StatusUrl) { appendFile($PROBE_LOG, "MONITORING\n==========\n".localtime(time)."\n$Status\n$StatusUrl\n\n"); } else { printMsg("ERROR", "failed to setup monitoring"); exitStatus(1); } } else { if($Log=~/disabled/) { appendFile($PROBE_LOG, "MONITORING\n==========\n".localtime(time)."\n$Status\n\n"); } else { printMsg("ERROR", "failed to setup monitoring"); exitStatus(1); } } my $CronDaily = "/etc/cron.daily"; # add/remove cron entry if(-e $CronDaily) { my $CronScript = $CronDaily."/hw-probe"; if($Enable) { writeFile($CronScript, "#!/bin/bash\n\nhw-probe -all -check-hdd -check-cpu -upload -monitoring -i ".$Opt{"Group"}."\n"); } elsif(-e $CronScript) { unlink($CronScript); } } else { if($Enable) { my $CronTime = "0 0"; if(my $Time = getTimeStamp(time)) { if($Time=~/\A(\d+):(\d+)\Z/) { $CronTime = "$2 $1"; } } system("(EDITOR=cat crontab -e 2>/dev/null | grep -v 'hw-probe' ; echo \"$CronTime * * * hw-probe -all -check-hdd -check-cpu -upload -monitoring -i ".$Opt{"Group"}."\") | crontab -"); } else { system("EDITOR=cat crontab -e 2>/dev/null | grep -v 'hw-probe' | crontab -"); } } } sub cleanData() { if(-d $LATEST_DIR) { rmtree($LATEST_DIR); } } sub readHostAttr($$) { my ($Path, $Attr) = @_; if(readFile($Path."/host")=~/\Q$Attr\E\:([^\n]*)/) { return $1; } return ""; } sub createPackage() { my ($Pkg, $HWaddr) = (); if($Opt{"Source"}) { if(-f $Opt{"Source"}) { if(isPkg($Opt{"Source"})) { $Pkg = $Opt{"Source"}; system("tar", "--directory", $TMP_DIR, "-xf", $Pkg); if($?) { printMsg("ERROR", "failed to extract package (".$?.")"); exitStatus(1); } if(my @Dirs = listDir($TMP_DIR)) { my $Dir = $Dirs[0]; my $Chg = 0; if($Dir ne "hw.info") { # packaged by user move($TMP_DIR."/".$Dir, $TMP_DIR."/hw.info"); $Chg = 1; } if(updateHost($TMP_DIR."/hw.info", "id", $Opt{"PC_Name"})) { $Chg = 1; } $HWaddr = readHostAttr($TMP_DIR."/hw.info", "hwaddr"); if($Chg) { chdir($TMP_DIR); system("tar", "-cJf", "hw.info.txz", "hw.info"); chdir($ORIG_DIR); if($?) { printMsg("ERROR", "failed to create a package (".$?.")"); exitStatus(1); } $Pkg = $TMP_DIR."/hw.info.txz"; } } } else { printMsg("ERROR", "not a package"); exitStatus(1); } } elsif(-d $Opt{"Source"}) { copyFiles($Opt{"Source"}, $TMP_DIR."/hw.info"); updateHost($TMP_DIR."/hw.info", "id", $Opt{"PC_Name"}); $HWaddr = readHostAttr($TMP_DIR."/hw.info", "hwaddr"); chdir($TMP_DIR); system("tar", "-cJf", "hw.info.txz", "hw.info"); chdir($ORIG_DIR); if($?) { printMsg("ERROR", "failed to create a package (".$?.")"); exitStatus(1); } $Pkg = $TMP_DIR."/hw.info.txz"; } else { printMsg("ERROR", "can't access '".$Opt{"Source"}."'"); exitStatus(1); } } else { if(not -d $DATA_DIR) { if($Admin) { printMsg("ERROR", "can't access '".$DATA_DIR."', please make probe first"); } else { printMsg("ERROR", "can't access '".$DATA_DIR."', please run as root"); } exitStatus(1); } if(not -f "$DATA_DIR/devices" and not -f "$DATA_DIR/devices.json") { printMsg("ERROR", "\'$DATA_DIR/devices\' file is not found, please make probe first"); exitStatus(1); } updateHost($DATA_DIR, "id", $Opt{"PC_Name"}); $HWaddr = readHostAttr($DATA_DIR, "hwaddr"); chdir(dirname($DATA_DIR)); # if(isOpenBSD() or isNetBSD() # or (defined $Sys{"Freebsd_release"} and $Sys{"Freebsd_release"} < 7.3)) if(isBSD() or not checkCmd("xz")) { $Pkg = $TMP_DIR."/hw.info.tgz"; system("tar", "-czf", $Pkg, basename($DATA_DIR)); } else { $Pkg = $TMP_DIR."/hw.info.txz"; system("tar", "-cJf", $Pkg, basename($DATA_DIR)); } chdir($ORIG_DIR); } return ($Pkg, $HWaddr); } sub copyFiles($$) { my ($P1, $P2) = @_; mkpath($P2); foreach my $Top (listDir($P1)) { if(-d "$P1/$Top") { # copy subdirectory foreach my $Sub (listDir("$P1/$Top")) { if($Sub=~/~\Z/) { next; } mkpath("$P2/$Top"); copy("$P1/$Top/$Sub", "$P2/$Top/$Sub"); } } else { # copy file if($Top=~/~\Z/) { next; } copy("$P1/$Top", "$P2/$Top"); } } } sub isPkg($) { my $Path = $_[0]; return ($Path=~/\.(tar\.xz|txz|tar\.gz|tgz)\Z/ or `file "$Path"`=~/(XZ|gzip) compressed data/); } sub updateHost($$$) { my ($Path, $Attr, $Val) = @_; if($Val) { if(not -f "$Path/host") { # internal error return 0; } my $Content = readFile($Path."/host"); my $Chg = 0; if($Content!~/(\A|\n)$Attr:/) { if($Content!~/\n\Z/) { $Content .= "\n"; } $Content .= $Attr.":".$Val."\n"; $Chg = 1; } elsif($Content=~/(\A|\n)$Attr:(.*)/) { if($2 ne $Val) { $Content=~s/(\A|\n)$Attr:(.*)/$1$Attr:$Val/; $Chg = 1; } } if($Chg) { writeFile($Path."/host", $Content); print "Added \'$Attr\' to host info\n"; return 1; } } return 0; } sub fixCpuVendor($) { my $Vendor = $_[0]; foreach my $VV ("Intel", "AMD", "ARM") { if($Vendor=~/$VV/) { return $VV; } } if($Vendor=~/Advanced Micro Devices/) { return "AMD"; } if($Vendor=~/unknown/i) { return undef; } return $Vendor; } sub fmtVal($) { my $Val = $_[0]; if(not defined $Val or $Val eq "" or $Val=~/\A\s+\Z/) { return ""; } if($Val!~/[a-z0-9]/i) { # invalid return ""; } $Val=~s/\((R|TM)\)\-/-/gi; $Val=~s/\((R|TM)\)/ /gi; $Val=~s/\x{2122}|\x{AE}|\x{A9}//g; # TM (trade mark), R (registered), C (copyright) special symbols $Val=~s/\303\227/x/g; # multiplication sign $Val=~s/\x{A0}/ /g; # no-break space $Val=~s/\A[_\-\? ]//gi; $Val=~s/[_\-\? ]\Z//gi; $Val=~s/[ ]{2,}/ /g; return $Val; } sub bytesToHuman($) { my $Bytes = $_[0]; $Bytes /= 1000000; # MB if($Bytes>=1000) { $Bytes /= 1000; # GB $Bytes = roundToNearest($Bytes); if($Bytes>=1000) { $Bytes /= 1000; # TB $Bytes = roundToNearest($Bytes); return $Bytes."TB"; } return $Bytes."GB"; } else { $Bytes = roundToNearest($Bytes); } return $Bytes."MB"; } sub toGb($) { my $S = $_[0]; $S=~s/\,/\./; if($S=~/([\d\.]+)([TGM])/) { my ($Res, $Ent) = ($1, $2); if($Ent eq "M") { $Res /= 1000.0; } elsif($Ent eq "T") { $Res *= 1000.0; } return $Res; } return 0; } sub roundFloat($$) { my ($N, $S) = @_; $N = sprintf("%.".$S."f", $N); $N=~s/(\.\d)0\Z/$1/; $N=~s/\.0\Z//; return $N; } sub getPnpVendor($) { my $V = $_[0]; if(defined $MonVendor{$V}) { return $MonVendor{$V}; } # NOTE: this is not reliable # if(not keys(%PnpVendor)) { # readPnpIds(); # } # # if(defined $PnpVendor{$V}) # { # if($PnpVendor{$V}!~/do not use/i) { # return $PnpVendor{$V}; # } # } return $V; } sub readPnpIds() { my $Path = undef; if($Opt{"PnpIDs"}) { $Path = $Opt{"PnpIDs"}; } else { $Path = "/usr/share/hwdata/pnp.ids"; # ROSA Fresh, RELS } if(not -e $Path) { $Path = "/usr/share/misc/pnp.ids"; # ROSA Marathon } if(not -e $Path) { return; } foreach my $Line (split(/\n/, readFile($Path))) { if($Line=~/\A([A-Z]+)\s+(.*?)\Z/) { $PnpVendor{$1} = $2; } } } sub getPciVendor($) { my $V = $_[0]; if(defined $PciInfo{"V"}{$V}) { return $PciInfo{"V"}{$V}; } if(not keys(%{$PciInfo{"V"}})) { readVendorIds(); } if(defined $PciInfo{"V"}{$V}) { return $PciInfo{"V"}{$V}; } return; } sub readVendorIds() { my $Path = "/usr/share/hwdata/pci.ids"; if($Opt{"PciIDs"}) { $Path = $Opt{"PciIDs"}; } elsif(-e "ids/pci.ids") { $Path = "ids/pci.ids"; } if(not -e $Path) { return; } foreach my $Line (split(/\n/, readFile($Path))) { if($Line=~/\A(\w{4})\s+(.*?)\Z/) { $PciInfo{"V"}{$1} = $2; } } } sub getSdioType($) { my $Class = $_[0]; return $SdioType{$Class}; } sub getClassType($$) { my ($Bus, $Class) = @_; while($Class) { if($Bus eq "pci") { if(defined $PciClassType{$Class}) { return $PciClassType{$Class}; } } elsif($Bus eq "usb") { if(defined $UsbClassType{$Class}) { return $UsbClassType{$Class}; } } if($Class!~s/\-\w+?\Z//) { last; } } return ""; } sub fixRootHub($$$) { my ($V, $D, $Dev) = @_; if(grep {$V eq $_} ("8086", "0000") and $D eq "0000") { $V = "1d6b"; $Dev->{"Vendor"} = "BSD"; if($Dev->{"Device"}=~/UHCI|OHCI/i) { $D = "0001"; } elsif($Dev->{"Device"}=~/EHCI/i) { $D = "0002"; } elsif($Dev->{"Device"}=~/XHCI/i) { $D = "0003"; } } return ($V, $D); } sub getDefaultType($$$) { my ($Bus, $DId, $Device) = @_; foreach my $Name ($Device->{"Device"}, $Device->{"SDevice"}) { if(not $Name) { next; } if($Bus eq "usb") { if($Name=~/camera|webcam|web cam/i) { return "camera"; } elsif($Name=~/card reader/i) { return "card reader"; } elsif($Name=~/fingerprint (reader|scanner|sensor|device|coprocessor)|swipe sensor/i) { return "fingerprint reader"; } elsif($Name=~/smartcard/i) { return "smartcard reader"; } elsif($Name=~/USB Scanner|CanoScan|FlatbedScanner|Scanjet|EPSON Scanner/i) { return "scanner"; } elsif($Name=~/bluetooth/i) { return "bluetooth"; } elsif($Name=~/(\A| )(WLAN|NIC|11n Adapter)( |\Z)|Wireless.*Adapter|Wireless Network|Wireless LAN|WiMAX|WiFi|802\.11|Mobile Broadband|Ethernet/i) { return "network"; } elsif($Name=~/converter/i) { return "converter"; } elsif($Name=~/(\A| )UPS(\Z| )/) { return "ups"; } elsif($Name=~/TouchScreen/i) { return "touchscreen"; } elsif($Name=~/Touchpad|Touch Pad/i) { return "touchpad"; } elsif($Name=~/(\A| )Phone(\Z| )/i) { return "phone"; } elsif($Name=~/Gamepad/i) { return "gamepad"; } elsif($Name=~/DVB-T/) { return "dvb card"; } } elsif($Bus eq "pci") { if($Name=~/card reader/i) { return "card reader"; } elsif($Name=~/I\/O card/i) { return "i/o card"; } elsif($Name=~/PCI Bridge/i) { return "bridge"; } elsif($Name=~/(\A|\s)SD Host Controller/i) { return "sd host controller"; } elsif($Name=~/High Definition Audio Controller/i and $Name!~/HD Graphics/i) { return "sound"; } } elsif($Bus eq "pcmcia") { if($Name=~/Bay8Controller/i) { return "smartcard reader"; } } } if($Bus eq "usb") { if(defined $Device->{"ActiveDriver"}{"btusb"}) { return "bluetooth"; } if($Device->{"Vendor"}=~/AuthenTec|Validity Sensors/) { return "fingerprint reader"; } if($Device->{"Vendor"}=~/Synaptics/ and $DId=~/0081|009a|009b|00a2|00a8|00bb|00bd|00be|00c7|00c9|00df|00e7|00e9|00f0/) { return "fingerprint reader"; } if($Device->{"Vendor"}=~/Goodix/ and $DId=~/533c/) { return "fingerprint reader"; } } return ""; } sub addCapacity($$) { my ($Device, $Capacity) = @_; $Capacity=~s/\.0\d+//; $Capacity=~s/(\.\d)\d+/$1/; $Capacity=~s/\s+//g; if($Capacity) { if($Device!~/(\A|\s|\-)[\d\.\,]+\s*([MGT]B|[MGT])(\s|\Z)/ and $Device!~/reader|bridge|\/sd\/|adapter/i and $Device!~/\Q$Capacity\E/i) { return " ".$Capacity; } } return ""; } sub decodeEdid($) { my $Edid = $_[0]; my $TmpFile = $TMP_DIR."/hex-edid"; writeFile($TmpFile, $Edid); my $Res = qx/edid-decode $TmpFile 2>&1/; unlink($TmpFile); return $Res; } sub countDevice($$) { my ($DevId, $DevType) = @_; if(not defined $HW_Count{$DevId}{$DevType}) { $HW_Count{$DevId}{$DevType} = 1; } else { $HW_Count{$DevId}{$DevType} += 1; } } sub setDevCount($$$) { my ($DevId, $DevType, $Count) = @_; $HW_Count{$DevId}{$DevType} = $Count; } sub getDeviceCount($) { my $DevId = $_[0]; if(defined $HW_Count{$DevId}) { foreach (keys(%{$HW_Count{$DevId}})) { return $HW_Count{$DevId}{$_}; } } return 0; } sub getSysVer($) { if($_[0]=~/\-(\d.*)\Z/) { return int($1); } return undef; } sub probeHW() { if($Opt{"FixProbe"}) { print "Fixing probe ... "; } else { if(enabledLog("hwinfo") and not defined $Opt{"HWInfoPath"} and not checkCmd("hwinfo")) { printMsg("ERROR", "'hwinfo' is not installed"); exitStatus(1); } if($Opt{"HWLogs"}) { my %CmdPackage = ( "dmidecode" => "dmidecode", "lspci" => "pciutils", "lsusb" => "usbutils", "lscpu" => "lscpu", "smartctl" => "smartmontools", "edid-decode" => "edid-decode", "hwstat" => "hwstat", "curl" => "curl", "usbctl" => "usbutil", "cpuid" => "cpuid", "shasum" => "p5-Digest-SHA" ); my @NeedProgs = ("dmidecode", "smartctl"); if(isOpenBSD()) { push(@NeedProgs, "lscpu", "usbctl", "curl"); # we have pcidump and usbdevs on OpenBSD by default if($Sys{"System_version"} < 6.3) { @NeedProgs = grep {$_!~/lscpu/} @NeedProgs; } if($Sys{"Arch"}!~/i386|amd64/) { @NeedProgs = grep {$_!~/dmidecode/} @NeedProgs; if($Sys{"System_version"} eq "6.3") { @NeedProgs = grep {$_!~/lscpu/} @NeedProgs; } } } elsif(isNetBSD()) { push(@NeedProgs, "usbctl", "curl"); # we have pcictl and usbdevs on NetBSD by default, TODO: cpuid? if($Sys{"Arch"}!~/i386|amd64|aarch64/) { @NeedProgs = grep {$_!~/dmidecode/} @NeedProgs; } if($Sys{"Arch"}=~/aarch64/ and $Sys{"System_version"} < 9.0) { @NeedProgs = grep {$_!~/dmidecode/} @NeedProgs; } } elsif($Sys{"System"}=~/midnightbsd/) { push(@NeedProgs, "cpuid", "curl"); # using cpuid instead of lscpu on MidnightBSD due to huge recursive deps list } elsif($Sys{"System"}=~/dragonfly/) { push(@NeedProgs, "hwstat", "lscpu", "curl"); } elsif($Sys{"System"}=~/pfsense|opnsense/) { push(@NeedProgs, "curl"); # no hwstat and lscpu on pfSense if($Sys{"Arch"}!~/i386|amd64/) { @NeedProgs = grep {$_!~/dmidecode/} @NeedProgs; } } elsif(defined $Sys{"Freebsd_release"}) { push(@NeedProgs, "hwstat", "lscpu", "curl"); # we have pciconf and usbconfig (since 8.0) on FreeBSD by default if($Sys{"Freebsd_release"} < 11.2) { @NeedProgs = grep {$_!~/lscpu/} @NeedProgs; push(@NeedProgs, "cpuid"); } if($Sys{"Freebsd_release"} < 8.1) { @NeedProgs = grep {$_!~/hwstat/} @NeedProgs; } if($Sys{"Freebsd_release"} < 8.0) { push(@NeedProgs, "usbctl"); } if($Sys{"Freebsd_release"} < 7.0) { # Use Perl instead of openssl push(@NeedProgs, "shasum"); } if($Sys{"Freebsd_release"} < 5.2) { @NeedProgs = grep {$_!~/smartctl/} @NeedProgs; } if($Sys{"Arch"}!~/i386|amd64/) { @NeedProgs = grep {$_!~/dmidecode|lscpu/} @NeedProgs; } if($Sys{"System"}!~/$KNOWN_BSD_ALL|freebsd/) { # Unknown FreeBSD-based @NeedProgs = grep {$_!~/hwstat|lscpu/} @NeedProgs; } } elsif(isBSD()) { # Unknown BSD push(@NeedProgs, "curl"); if($Sys{"Arch"}!~/i386|amd64/) { @NeedProgs = grep {$_!~/dmidecode/} @NeedProgs; } } else { # Linux push(@NeedProgs, "lspci", "lsusb", "edid-decode"); } my @NeedToInstall = (); foreach my $Prog (@NeedProgs) { if(enabledLog($Prog) and not checkCmd($Prog)) { if(isBSD()) { if(not defined $Opt{"InstallDeps"}) { printMsg("ERROR", "'".$CmdPackage{$Prog}."' package is not installed"); } push(@NeedToInstall, $CmdPackage{$Prog}) } else { printMsg("WARNING", "'".$CmdPackage{$Prog}."' package is not installed"); } } } if(@NeedToInstall) { my $NeedCmd = "pkg install"; if(isOpenBSD()) { $NeedCmd = "pkg_add"; if($Sys{"System_version"} < 6.5) { # for old OpenBSD versions $NeedCmd = "PKG_PATH=https://ftp.nluug.nl/OpenBSD/".$Sys{"System_version"}."/packages/".$Sys{"Arch"}." pkg_add"; } } elsif($Sys{"System"}=~/midnightbsd/) { $NeedCmd = "mport install"; } elsif(isNetBSD()) { $NeedCmd = "pkgin install"; } elsif(defined $Sys{"Freebsd_release"}) { if($Sys{"Freebsd_release"} < 10.0) { $NeedCmd = "pkg_add"; } if($Sys{"Freebsd_release"} < 9.3) { $NeedCmd = "env PACKAGESITE='http://ftp-archive.freebsd.org/pub/FreeBSD-Archive/ports/".$Sys{"Arch"}."/packages-".$Sys{"Freebsd_release"}."-release/Latest/' pkg_add -r"; } } $NeedCmd .= " ".join(" ", @NeedToInstall); if(defined $Opt{"InstallDeps"}) { printMsg("INFO", "Installing dependencies ..."); system($NeedCmd); } else { printMsg("TIP", "install missed packages by command (auto-install by adding `-install-deps` option):\n\n $NeedCmd\n"); } if(not $Opt{"SkipDeps"}) { exitStatus(1); } } elsif(defined $Opt{"InstallDeps"}) { printMsg("INFO", "Nothing to install"); exitStatus(0); } } print "Probe for hardware ... "; if($Opt{"ListProbes"}) { print "\n"; } } # Dev listing my $DevFiles = ""; if($Opt{"FixProbe"}) { $DevFiles = readFile($FixProbe_Logs."/dev"); } else { listProbe("logs", "dev"); $DevFiles = runCmd("find /dev -ls 2>/dev/null"); if($DevFiles) { $DevFiles=~s/(\A|\n).*?\d+ \//$1\//g; $DevFiles = join("\n", sort split(/\n/, $DevFiles)); } else { # Alpine $DevFiles = runCmd("ls -lR /dev"); $DevFiles=~s/total \d+\n//g; $DevFiles=~s/(\A|\n).*?\s+\d+\s+\d\d:\d\d\s+/$1/g; } $DevFiles = encryptSerialsInPaths($DevFiles); $DevFiles = encryptWWNs($DevFiles); $DevFiles = hideByRegexp($DevFiles, qr/\/by-partlabel\/([^\s]+)/); $DevFiles = hideByRegexp($DevFiles, qr/\/by-partuuid\/([a-f\d]{8})\-\d\d/); $DevFiles = hideLVM($DevFiles); $DevFiles = hideByRegexp($DevFiles, qr/\/([^\s\/]+?)-vg/); $DevFiles = hidePaths($DevFiles); $DevFiles = encryptUUIDs($DevFiles); writeLog($LOG_DIR."/dev", $DevFiles); } my @DevUUIDs = $DevFiles=~/by-uuid\/([^\s]{36})/g; if($Sys{"Kernel"}=~/raspi/) { my @MMCUuids = ($DevFiles=~/\/mmc-(\w+0x[a-f\d]{8}) /g); push(@DevUUIDs, @MMCUuids); } if(@DevUUIDs) { $Sys{"Uuid"} = getSysUUID(@DevUUIDs); } if(not $Sys{"System"} or $Sys{"System"}=~/freedesktop/) { if(index($DevFiles, "/dev/chromeos-low-mem") != -1) { $Sys{"System"} = "chrome_os"; } elsif(index($DevFiles, "eos-swap") != -1) { $Sys{"System"} = "endless"; } } my %DevIdByName = (); my %DevNameById = (); my $InDevById = 0; foreach my $Line (split(/\n/, $DevFiles)) { if(not $InDevById and index($Line, "/dev/disk/by-id")==0) { $InDevById = 1; } if($InDevById) { if(not $Line or index($Line, "/dev/disk/by-uuid")==0) { last; } if($Line=~/\A(\/dev\/disk\/by-id\/|)((ata|usb|nvme|wwn)\-[^\/]+)\s+\-\>\s+.*?(\w+)\Z/) { my ($DFile, $DIdent) = ($4, $2); if($DIdent!~/\Awwn\-/) { $DevIdByName{$DFile} = $DIdent; } $DevNameById{$DIdent} = "/dev/".$DFile; } } } # Loaded modules my $Lsmod = ""; if($Opt{"FixProbe"}) { $Lsmod = readFile($FixProbe_Logs."/lsmod"); } elsif(enabledLog("lsmod") and checkCmd("lsmod")) { listProbe("logs", "lsmod"); if($Opt{"Snap"} or $Opt{"Flatpak"}) { $Lsmod = "Module Size Used by\n"; foreach my $L (split(/\n/, readFile("/proc/modules"))) { if($L=~/\A(\w+)\s+(\d+)\s+(\d+)\s+([\w,-]+)/) { my ($Mod, $Size, $Used, $By) = ($1, $2, $3, $4); $By=~s/[,-]\Z//; # if($By) { # $By = join(",", sort split(/,/, $By)); # } $Lsmod .= $Mod; my $Sp = 28 - length($Size) - length($Mod); if($Sp<4) { $Sp = 4; } foreach (1 .. $Sp) { $Lsmod .= " "; } $Lsmod .= $Size." ".$Used." ".$By."\n"; } } } else { $Lsmod = runCmd("lsmod 2>&1"); if(length($Lsmod)<60) { $Lsmod = ""; } } if($Lsmod) { # Sort, but save title my $FL = ""; if($Lsmod=~s/\A(.*?)\n//) { $FL = $1; } $Lsmod = $FL."\n".join("\n", sort split(/\n/, $Lsmod)); } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/lsmod", $Lsmod); } } my $Kldstat = ""; if($Opt{"FixProbe"}) { $Kldstat = readFile($FixProbe_Logs."/kldstat"); } elsif(enabledLog("kldstat") and checkCmd("kldstat")) { listProbe("logs", "kldstat"); $Kldstat = runCmd("kldstat 2>/dev/null"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/kldstat", $Kldstat); } } my $Kldstat_v = ""; if($Opt{"FixProbe"}) { $Kldstat_v = readFile($FixProbe_Logs."/kldstat_v"); } elsif(enabledLog("kldstat_v") and checkCmd("kldstat")) { listProbe("logs", "kldstat_v"); $Kldstat_v = runCmd("kldstat -v 2>/dev/null"); if($Opt{"HWLogs"} and $Kldstat_v) { writeLog($LOG_DIR."/kldstat_v", $Kldstat_v); } } # TODO: clarification of the condition is required # if($Kldstat_v=~/bcm2835_/) # { # $Sys{"Type"} = "system on chip"; # $Sys{"Model"} = "Raspberry Pi"; # } # if($Kldstat_v=~/rockchip_dwmmc/) # { # $Sys{"Type"} = "system on chip"; # $Sys{"Vendor"} = "Pine Microsystems"; # $Sys{"Model"} = "Rockpro64"; # } my $Modstat = ""; if($Opt{"FixProbe"}) { $Modstat = readFile($FixProbe_Logs."/modstat"); } elsif(enabledLog("modstat") and checkCmd("modstat")) { listProbe("logs", "modstat"); $Modstat = runCmd("modstat 2>/dev/null"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/modstat", $Modstat); } } my $Sndstat = ""; if($Opt{"FixProbe"}) { $Sndstat = readFile($FixProbe_Logs."/sndstat"); } elsif(enabledLog("sndstat")) { listProbe("logs", "sndstat"); $Sndstat = readFile("/dev/sndstat"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/sndstat", $Sndstat); } } my $Neofetch = ""; if($Opt{"FixProbe"}) { $Neofetch = readFile($FixProbe_Logs."/neofetch"); } elsif(enabledLog("neofetch") and checkCmd("neofetch")) { listProbe("logs", "neofetch"); $Neofetch = runCmd("neofetch --json 2>/dev/null"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/neofetch", $Neofetch); } } if($Neofetch and $USE_JSON_XS) { require Encode; $Neofetch = JSON::XS::decode_json(Encode::encode_utf8($Neofetch)); if(not $Sys{"Wm"} and $Neofetch) { $Sys{"Wm"} = $Neofetch->{"WM"}; } } my $KernelConfig = ""; if($Opt{"FixProbe"}) { $KernelConfig = readFile($FixProbe_Logs."/config"); } elsif(enabledLog("config") and checkCmd("config") and -e "/boot/kernel/kernel") { listProbe("logs", "config"); $KernelConfig = runCmd("config -x /boot/kernel/kernel 2>/dev/null"); if($Opt{"HWLogs"} and $KernelConfig) { writeLog($LOG_DIR."/config", $KernelConfig); } } my @KernDrvs = (); foreach my $Line (split(/\n/, $Lsmod)) { if($Line=~/(\w+)\s+(\d+)\s+(\d+)/) { my ($Name, $Use) = ($1, $3); $KernMod{$Name} = $Use; push(@KernDrvs, $Name); if($Use) { $WorkMod{$Name} = 1; } } } if(not $Sys{"Type"} and not $Sys{"Model"}) { if(defined $KernMod{"raspberrypi_hwmon"}) { $Sys{"Type"} = "system on chip"; $Sys{"Model"} = "Raspberry Pi"; ($Sys{"Vendor"}, $Sys{"Model"}) = fixVendorModel($Sys{"Vendor"}, $Sys{"Model"}); } } my $Lsblk = ""; if($Opt{"FixProbe"}) { $Lsblk = readFile($FixProbe_Logs."/lsblk"); } elsif(enabledLog("lsblk") and checkCmd("lsblk")) { listProbe("logs", "lsblk"); my $LsblkCmd = undef; if(isBSD()) { $LsblkCmd = "lsblk"; } else { $LsblkCmd = "lsblk -al -o NAME,SIZE,TYPE,FSTYPE,UUID,MOUNTPOINT,MODEL,PARTUUID"; if($Opt{"Flatpak"}) { $LsblkCmd .= " 2>/dev/null"; } else { $LsblkCmd .= " 2>&1"; } } $Lsblk = runCmd($LsblkCmd); if($Lsblk=~/unknown column/) { # CentOS 6: no PARTUUID column if($LsblkCmd=~s/\,PARTUUID//g) { $Lsblk = runCmd($LsblkCmd); } } if($Opt{"Snap"} and $Lsblk=~/Permission denied/) { $Lsblk = ""; } $Lsblk = hideByRegexp($Lsblk, qr/(.+?)\s+[^\s]+?\s+crypt\s+/); $Lsblk = hidePaths($Lsblk); $Lsblk = hideLVM($Lsblk); $Lsblk = encryptUUIDs($Lsblk); $Lsblk = hideByRegexp($Lsblk, qr/\s([a-f\d]{8})\-\d\d\n/); # PARTUUID writeLog($LOG_DIR."/lsblk", $Lsblk); } if($Lsblk) { foreach my $Line (split(/\n/, $Lsblk)) { if($Line=~/\blive-/) { next; } my @L = split(/\s+/, $Line); if($L[0]=~/\A(sd[a-z]+|nvme\d+n\d+|mmcblk\d+|mtdblock\d+)\Z/) { my $HDD_File = "/dev/".$L[0]; my $HDD_Size = $L[1]; if(index($HDD_Size, ":")!=-1) { # old lsblk log $HDD_Size = $L[3]; $HDD_Size=~s/\,/./; } if($HDD_Size!~/\A\d.*[A-Z]\Z/) { next; } $HDD_Size=~s/\.X/\.0/; if($HDD_Size=~/\A([\d\.]+)([A-Z]+)\Z/) { my ($N, $S) = ($1, $2); if($S eq "T") { $N = $N*1.11111111111; } elsif($S eq "G") { $N = $N*1.07355; } elsif($S eq "X") { # incorrect anonymization next; } $HDD_Size = sprintf("%.1f", $N).$S; $HDD_Size=~s/\.\d+//; } if($HDD_Size!~/B\Z/) { $HDD_Size .= "B"; } if($HDD_Size eq "1000GB") { $HDD_Size = "1TB"; } $HDD_Size = fixCapacity($HDD_Size); if($HDD_Size) { $BlockCapacity{$HDD_File} = $HDD_Size; } } } } if(not $Opt{"FixProbe"} and $Opt{"Logs"}) { if(enabledLog("modinfo") and checkCmd("modinfo")) { listProbe("logs", "modinfo"); my $Modinfo = runCmd("modinfo ".join(" ", @KernDrvs)." 2>&1"); $Modinfo=~s/\n(filename:)/\n\n$1/g; $Modinfo=~s/\n(author|signer|sig_key|sig_hashalgo|vermagic):.+//g; $Modinfo=~s/\ndepends:\s+\n/\n/g; if(index($Modinfo, "signature: ")!=-1) { $Modinfo=~s/:*\n\s+[A-F\d]{2}\:.+//g; } $Modinfo=~s&/lib/modules/[^\/]+/kernel/&&g; writeLog($LOG_DIR."/modinfo", $Modinfo); } } if(not $Opt{"FixProbe"}) { my $RpmLst = "/run/initramfs/live/rpm.lst"; if(-f $RpmLst) { # Live my $Build = `head -n 1 $RpmLst 2>&1`; # iso build No.11506 if($Build=~/(\d+)/) { $Sys{"Build"} = $1; } if($Opt{"Logs"}) { writeLog($LOG_DIR."/build", $Build); } } else { my $RevInfo = "/run/initramfs/live/revision.info"; if(-f $RevInfo) { # DX my $Build = readFile($RevInfo); if($Build=~/RELEASE\:\s*(\d+)/i) { $Sys{"Build"} = $1; } if($Opt{"Logs"}) { writeLog($LOG_DIR."/revision.info", $Build); } } } } my %DriveKind = (); if($Opt{"FixProbe"}) { # Fix drive IDs after uploading my $Smart = readFile($FixProbe_Logs."/smartctl"); my $CurDev = undef; foreach my $SL (split(/\n/, $Smart)) { if(index($SL, "/dev/")==0) { $CurDev = $SL; $DriveKind{$CurDev} = "HDD"; } elsif($CurDev) { if($SL=~/Rotation Rate:.*Solid State Device|\bSSD/) { $DriveKind{$CurDev} = "SSD"; } elsif(index($SL, "NVM Commands")!=-1 or index($SL, "NVMe Log")!=-1) { $DriveKind{$CurDev} = "NVMe"; } } } } # HW Info my $HWInfo = ""; if($Opt{"FixProbe"}) { $HWInfo = readFile($FixProbe_Logs."/hwinfo"); } elsif(enabledLog("hwinfo")) { listProbe("logs", "hwinfo"); my @Items = qw(monitor bluetooth bridge camera cdrom chipcard cpu disk dvb fingerprint floppy gfxcard hub ide isapnp isdn joystick keyboard mouse netcard network pci pcmcia scanner scsi smp sound tape tv usb usb-ctrl wlan); my $HWInfoCmd = "hwinfo"; if(defined $Opt{"HWInfoPath"}) { my $HWInfoDir = dirname(dirname($Opt{"HWInfoPath"})); $HWInfoCmd = $Opt{"HWInfoPath"}; if(-d "$HWInfoDir/lib64") { $HWInfoCmd = "LD_LIBRARY_PATH=\"$HWInfoDir/lib64\" ".$HWInfoCmd; } elsif(-d "$HWInfoDir/lib") { $HWInfoCmd = "LD_LIBRARY_PATH=\"$HWInfoDir/lib\" ".$HWInfoCmd; } } if(my $HWInfoVer = qx/$HWInfoCmd --version/) { chomp($HWInfoVer); if($HWInfoVer=~/\A(\d+)\.(\d+)\Z/) { my ($V1, $V2) = (int($1), int($2)); if($V1>21 or $V1==21 and $V2>=34) { # newer than 21.34 push(@Items, "mmc-ctrl"); } } } if($Opt{"LogLevel"} eq "maximal") { # this may hang push(@Items, "framebuffer"); } my $Items = "--".join(" --", @Items); $HWInfo = runCmd("$HWInfoCmd $Items 2>/dev/null"); if(not $HWInfo) { # incorrect option printMsg("WARNING", "incorrect hwinfo option passed, using --all"); $HWInfo = runCmd($HWInfoCmd." --all 2>&1"); } $HWInfo = hideTags($HWInfo, "UUID|Asset Tag"); $HWInfo = encryptMACs($HWInfo); if(index($HWInfo, "Serial ID:")) { $HWInfo = encryptSerials($HWInfo, "Serial ID", "hwinfo"); } $HWInfo = encryptSerialsInPaths($HWInfo); $HWInfo = encryptWWNs($HWInfo); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/hwinfo", $HWInfo); } } foreach my $Info (split(/\n\n/, $HWInfo)) { my %Device = (); my ($DevNum, $Bus) = (); my ($V, $D, $SV, $SD, $C) = (); if($Info=~s/(\d+):\s*([^ ]+)//) { # 37: PCI 700.0: 0200 Ethernet controller $DevNum = $1; $Bus = lc($2); } $Bus=~s/\(.*?\)//g; if($Bus eq "adb") { # adb:0001-0001-macintosh-mouse-button-emulation next; } if($Info=~s/:\s*\w+\s+(.*)//) { # 37: PCI 700.0: 0200 Ethernet controller if($1 eq "BIOS") { next; } elsif($1 ne "Unclassified device") { $Device{"Type"} = lc($1); $Device{"GeneralType"} = $1; } } if($Device{"Type"} eq "partition") { next; } elsif($Device{"Type"} eq "disk" and $Bus eq "pci") { $Bus = $PCI_DISK_BUS; } $Info=~s/[ ]{2,}/ /g; my $ID = ""; while($Info=~s/[ \t]*([\w ]+?):[ \t]*(.*)//) { my ($Key, $Val) = ($1, $2); if($Key eq "Device" or $Key eq "Vendor" or $Key eq "SubVendor" or $Key eq "SubDevice") { $Key=~s/\ASub/S/; # name mapping if($Bus ne "ide" and $Bus ne $PCI_DISK_BUS) { if($Val=~s/\A(\w+) 0x/0x/) { $Bus = $1; } if($Val=~s/0x(\w{4})\s*//) { if($Key eq "Vendor") { $V = $1; } elsif($Key eq "Device") { $D = $1; } elsif($Key eq "SVendor") { $SV = $1; } elsif($Key eq "SDevice") { $SD = $1; } } } if($Val=~/\"(.*)\"/) { $Device{$Key} = fmtVal($1); } if($Device{"Type"} eq "cpu") { # fix cpu if($Key eq "Vendor") { $Device{$Key} = fixCpuVendor($Device{$Key}); } } if(not $V) { if($Val=~/(\w+)\s+\".*\"/) { $V = $1; } elsif($Val!~/\".*\"/) { $V = fmtVal($Val); } } } elsif($Key eq "Model") { if($Val=~/\A(.*?)\s*\"(.*)\"/) { $D = $1; $Device{"Model"} = fmtVal($2); } } elsif($Key eq "Hardware Class") { if(lc($Val) ne "unknown") { $Device{"Type"} = $Val; } } elsif($Key eq "Driver") { while($Val=~s/\"([\w\-]+)\"//) { my $Dr = $1; $Dr=~s/\-/_/g; $Device{"ActiveDriver_Common"}{$Dr} = keys(%{$Device{"ActiveDriver_Common"}}); } } elsif($Key eq "Driver Status") { if($Val=~/(.*) is active/) { my $Dr = $1; $Dr=~s/\-/_/g; $Device{"ActiveDriver"}{$Dr} = keys(%{$Device{"ActiveDriver"}}); } } elsif($Key eq "Module Alias") { if($Val=~/\"(.*)\"/) { $Val = $1; if($Val=~/ic(\w\w)isc(\w\w)ip(\w\w)\Z/) { # usb $C = devID($1, $2, $3); } elsif($Val=~/bc(\w\w)sc(\w\w)i(\w\w)\Z/) { # pci $C = devID($1, $2, $3); } $Device{$Key} = $Val; } } elsif($Key eq "Resolution" and $Device{"Type"} eq "monitor") { # monitor if($Val=~s/\@.*//) { if(not defined $Device{"Resolution"} or getXRes($Val)>getXRes($Device{"Resolution"})) { $Device{$Key} = $Val; $Device{$Key}=~s/ //g; } } } elsif($Key eq "Size" and $Device{"Type"} eq "monitor") { # monitor if($Val ne "1600x900 mm") { $Device{$Key} = $Val; $Device{$Key}=~s/ //g; } } elsif($Key eq "Size") { # disk if($Val=~/(\d+) sectors a (\d+) bytes/) { $Device{"Capacity"} = bytesToHuman($1*$2); } } elsif($Key eq "Capacity") { # disk if($Val=~s/\s*\((.*?)\)//) { my $Bytes = $1; $Bytes=~s/ bytes//g; $Val = bytesToHuman($Bytes); } $Val=~s/ //g; $Device{$Key} = $Val; } elsif($Key eq "Attached to") { $Device{"Attached"} = $Val; if($Bus eq "ide" or $Bus eq $PCI_DISK_BUS) { # FIXME: check for PATA # if($Val=~/SATA/) # { # $Bus = "sata"; # } } if($Val=~/#(\d+)/) { $DeviceAttached{$DevNum} = $1; } } elsif($Key eq "Device Files") { foreach my $F (split(/,\s*/, $Val)) { if(index($F, "nvme-nvme")==-1 and $F=~/by-id\/((ata|nvme|usb|mmc)-.*)\Z/) { $Device{"FsId"} = $1; } $Device{"AllFiles"}{$F} = 1; } } elsif($Key eq "Device File") { if($Device{"Type"} eq "disk" or $Device{"Type"} eq "storage device") { if($Val=~s/\s*\((.*)\)//) { $Device{"AdvFile"} = $1; } $Device{"File"} = $Val; if($Bus eq "ide" or $Bus eq $PCI_DISK_BUS or index($Val, "nvme")!=-1 or $Bus eq "usb") { $HDD{$Val} = 0; } elsif(index($Val, "mmcblk")!=-1 and $Val=~/mmcblk\d+\Z/) { $MMC{$Val} = 0; } } elsif($Device{"Type"} eq "network") { $Device{"Files"}{$Val} = 1; if($Bus eq "usb") { $ExtraConnection{$Val} = 1; } } elsif($Device{"Type"} eq "network interface") { if(index($Device{"SysFS Device Link"}, "\/usb")!=-1 or index($Device{"SysFS Device Link"}, "/devices/virtual")!=-1) { $ExtraConnection{$Val} = 1; } } } elsif($Key eq "Serial ID") { # disk if($Val=~/\"(.*)\"/) { $Device{"Serial"} = $1; } } elsif($Key eq "Memory Size") { # framebuffer $Val=~s/(\d)\s+(MB|GB|KB)/$1$2/ig; $Device{"Memory Size"} = $Val; } elsif($Key eq "Platform" and $Device{"Type"} eq "cpu") { # ARM if($Val=~/\"(.*)\"/) { $Device{"Platform"} = $1; } } elsif($Key eq "Link detected") { $Device{"Link detected"} = $Val; } elsif($Key eq "SysFS Device Link" ) { $Device{$Key} = $Val; } elsif($Key eq "SysFS ID" ) { $Device{$Key} = $Val; } } cleanValues(\%Device); if(my $DF = $Device{"File"}) { if($Bus eq "scsi") { if($Device{"Attached"}!~/RAID/) { $HDD{$DF} = 0; } } } if(not $Device{"Device"}) { if(my $Model = $Device{"Model"}) { $Device{"Device"} = $Model; } elsif($Device{"Type"} eq "cpu") { if(my $Platform = $Device{"Platform"}) { $Device{"Device"} = $Platform." Processor"; } elsif($Device{"Vendor"}) { $Device{"Device"} = $Device{"Vendor"}." Processor"; } } } if(defined $Device{"ActiveDriver"}) { $Device{"Driver"} = join(", ", sort {$Device{"ActiveDriver"}{$a} <=> $Device{"ActiveDriver"}{$b}} keys(%{$Device{"ActiveDriver"}})); } elsif(defined $Device{"ActiveDriver_Common"}) { $Device{"Driver"} = join(", ", sort {$Device{"ActiveDriver_Common"}{$a} <=> $Device{"ActiveDriver_Common"}{$b}} keys(%{$Device{"ActiveDriver_Common"}})); } if($Device{"Type"} eq "cpu") { $Bus = "cpu"; } elsif($Device{"Type"} eq "framebuffer") { $Bus = "fb"; next; # disabled } if($Device{"Type"} eq "network") { if($Bus eq "pci") { if($Sys{"NICs"}) { $Sys{"NICs"} += 1; } else { $Sys{"NICs"} = 1; } } foreach my $NF (keys(%{$Device{"Files"}})) { if($NF=~/\Ae/) { $Device{"Kind"} = "Ethernet"; } elsif($NF=~/\Aw/) { $Device{"Kind"} = "WiFi"; } } } if($Device{"Type"} eq "monitor") { if(my $MSize = $Device{"Size"}) { if(my $Inches = computeInch($MSize)) { $Device{"Inches"} = sprintf("%.1f", $Inches); if(my $Density = computeDensity($Device{"Resolution"}, $Inches)) { $Device{"Density"} = roundFloat($Density, 1); } } if(my $Ratio = computeRatio($MSize)) { $Device{"Ratio"} = $Ratio; } if(my $Area = computeArea($MSize)) { $Device{"Area"} = $Area; } if($MSize=~/\A(\d+)/) { $Device{"Width"} = $1; } } if(not $Device{"Ratio"}) { if(my $RatioByRes = computeRatio($Device{"Resolution"})) { $Device{"Ratio"} = $RatioByRes; } } } if($Device{"Type"} eq "disk") { if(not $Device{"Capacity"} and defined $BlockCapacity{$Device{"File"}}) { $Device{"Capacity"} = $BlockCapacity{$Device{"File"}}; } $DriveNumByFile{$Device{"File"}} = $DevNum; if(index($Device{"File"}, "nvme")!=-1) { if(not $Device{"Device"} or $Device{"Device"} eq "Disk" or not $Device{"Vendor"} or not $Device{"Serial"}) { if($Device{"FsId"}=~/\Anvme\-(INTEL|Samsung)_(.+)_([^_]+)\Z/) { $Device{"Vendor"} = ucfirst(lc($1)); $Device{"Model"} = $2; $Device{"Serial"} = $3; $Device{"Model"}=~s/_/ /g; $Device{"Device"} = $Device{"Model"}; if($Device{"Serial"} and $Device{"Serial"}!~/\A[\dA-F]{$HASH_LEN_CLIENT}\Z/) { $Device{"Serial"} = clientHash($Device{"Serial"}); } if($Bus eq "none") { $Bus = $PCI_DISK_BUS; } } } if(not $Device{"Device"} or $Device{"Device"} eq "Disk" or not $Device{"Vendor"} or not $Device{"Serial"}) { # empty info for NVMe drives if($Device{"Model"}) { if(index($Device{"Model"}, $Device{"Device"})!=-1) { if(my $Vnd = guessDeviceVendor($Device{"Model"})) { $Device{"Model"} = $Vnd." Disk"; $Device{"Vendor"} = $Vnd; } else { $Device{"Model"} = undef; } } elsif($Device{"Model"}=~/controller/i) { $Device{"Model"} = undef; } } $HDD_Info{$Device{"File"}} = \%Device; next; } } elsif(index($Device{"File"}, "mmcblk")!=-1) { $Bus = "mmc"; if($Device{"FsId"} and $Device{"FsId"}=~/mmc-(.+?)[_]+(0x[a-f\d]{8})/) { $Device{"Device"} = $1; $Device{"Serial"} = clientHash($2); } else { $Device{"Device"} = "MMC Card"; # $Device{"Serial"} = "000"; } $MMC_Info{$Device{"File"}} = \%Device; next; } if(not $Device{"Attached"}) { next; } } #if($Bus eq "none") #{ # if($Device{"Type"} eq "disk" and $Device{"File"}=~/\/dev\/vd/) { # $Bus = "ide"; # } #} if($Bus eq "none") { if($Device{"Module Alias"}=~/\Aplatform:/) { $Bus = "platform"; } } if($Bus eq "none") { next; } if(not $Device{"Type"}) { $Device{"Type"} = getDefaultType($Bus, $D, \%Device); } # fix type if($Device{"Type"} eq "keyboard") { if($Device{"Device"}=~/mouse/i and $Device{"Device"}!~/keyboard/i) { $Device{"Type"} = "mouse"; } } elsif($Device{"Type"} eq "mouse") { if($Device{"Device"}!~/mouse/i) { if($Device{"Device"}=~/keyboard/i) { $Device{"Type"} = "keyboard"; } elsif($Device{"Device"}=~/touchscreen/i) { $Device{"Type"} = "touchscreen"; } elsif($Device{"Device"}=~/touchpad/i) { $Device{"Type"} = "touchpad"; } } } elsif($Device{"Type"} eq "printer") { if($Device{"Device"}=~/(\A| )MFP( |\Z)/) { $Device{"Type"} = "mfp"; } } elsif($Device{"Type"} eq "disk") { if(defined $Device{"AllFiles"}{"/dev/cdrom"}) { $Device{"Type"} = "cdrom"; if(my $File = $Device{"File"}) { delete($HDD{$File}); } } } # fix vendor if($V eq "1d6b") { $Device{"Vendor"} = "Linux Foundation"; } if(not $Device{"Vendor"}) { if($Bus eq "ps/2") { if($Device{"Type"}=~/touchpad|touchscreen|mouse/) { if($Device{"Device"}=~s/(\w+) (DualPoint Touchpad)/$2/i) { # AlpsPS/2 ALPS DualPoint TouchPad $Device{"Vendor"} = $1; } elsif($Device{"Device"}=~s/(\w+) (Touchpad|TrackPoint|GlidePoint)/$2/i) { $Device{"Vendor"} = $1; } elsif($Device{"Device"}=~s/(PS\/2) (\w+) (Wheel Mouse)/$1 $3/i) { if($2 ne "Generic") { $Device{"Vendor"} = $2; } } elsif($Device{"Device"}=~/(Sony) Vaio Jogdial/i) { $Device{"Vendor"} = $1; } elsif($Device{"Device"}=~/\A(ALPS|Goodix|Wacom) /i) { $Device{"Vendor"} = $1; } if($Device{"Vendor"} eq "FocalTech") { $Device{"Device"}=~s/FocalTech (FocalTech)/$1/i; } } } } if($Device{"Type"} eq "disk" and $Device{"Device"}=~/DVD|\ACD(-|RW)|\ADRW-|\A(DVD|DVDR|DVDRAM) /) { $Device{"Type"} = "cdrom"; } if($Device{"Type"} eq "disk" and $Bus ne "usb") { my $FsId = $Device{"FsId"}; if(not $FsId) { # Docker if($Device{"File"}) { $FsId = $DevIdByName{basename($Device{"File"})}; } } if($FsId) { my $N = $Device{"Device"}; $N=~s/ /_/g; if(my $Serial = $Device{"Serial"}) { if($FsId=~/\Q$N\E(.*?)_\Q$Serial\E/) { my $Suffix = $1; $Suffix=~s/[_]+/ /g; $Suffix=~s/ 1XB\Z/ 1TB/; # wrong anonymization $Device{"Device"} .= $Suffix; } } elsif($FsId=~/\Q$N\E(.*)_(.*?)\Z/) { my $Suffix = $1; my $Ser = $2; $Suffix=~s/[_]+/ /g; $Suffix=~s/ 1XB\Z/ 1TB/; # wrong anonymization $Device{"Device"} .= $Suffix; if(not $Device{"Serial"} and index($Ser, "...") == -1) { $Device{"Serial"} = $Ser; } } } if(defined $DriveKind{$Device{"File"}}) { # NOTE: on fixing probe $Device{"Kind"} = $DriveKind{$Device{"File"}}; } $Device{"Device"} = duplVendor($Device{"Vendor"}, $Device{"Device"}); # Fix incorrect vendor in hwinfo if($Device{"Vendor"} eq "m.2") { $Device{"Device"} .= " ".$Device{"Vendor"}; $Device{"Vendor"} = undef; } elsif($Device{"Vendor"} eq "SK") { $Device{"Device"} = $Device{"Vendor"}." ".$Device{"Device"}; $Device{"Vendor"} = undef; } fixDrive_Pre(\%Device, $Bus); fixDrive(\%Device); } else { if($Device{"Type"} eq "storage device") { if(not $Device{"Vendor"} and my $Vnd = guessDriveVendor($Device{"Device"})) { $Device{"Vendor"} = $Vnd; $Device{"Device"} = duplVendor($Device{"Vendor"}, $Device{"Device"}); } } $Device{"Device"} = duplVendor($Device{"Vendor"}, $Device{"Device"}); if($Device{"Type"} eq "monitor" and not $Device{"Device"}) { $Device{"Device"} = "LCD Monitor"; } } if($Bus eq "usb" or $Bus eq "pci") { $ID = devID($V, $D, $SV, $SD); if($SD) { $LongID{$Bus.":".devID($V, $D)}{$ID} = 1; } if($Device{"Type"} eq "disk") { $Device{"Device"} .= addCapacity($Device{"Device"}, $Device{"Capacity"}); } } else { if($Device{"Device"} eq "Unclassified device") { # PNP devices, etc. next; } if(not $Device{"Device"}) { next; } if($Device{"Type"} eq "monitor") { if(lc($Device{"Device"}) eq lc($Device{"Vendor"})) { $Device{"Device"} = $Device{"GeneralType"}; } if($V) { if(my $Vendor = getPnpVendor($V)) { $Device{"Vendor"} = $Vendor; $Device{"Device"}=~s/\A\Q$Vendor\E(\s+|\-)//ig; } elsif(not $Device{"Vendor"}) { $Device{"Vendor"} = $V; } } } if($Device{"Type"} eq "framebuffer") { if($Device{"Vendor"} eq $Device{"Device"}) { $Device{"Vendor"} = ""; } } # create id if($Device{"Type"} eq "monitor" and $V) { #if(nameID($Device{"Vendor"}) ne $V) #{ # do not add vendor name to id $ID = devID(nameID($Device{"Vendor"})); #} $ID = devID($ID, $V.$D); } else { if(my $Vendor = $Device{"Vendor"}) { $ID = devID(nameID($Vendor)); } else { $ID = devID($V); } $ID = devID($ID, $D, devSuffix(\%Device)); } # additionals to device attributes if($Device{"Type"} eq "monitor") { if($D) { $Device{"Device"} .= " ".uc($V.$D); } if($Device{"Resolution"}) { $Device{"Device"} .= " ".$Device{"Resolution"}; } if($Device{"Size"}) { $Device{"Device"} .= " ".$Device{"Size"}; } if(my $Inches = $Device{"Inches"}) { $Device{"Device"} .= " ".$Inches."-inch"; } } elsif($Device{"Type"} eq "disk") { $Device{"Device"} .= addCapacity($Device{"Device"}, $Device{"Capacity"}); if($Device{"Kind"} eq "SSD" and $Device{"Device"}!~/SSD|Solid State/i) { $Device{"Device"} .= " SSD"; } } elsif($Device{"Type"} eq "cpu") { $Device{"Status"} = "works"; } elsif($Device{"Type"} eq "framebuffer") { $Device{"Device"} .= " ".$Device{"Memory Size"}; } } if($Device{"Type"} eq "network") { if(defined $Device{"Files"}) { foreach my $F (sort keys(%{$Device{"Files"}})) { if(defined $UsedNetworkDev{$F}) { $Device{"Status"} = "works"; } } } if($Device{"Link detected"} eq "yes") { $Device{"Status"} = "works"; } } # delete unused fields delete($Device{"ActiveDriver_Common"}); delete($Device{"ActiveDriver"}); delete($Device{"FsId"}); delete($Device{"Model"}); delete($Device{"GeneralType"}); delete($Device{"Attached"}); delete($Device{"AllFiles"}); delete($Device{"Files"}); delete($Device{"Module Alias"}); delete($Device{"SysFS Device Link"}); if($C) { $Device{"Class"} = $C; } cleanValues(\%Device); $ID = fmtID($ID); my $BusID = $Bus.":".$ID; if($Device{"Type"} eq "monitor") { $Monitor_ID{uc($V.$D)} = $ID; } elsif($Device{"Type"} eq "disk" or $Device{"Type"} eq "storage device") { if(my $File = $Device{"File"}) { $HDD{$File} = $BusID; } } if($Bus eq "ps/2" and $Device{"Type"}=~/touchpad/) { if(not $Sys{"Type"} or $Sys{"Type"}=~/$DESKTOP_TYPE|$SERVER_TYPE|other/) { $Sys{"Type"} = "notebook"; } } if($Bus eq "pci" and $Device{"SysFS ID"}=~/\/0000\:([^\/]+)\Z/) { $DevBySysID{$1} = $ID; } delete($Device{"SysFS ID"}); $DeviceIDByNum{$DevNum} = $BusID; $DeviceNumByID{$BusID} = $DevNum; if(not $HW{$BusID}) { $HW{$BusID} = \%Device; } else { # double entry if($Device{"Type"} and not $HW{$BusID}{"Type"}) { $HW{$BusID} = \%Device; } if($HW{$BusID}{"Driver"} eq "nvidiafb") { # two Nvidia cards $HW{$BusID}{"Driver"} = $Device{"Driver"}; } } if($Device{"Type"} and $Device{"Type"}!~/mouse|keyboard|monitor/) { countDevice($BusID, $Device{"Type"}); } if($Device{"Type"} eq "cpu") { if($Device{"Vendor"}) { $CPU_ID = $BusID; } } else { $ComponentID{$Device{"Type"}}{$BusID} = 1; } } my $Sysctl = ""; if($Opt{"FixProbe"}) { $Sysctl = readFile($FixProbe_Logs."/sysctl"); } elsif(enabledLog("sysctl") and checkCmd("sysctl")) { listProbe("logs", "sysctl"); $Sysctl = runCmd("sysctl -a 2>/dev/null"); $Sysctl=~s{()(.+)()}{$1...$3}g; $Sysctl=~s/((kern\.hostname|serialno|-serial|-asset-tag)\s*[:=]\s*).+/$1.../g; $Sysctl=~s/ ([^\s]+) (login|syslogd)/ ... $2/g; $Sysctl=~s/(Serial Number\s+)(.+)/$1.../g; $Sysctl=~s/((sernum|soiikey)=)[^\s]+/$1.../g; foreach my $Hide ("kern.msgbuf", "kern.geom.confxml", "kern.geom.confdot", "kern.geom.conftxt") { $Sysctl=~s/(\Q$Hide\E:).+?(\skern\.)/$1 ...$2/gs; } $Sysctl=~s/(vm\.pmap\.kernel_maps:).+?(\svm\.pmap\.)/$1 ...$2/gs; $Sysctl = encryptUUIDs($Sysctl); $Sysctl = encryptSerials($Sysctl, "kern.hostid"); $Sysctl = encryptMACs($Sysctl); $Sysctl = hideIPs($Sysctl); $Sysctl = hidePaths($Sysctl); $Sysctl = hideEmail($Sysctl); writeLog($LOG_DIR."/sysctl", $Sysctl); if(isOpenBSD()) { if($Sysctl=~/kern\.allowkmem=0/) { printMsg("WARNING", "DMI info cannot be collected, need kern.allowkmem=1 to be set"); } } if($Sysctl=~/kern\.securelevel\s*[=:]\s*([2])/) { printMsg("WARNING", "can't list all devices due to securelevel=$1"); } } if($Sysctl) { if(isOpenBSD()) { if($Sysctl=~/hw\.disknames=(.+)/) { my $DrNames = $1; my @Drs = ($DrNames=~/(\w+):/g); foreach my $Dr (@Drs) { if($Dr=~/\Acd\d+/) { # TODO: detect CDROM } elsif($Dr=~/\Afd\d+/) { # TODO: detect floppy } else { $HDD{"/dev/".$Dr} = 0; } } } } elsif($Sys{"System"}=~/dragonfly|midnightbsd/ or defined $Sys{"Freebsd_release"}) { if($Sysctl=~/kern\.disks: (.+)/) { my @Drs = split(/\s+/, $1); foreach my $Dr (@Drs) { if($Dr!~/\A(md|vn|cd|fd)\d+/) { $HDD{"/dev/".$Dr} = 0; } } } } elsif(isNetBSD()) { if($Sysctl=~/hw\.disknames = (.+)/) { my @Drs = split(/\s+/, $1); foreach my $Dr (@Drs) { if($Dr!~/\A(cd|fd)\d+/) { $HDD{"/dev/".$Dr} = 0; } } } } } my $DevInfo = ""; if($Opt{"FixProbe"}) { $DevInfo = readFile($FixProbe_Logs."/devinfo"); } elsif($Opt{"HWLogs"} and enabledLog("devinfo") and checkCmd("devinfo")) { listProbe("logs", "devinfo"); $DevInfo .= runCmd("devinfo -v 2>&1"); $DevInfo=~s/(sernum=)[^\s]+/$1.../g; writeLog($LOG_DIR."/devinfo", $DevInfo); } if($DevInfo) { my %ParentDev = (); foreach my $Line (split(/\n/, $DevInfo)) { if($Line=~/\A(\s*)(\w+\d+)/) { my $CurDepth = length($1)/2; my $DevFile = $2; $ParentDev{$CurDepth} = $DevFile; foreach (0 .. $CurDepth - 1) { $DevAttachedRecursive{$DevFile}{$ParentDev{$_}} = 1; $DevAttachedRecursive_R{$ParentDev{$_}}{$DevFile} = 1; } if($CurDepth > 0) { $DevAttached{$DevFile} = $ParentDev{$CurDepth - 1}; $DevAttached_R{$ParentDev{$CurDepth - 1}}{$DevFile} = 1; } } } } my $FreeBSD7 = (defined $Sys{"Freebsd_release"} and $Sys{"Freebsd_release"} < 8.0); my $Dmesg = ""; if($Opt{"FixProbe"}) { $Dmesg = readFile($FixProbe_Logs."/dmesg"); } elsif(checkCmd("dmesg")) { listProbe("logs", "dmesg"); my $DmesgBoot = "/var/run/dmesg.boot"; if(isBSD() and -e $DmesgBoot) { $Dmesg = readFile($DmesgBoot); } else { $Dmesg = runCmd("dmesg 2>&1"); } my $Messages = "/var/log/messages"; if(not isBSD() and -e $Messages and -r $Messages) { if(index($Dmesg, "] Command line:") == -1) { $Dmesg = runCmd("grep -I ' kernel: \\[' $Messages | sed 's/.* kernel: \\[/\\[/g'"); $Dmesg=~s/(.|\n)+(\[ 0.000000\] Linux version)/$2/g; # last boot only } } $Dmesg = hideDmesg($Dmesg); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/dmesg", $Dmesg); } } my %PciNumDev = (); my %PciPPb = (); my %UsbAddrDev = (); my %UsbAddrClass = (); if(isBSD()) { if($Dmesg=~/<(PS\/2 Mouse)>.* on (\w+)\d+/) { $HW{"ps/2:mouse"} = {"Device"=>$1, "Driver"=>$2, "Type"=>"mouse"}; } if($Dmesg=~/<(AT Keyboard)>.* on (\w+)\d+/) { $HW{"ps/2:keyboard"} = {"Device"=>$1, "Driver"=>$2, "Type"=>"keyboard"}; } if(isOpenBSD()) { if(not $Bios_ID and $Dmesg=~/bios0: vendor (.+) version "(.+)" date (.+)/) { $Bios_ID = registerBIOS({"Vendor"=>fmtVal($1), "Version"=>$2, "Release Date"=>$3}); } } if(not isOpenBSD() and not isNetBSD()) { my @DrmMap = ($Dmesg=~/(\w+\d+: .+ on vgapci\d+)/g); foreach my $Dr (@DrmMap) { if($Dr=~/\A(\w+\d+): .+ on (vgapci\d+)\Z/) { $DrmAttached{$2}{$1} = 1; } } my @DrmMap2 = ($Dmesg=~/(Initialized .+ for drmn\d+)/g); foreach my $Dr (@DrmMap2) { if($Dr=~/\AInitialized (\w+) .+ for (drmn\d+)\Z/) { $DrmAttached{$2}{$1} = 1; } } my @DrmMap3 = ($Dmesg=~/(drmn\d+: .+)/g); foreach my $Dr (@DrmMap3) { if($Dr=~/\A(drmn\d+): (.+)\Z/) { my ($DrmFile, $DrmDesc) = ($1, $2); if($DrmDesc=~/amdgpu/) { $DrmAttached{$DrmFile}{"amdgpu"} = 1; } } } } my @DriversMap = ($Dmesg=~/(\w+\d+ at \w+\d+)/g); foreach my $Dr (@DriversMap) { if($Dr=~/\A(\w+\d+) at (\w+\d+)\Z/) { my ($DevFile, $Parent) = ($1, $2); $DevAttached{$DevFile} = $Parent; $DevAttached_R{$Parent}{$DevFile} = 1; } } foreach my $DevFile (keys(%DevAttached)) { my $CurDevFile = $DevFile; my %Recur = (); while(defined $DevAttached{$CurDevFile}) { if(defined $Recur{$CurDevFile}) { last; } $DevAttachedRecursive{$DevFile}{$DevAttached{$CurDevFile}} = 1; $Recur{$CurDevFile} = 1; $CurDevFile = $DevAttached{$CurDevFile}; } } if(isOpenBSD() or (isNetBSD() and $Sys{"System_version"} < 9.0)) { my @AllPpb = ($Dmesg=~/\n(pci\d+ at ppb\d+ bus \d+)/g); foreach my $PciLine (@AllPpb) { if($PciLine=~/pci(\d+) at ppb\d+ bus (\d+)/) { $PciPPb{$1} = $2; } } my @AllPci = ($Dmesg=~/\n(\w+\d+ at pci\d+ dev \d+ function \d+)/g); # others are not configured foreach my $PciLine (@AllPci) { if($PciLine=~/\A(\w+\d+) at pci(\d+) dev (\d+) function (\d+)\Z/) { my $DevFile = $1; my ($Pn1, $Pn2, $Pn3) = ($2, $3, $4); if(defined $PciPPb{$Pn1}) { $Pn1 = $PciPPb{$Pn1}; } $PciNumDev{$Pn1.":".$Pn2.":".$Pn3} = $DevFile; } } } if(isNetBSD() or (isOpenBSD() and $Sys{"System_version"} < 6.3)) { my @AllUsb = ($Dmesg=~/[ \n](\w+\d+ at \w+\d+.+? addr \d+)/g); # others are not configured foreach my $UsbLine (@AllUsb) { if($UsbLine=~/\A(\w+\d+) at (\w+\d+).+? addr (\d+)\Z/) { my ($DevFile, $Parent, $UsbAddr) = ($1, $2, $3); $UsbAddrDev{$Parent}{$UsbAddr} = $DevFile; } } my @DevUsb = ($Dmesg=~/[ \n](\w+\d+: .+? addr \d+)/g); # others are not configured foreach my $UsbLine (@DevUsb) { if($UsbLine=~/\A(\w+\d+): .+? addr (\d+)\Z/) { my ($DevFile, $UsbAddr) = ($1, $2); $UsbAddrDev{$DevFile}{$UsbAddr} = $DevFile; } } } elsif($FreeBSD7) { my @AllUsb = ($Dmesg=~/\n(\w+\d+: .+? class [a-f\d]+\/[a-f\d]+.+? addr \d+.+? on \w+\d+)/g); foreach my $UsbLine (@AllUsb) { if($UsbLine=~/\A(\w+\d+): .+? class ([a-f\d]+)\/([a-f\d]+).+? addr (\d+).+? on (\w+\d+)\Z/) { my ($DevFile, $C1, $C2, $UsbAddr, $Parent) = ($1, $2, $3, $4, $5); $UsbAddrDev{$Parent}{$UsbAddr} = $DevFile; $UsbAddrClass{$Parent}{$UsbAddr} = devID((fNum($C1), fNum($C2))); } } } foreach my $D (keys(%HDD)) { my $DFile = basename($D); if($Dmesg=~/\b\Q$DFile\E: <([^<>]+?)>/) { $HDD_Info{$DFile}{"Title"} = $1; } } } my $Sensors = ""; if($Opt{"FixProbe"}) { $Sensors = readFile($FixProbe_Logs."/sensors"); } elsif(enabledLog("sensors") and checkCmd("sensors")) { listProbe("logs", "sensors"); $Sensors = runCmd("sensors 2>/dev/null"); writeLog($LOG_DIR."/sensors", $Sensors); } if($Sensors) { $Sys{"Cpu_temp"} = undef; $Sys{"Cpu_fan"} = undef; foreach my $S (split(/\n\n/, $Sensors)) { if($S=~/k\d+temp-pci|acpitz|cpu\d+_thermal/) { if(not $Sys{"Cpu_temp"} and $S=~/(temp1|Tctl):\s*\+([\d\.]+)/) { $Sys{"Cpu_temp"} = $2; } } elsif($S=~/dell_smm|-(isa|i2c)-/) { my $FanSpeed = undef; foreach my $F ($S=~/(fan\d+|Left side|Right side)\s*:\s*([\d\.]+)/g) { if($F=~/[a-z]/i) { next; } if(not $FanSpeed or $F>$FanSpeed) { $FanSpeed = $F; } } if(defined $FanSpeed) { $Sys{"Cpu_fan"} = $FanSpeed; } foreach my $Sp (split(/\n/, $S)) { if($Sp=~/CPU/ and $Sp=~/temp\d+:\s*\+([\d\.]+)/) { $Sys{"Cpu_temp"} = $1; } } } } if($Sensors=~/(Physical|Package) id 0:\s*\+([\d\.]+)/) { $Sys{"Cpu_temp"} = $2; } else { my $CoreTemp = undef; foreach my $T ($Sensors=~/(Core \d+|Core\d+ Temp):\s*\+([\d\.]+)/g) { if($T=~/[a-z]/i) { next; } if(not $CoreTemp or $T>$CoreTemp) { $CoreTemp = $T; } } if(defined $CoreTemp) { $Sys{"Cpu_temp"} = $CoreTemp; } elsif($Sensors=~/(CPU|CPU Temperature):\s*\+([\d\.]+)/) { $Sys{"Cpu_temp"} = $2; } } if($Sensors=~/(Processor Fan|cpu_fan|CPU FAN Speed|Exhaust)\s*:\s*([\d\.]+)/) { $Sys{"Cpu_fan"} = $2; } if($Sys{"Cpu_temp"} eq "0") { $Sys{"Cpu_temp"} = undef; } if(not defined $Sys{"Cpu_temp"}) { # printMsg("INFO", "failed to identify CPU temperature"); } } my $Uptime = ""; if($Opt{"FixProbe"}) { $Uptime = readFile($FixProbe_Logs."/uptime"); } elsif(enabledLog("uptime") and checkCmd("uptime")) { listProbe("logs", "uptime"); $Uptime = runCmd("uptime"); writeLog($LOG_DIR."/uptime", $Uptime); } if($Uptime) { chomp($Uptime); if($Uptime=~/load average:\s+(.+?)\Z/) { $Sys{"Load_average"} = $1; } } my $Geom = ""; if($Opt{"FixProbe"}) { $Geom = readFile($FixProbe_Logs."/geom"); } elsif(enabledLog("geom") and checkCmd("geom")) { listProbe("logs", "geom"); $Geom = runCmd("geom disk list 2>/dev/null"); $Geom = encryptSerials($Geom, "ident"); $Geom=~s/(lunid:\s*[a-f\d]{7})[a-f\d]{9}\n/$1...\n/g; # WWN $Geom=~s/( SN ).+?( MFG )/$1...$2/g; writeLog($LOG_DIR."/geom", $Geom); } foreach my $DriveInfo (split(/\n\n/, $Geom)) { if($DriveInfo=~/Geom name:\s+(.+)/) { my $DevFile = $1; if($DevFile=~/\Acd\d\Z/) { if(not $CDROM_ID and $DriveInfo=~/descr:\s+(.+)/) { $CDROM_ID = registerCdrom($1, $DevFile); } } elsif($DevFile=~/\Afd\d\Z/) { # TODO: detect floppy } else { $HDD{"/dev/".$DevFile} = 0; } } } my $Sysinfo = ""; if($Opt{"FixProbe"}) { $Sysinfo = readFile($FixProbe_Logs."/sysinfo"); } elsif(enabledLog("sysinfo") and checkCmd("sysinfo")) { listProbe("logs", "sysinfo"); $Sysinfo = runCmd("sysinfo -a -v 1 -c -i 2>/dev/null"); $Sysinfo = encryptUUIDs($Sysinfo); $Sysinfo = encryptMACs($Sysinfo); $Sysinfo = hideIPs($Sysinfo); $Sysinfo=~s/(Serial Number\s+)[^\s]+/$1.../g; if($Sysinfo) { writeLog($LOG_DIR."/sysinfo", $Sysinfo); } } if($Sysinfo) { if($Sysinfo=~/Total real memory available:\s+(\d+) MB/) { $Sys{"Ram_total"} = $1*1024; } if($Sysinfo=~/Logically used memory:\s+(\d+) MB/) { $Sys{"Ram_used"} = $1*1024; } } # UDEV my $Udevadm = ""; if($Opt{"FixProbe"}) { $Udevadm = readFile($FixProbe_Logs."/udev-db"); if(not $Udevadm) { # support for old probes $Udevadm = readFile($FixProbe_Logs."/udevadm"); } if(not $Udevadm) { # support for sdio $Udevadm = readFile($FixProbe_Logs."/sdio"); } } elsif(checkCmd("udevadm") and $Opt{"HWLogs"}) { listProbe("logs", "udev-db"); $Udevadm = runCmd("udevadm info --export-db 2>/dev/null"); $Udevadm = hideTags($Udevadm, "ID_NET_NAME_MAC|ID_SERIAL|ID_SERIAL_SHORT|DEVLINKS|ID_WWN|ID_WWN_WITH_EXTENSION"); $Udevadm=~s/(by\-id\/(ata|usb|nvme|wwn)\-).+/$1.../g; $Udevadm = encryptUUIDs($Udevadm); $Udevadm = encryptSerials($Udevadm, "SERIAL_NUMBER"); if(enabledLog("udev-db")) { writeLog($LOG_DIR."/udev-db", $Udevadm); } else { my $ExtraDevs = ""; foreach my $UL (split(/\n\n/, $Udevadm)) { if($UL=~/sdio/) { $ExtraDevs .= $UL."\n\n"; } } $Udevadm = $ExtraDevs; if($ExtraDevs) { writeLog($LOG_DIR."/sdio", $ExtraDevs); } } } my %HDD_Serial = (); foreach my $Info (split(/\n\n/, $Udevadm)) { my %DInfo = ""; foreach my $Line (split(/\n/, $Info)) { if($Line=~/E:\s+(\w+)\=(.+)/) { $DInfo{$1} = $2; } } my %Device = (); my $Bus = undef; my ($V, $D) = (); my $ID = undef; if($DInfo{"DEVTYPE"} eq "disk" and $DInfo{"ID_TYPE"} eq "disk") { $HDD_Serial{$DInfo{"ID_MODEL"}}{$DInfo{"ID_SERIAL_SHORT"}} = 1; } if($DInfo{"SUBSYSTEM"} eq "sdio") { $Bus = "sdio"; if($DInfo{"SDIO_ID"}=~/(\w\w\w\w)\:(\w\w\w\w)/) { ($V, $D) = (lc($1), lc($2)); if(not keys(%SdioInfo)) { readSdioIds_Sys(); } $Device{"Vendor"} = $SdioVendor{$V}; $Device{"Device"} = $SdioInfo{$V}{$D}; $ID = devID($V, $D); } $Device{"Class"} = $DInfo{"SDIO_CLASS"}; if($Device{"Device"}=~/WLAN|Wireless/i) { $Device{"Class"} = "07"; } $Device{"Driver"} = $DInfo{"DRIVER"}; $Device{"Type"} = getSdioType($Device{"Class"}); } if($ID) { $ID = fmtID($ID); if(not $HW{$Bus.":".$ID}) { $HW{$Bus.":".$ID} = \%Device; } } } # fix incomplete HDD ids (if not root) if((not $Admin or $Opt{"FixProbe"}) and keys(%HDD_Serial)) { foreach my $ID (sort keys(%HW)) { if($ID=~/\Aide:(.+)/) { my $Name = $HW{$ID}{"Device"}; foreach my $FN (sort keys(%HDD_Serial)) { if($FN=~/\Q$Name\E(.+)/i) { my $Missed = $1; foreach my $Ser (sort keys(%{$HDD_Serial{$FN}})) { my $NewID = $ID.devID($Missed)."-serial-".devID($Ser); $HW{$NewID} = $HW{$ID}; $HW{$NewID}{"Device"}=~s/(\Q$Name\E)/$1$Missed/; countDevice($NewID, $HW{$NewID}{"Type"}); } delete($HW{$ID}); } } } } } # PCI (all) my $Lspci_A = ""; if($Opt{"FixProbe"}) { $Lspci_A = readFile($FixProbe_Logs."/lspci_all"); } elsif(enabledLog("lspci_all") and checkCmd("lspci")) { listProbe("logs", "lspci_all"); my $PciLink = createIDsLink("pci"); $Lspci_A = runCmd("lspci -vvnn 2>&1"); if($PciLink) { unlink($PciLink); } $Lspci_A=~s/(Serial Number:?\s+|Manufacture ID:\s+).+/$1.../gi; if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/lspci_all", $Lspci_A); } } if(isBSD()) { # collect but do not parse $Lspci_A = ""; } foreach my $Info (split(/\n\n/, $Lspci_A)) { my ($V, $D) = (); my @ID = (); if($Info=~/\w+:\w+\.\w\s+(.*?)\s*\[\w+\]:.*?\[(\w+)\:(\w+)\]/) { ($V, $D) = ($2, $3); } if($Info=~/Subsystem\:.*?\[(\w+)\:(\w+)\]/i) { my ($SV, $SD) = ($1, $2); if($SV ne "0000" or $SD ne "0000") { push(@ID, $SV, $SD); } } my $ID = devID($V, $D, @ID); if($V and $D and @ID) { $LongID{"pci:".devID($V, $D)}{$ID} = 1; } } # PCI my $Lspci = ""; if($Opt{"FixProbe"}) { $Lspci = readFile($FixProbe_Logs."/lspci"); } else { if(checkCmd("lspci")) { listProbe("logs", "lspci"); my $PciLink = createIDsLink("pci"); if(isBSD()) { $Lspci = runCmd("lspci -vmnn 2>&1"); } else { $Lspci = runCmd("lspci -vmnnk 2>&1"); } if($PciLink) { unlink($PciLink); } } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/lspci", $Lspci); } } if(isBSD()) { # collect but do not parse $Lspci = ""; } foreach my $Info (split(/\n\n/, $Lspci)) { my %Device = (); my (@IDs, @Class) = (); while($Info=~s/(\w+):\s*(.*)//) { if($1 eq "Rev") { next; } if($1 eq "Device" and not defined $Device{$1}) { $Device{"SysFsId"} = $2; } $Device{$1} = $2; } foreach ("Vendor", "Device", "SVendor", "SDevice") { if($Device{$_}=~s/\s*\[(\w{4})\]\s*\Z//) { push(@IDs, $1); } } my $ClassName = $Device{"Class"}; if($ClassName=~s/\s*\[(\w{2})(\w{2})\]//) { push(@Class, $1, $2); if($Device{"ProgIf"}) { push(@Class, $Device{"ProgIf"}); } } delete($Device{"Class"}); delete($Device{"ProgIf"}); cleanValues(\%Device); if($Opt{"PciIDs"} or 1) { if(not $Device{"Device"}) { if(my $Name = $PciInfo{"I"}{$IDs[0]}{$IDs[1]}) { $Device{"Device"} = $Name; } } if(not $Device{"SDevice"}) { if(my $Name = $PciInfo{"D"}{$IDs[0]}{$IDs[1]}{$IDs[2]}{$IDs[3]}) { $Device{"SDevice"} = $Name; } } } $Device{"Class"} = devID(@Class); my $ID = devID(@IDs); if(not $ID) { next; } if($Device{"SysFsId"} and my $OrigID = $DevBySysID{$Device{"SysFsId"}}) { if($ID ne $OrigID) { $ID = $OrigID; } } elsif(my $L_ID = getLongPCI("pci:".$ID)) { my $S_ID = $ID; $ID = $L_ID; if(defined $HW{"pci:".$S_ID}) { $HW{"pci:".$ID} = $HW{"pci:".$S_ID}; delete($HW{"pci:".$S_ID}); } } #if(defined $HW{"pci:".$ID}{"Class"}) { # delete($Device{"Class"}); #} if($Device{"Module"}) { $Device{"Driver"} = $Device{"Module"}; delete($Device{"Module"}); } my $NewDevice = (not defined $HW{"pci:".$ID}); $Device{"Type"} = getDefaultType("pci", $IDs[1], \%Device); if(not $Device{"Type"}) { if($Class[0] eq "02") { # pci:10ec-8136-10ec-8136 $Device{"Type"} = "network"; } } if(not $Device{"Type"}) { if(@Class) { $Device{"Type"} = getClassType("pci", devID(@Class)); } } if(not $Device{"Type"}) { if($Device{"Device"}=~/Ethernet Controller/i) { $Device{"Type"} = "network"; } } if(not $Device{"Type"} and $ClassName ne "Class") { $Device{"Type"} = lc($ClassName); } delete($Device{"SysFsId"}); foreach my $Attr (keys(%Device)) { if(my $Val = $Device{$Attr}) { if(not $NewDevice) { if($Attr eq "Driver") { next; } if($Attr eq "Type" and $HW{"pci:".$ID}{$Attr}) { next; } } $HW{"pci:".$ID}{$Attr} = $Val; } } } my %PciCtlInfo = (); my $PciCtl = ""; if($Opt{"FixProbe"}) { $PciCtl = readFile($FixProbe_Logs."/pcictl"); } elsif(enabledLog("pcictl") and checkCmd("pcictl")) { listProbe("logs", "pcictl"); $PciCtl = runCmd("pcictl pci0 list -N 2>/dev/null"); if(not $PciCtl) { # NetBSD 7.2 $PciCtl = runCmd("pcictl pci0 list 2>/dev/null"); } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/pcictl", $PciCtl); } } foreach my $Info (split(/\n/, $PciCtl)) { if($Info=~/\A([^\s]+):\s+([^\s]+)\s+(.+?)\s+\((\w+)\s+([^,]+).*?\)\s+\[(\w+\d+)\]/) { $PciCtlInfo{$1} = {"Vendor"=>$2, "Device"=>$3, "SubType"=>$4, "Type"=>$5, "File"=>$6}; } elsif($Info=~/\A([^\s]+):\s+([^\s]+)\s+(.+?)\s+\((\w+)\s+([^,]+).*?\)/) { my $BusNum = $1; $PciCtlInfo{$BusNum} = {"Vendor"=>$2, "Device"=>$3, "SubType"=>$4, "Type"=>$5}; my $ShortBus = $BusNum; $ShortBus=~s/0+(\d:)/$1/g; if(my $DevFile = $PciNumDev{$ShortBus}) { $PciCtlInfo{$BusNum}{"File"} = $DevFile; } } } my $PciCtl_n = ""; if($Opt{"FixProbe"}) { $PciCtl_n = readFile($FixProbe_Logs."/pcictl_n"); } elsif(enabledLog("pcictl_n") and checkCmd("pcictl")) { listProbe("logs", "pcictl_n"); $PciCtl_n = runCmd("pcictl pci0 list -Nn 2>/dev/null"); if(not $PciCtl_n) { # NetBSD 7.2 $PciCtl_n = runCmd("pcictl pci0 list -n 2>/dev/null"); } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/pcictl_n", $PciCtl_n); } } foreach my $Info (split(/\n/, $PciCtl_n)) { my ($V, $D, $SV, $SD) = (); my %Device = (); if($Info=~/\A([^\s]+):\s*0x([a-f\d]{4})([a-f\d]{4})\s+\(0x([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})\)/) { if(defined $PciCtlInfo{$1}) { %Device = %{$PciCtlInfo{$1}}; $Device{"Driver"} = $Device{"File"}; $Device{"Driver"}=~s/\d+\Z//; } ($V, $D) = ($3, $2); $Device{"Class"} = devID(($4, $5, $6)); } if($Device{"Class"}) { $Device{"Type"} = getClassType("pci", $Device{"Class"}); } my $ID = devID(($V, $D, $SV, $SD)); my $BusID = "pci:".$ID; foreach my $Attr (keys(%Device)) { $HW{$BusID}{$Attr} = $Device{$Attr}; } countDevice($BusID, $Device{"Type"}); } my $PciDump = ""; if($Opt{"FixProbe"}) { $PciDump = readFile($FixProbe_Logs."/pcidump"); } elsif(enabledLog("pcidump") and checkCmd("pcidump")) { listProbe("logs", "pcidump"); $PciDump = runCmd("pcidump -v 2>/dev/null"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/pcidump", $PciDump); } } $PciDump=~s/\n( \w)/\n\n$1/g; foreach my $Info (split(/\n\n/, $PciDump)) { my ($V, $D, $SV, $SD) = (); my %Device = (); my $BusNum = undef; if($Info=~/\A\s*([\d\:]+?):\s+([^\s]+)\s*(.+?)\n/) { ($Device{"Vendor"}, $Device{"Device"}) = ($2, $3); $BusNum = $1; } if($Info=~/Vendor ID:\s*([a-f\d]{4})/) { $V = $1; } if($Info=~/Product ID:\s*([a-f\d]{4})/) { $D = $1; } if($Info=~/Subsystem Vendor ID:\s*([a-f\d]{4}).+?Product ID:\s*([a-f\d]{4})/) { if($1 ne "0000" or $2 ne "0000") { ($SV, $SD) = ($1, $2); } } my @Class = (); if($Info=~/Class:\s*([a-f\d]{2})/) { push(@Class, $1); } if($Info=~/Subclass:\s*([a-f\d]{2})/) { push(@Class, $1); } if($Info=~/Interface:\s*([a-f\d]{2})/) { push(@Class, $1); } if(@Class) { $Device{"Class"} = devID(@Class); } if($Info=~/Class:\s*[a-f\d]{2}\s+(.+?),/) { $Device{"Type"} = lc($1); } if($Info=~/Subclass:\s*[a-f\d]{2}\s+(.+?),/) { $Device{"SubType"} = $1; } if($Device{"Class"}) { $Device{"Type"} = getClassType("pci", $Device{"Class"}); } if(my $DevFile = $PciNumDev{$BusNum}) { $Device{"File"} = $DevFile; $Device{"Driver"} = $DevFile; $Device{"Driver"}=~s/\d+\Z//; } my $ID = devID(($V, $D, $SV, $SD)); my $BusID = "pci:".$ID; foreach my $Attr (keys(%Device)) { $HW{$BusID}{$Attr} = $Device{$Attr}; } countDevice($BusID, $Device{"Type"}); } my $PciConf = ""; if($Opt{"FixProbe"}) { $PciConf = readFile($FixProbe_Logs."/pciconf"); } elsif(enabledLog("pciconf") and checkCmd("pciconf")) { listProbe("logs", "pciconf"); $PciConf = runCmd("pciconf -l -bcv 2>/dev/null"); # -BbcevV ? $PciConf=~s/\n(\w)/\n\n$1/g; if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/pciconf", $PciConf); } } foreach my $Info (split(/\n\n/, $PciConf)) { my ($V, $D, $SV, $SD) = (); my %Device = (); if($Info=~/chip=0x([a-f\d]{4})([a-f\d]{4})/) { ($D, $V) = ($1, $2); } if($Info=~/card=0x([a-f\d]{4})([a-f\d]{4})/) { if($1 ne "0000") { ($SD, $SV) = ($1, $2); } } if($Info=~/vendor=0x([a-f\d]{4})/) { # FreeBSD 13 $V = $1; } if($Info=~/device=0x([a-f\d]{4})/) { # FreeBSD 13 $D = $1; } if($Info=~/subvendor=0x([a-f\d]{4})/) { # FreeBSD 13 $SV = $1; } if($Info=~/subdevice=0x([a-f\d]{4})/) { # FreeBSD 13 $SD = $1; } if($SD eq "0000") { ($SV, $SD) = (); } if(not $D or not $V) { next; } if($Info=~/class=0x([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/) { $Device{"Class"} = devID(($1, $2, $3)); } if($Info=~/(.+)\@/) { $Device{"Driver"} = $1; $Device{"File"} = $1; $Device{"Files"}{$1} = 1; $Device{"Driver"}=~s/\d+\Z//; if($Device{"Driver"} eq "none") { $Device{"Driver"} = undef; } if($Device{"File"}=~/vgapci/) { $Device{"Driver"} = identifyVideoDriver_BSD($Device{"Driver"}, $Device{"File"}); } } if($Info=~/vendor\s+=\s+'(.+)'/) { $Device{"Vendor"} = $1; } if($Info=~/device\s+=\s+'(.+)'/) { $Device{"Device"} = $1; } if($Info=~/\sclass\s+=\s+(.+)/) { $Device{"Type"} = $1; if($Info=~/subclass\s+=\s+(.+)/) { $Device{"SubType"} = $1; } } if($Device{"Class"}) { $Device{"Type"} = getClassType("pci", $Device{"Class"}); } my $ID = devID(($V, $D, $SV, $SD)); my $BusID = "pci:".$ID; foreach my $Attr (keys(%Device)) { if(ref($HW{$BusID}{$Attr}) eq "HASH" and ref($Device{$Attr}) eq "HASH") { foreach my $SubAttr (keys(%{$Device{$Attr}})) { $HW{$BusID}{$Attr}{$SubAttr} = $Device{$Attr}{$SubAttr}; } } else { $HW{$BusID}{$Attr} = $Device{$Attr}; } } countDevice($BusID, $Device{"Type"}); } if(not $PciConf and not $PciCtl and not $PciDump and $DevInfo) { # NOTE: securelevel=2 foreach my $Line (split(/\n/, $DevInfo)) { if($Line=~/\A\s*(\w+\d+)\s+pnpinfo\s+vendor=0x([a-f\d]{4})\s+device=0x([a-f\d]{4})\s+subvendor=0x([a-f\d]{4})\s+subdevice=0x([a-f\d]{4})\s+class=0x([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})/) { my ($DevFile, $V, $D, $SV, $SD, $C1, $C2, $C3) = ($1, $2, $3, $4, $5, $6, $7, $8); my %Device = (); $Device{"File"} = $DevFile; $Device{"Files"}{$DevFile} = 1; $Device{"Driver"} = $DevFile; $Device{"Driver"}=~s/\d+\Z//; $Device{"Class"} = devID(($C1, $C2, $C3)); $Device{"Type"} = getClassType("pci", $Device{"Class"}); my $ID = devID(($V, $D, $SV, $SD)); my $BusID = "pci:".$ID; $HW{$BusID} = \%Device; countDevice($BusID, $Device{"Type"}); } elsif($Line=~/\A\s*(\w+\d+)\s+pnpinfo\s+vendor=0x([a-f\d]{4})\s+product=0x([a-f\d]{4})\s+devclass=0x([a-f\d]{2})\s+devsubclass=0x([a-f\d]{2})\s+devproto=0x([a-f\d]{2})/) { my ($DevFile, $V, $D, $C1, $C2, $C3) = ($1, $2, $3, $4, $5, $6); my %Device = (); $Device{"File"} = $DevFile; $Device{"Files"}{$DevFile} = 1; $Device{"Driver"} = $DevFile; $Device{"Driver"}=~s/\d+\Z//; $Device{"Class"} = devID(($C1, $C2, $C3)); $Device{"Type"} = getClassType("usb", $Device{"Class"}); my $ID = devID(($V, $D)); my $BusID = "usb:".$ID; $HW{$BusID} = \%Device; countDevice($BusID, $Device{"Type"}); } } } # USB my $Lsusb = ""; if($Opt{"FixProbe"}) { $Lsusb = readFile($FixProbe_Logs."/lsusb"); } else { if(checkCmd("lsusb")) { listProbe("logs", "lsusb"); my $UsbLink = createIDsLink("usb"); $Lsusb = runCmd("lsusb -v 2>&1"); if($UsbLink) { unlink($UsbLink); } $Lsusb=~s/(iSerial\s+\d+\s*)[^\s]+$/$1.../mg; $Lsusb = encryptUUIDs($Lsusb); if(length($Lsusb)<60 and $Lsusb=~/unable to initialize/i) { $Lsusb = ""; } } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/lsusb", $Lsusb); } } if(isBSD()) { # collect but do not parse $Lsusb = ""; } foreach my $Info (split(/\n\n/, $Lsusb)) { my %Device = (); my ($V, $D, @Class) = (); if($Info=~/idVendor[ ]+0x(\w{4})[ ]+(.*)/) { $V = $1; if($2) { $Device{"Vendor"} = fmtVal($2); } } if($Info=~/idProduct[ ]+0x(\w{4})[ ]+(.*)/) { $D = $1; if($2) { $Device{"Device"} = fmtVal($2); } } if($Info=~/bInterfaceClass\s+(\w+)\s+/) { push(@Class, fNum(sprintf('%x', $1))); } if($Info=~/bInterfaceSubClass\s+(\w+)\s+/) { push(@Class, fNum(sprintf('%x', $1))); } if($Info=~/bInterfaceProtocol\s+(\w+)\s+/) { push(@Class, fNum(sprintf('%x', $1))); } $Device{"Class"} = devID(@Class); if(not $V) { # Couldn't open device next; } if(not $D) { # Couldn't open device next; } my $ID = devID($V, $D); #if(defined $HW{"usb:".$ID}{"Class"}) { # delete($Device{"Class"}); #} my $Vendor = $Device{"Vendor"}; my $OldName = $HW{"usb:".$ID}{"Device"}; my $OldVendor = $HW{"usb:".$ID}{"Vendor"}; if($Device{"Device"}=~/\AFlash (Drive|Disk)\Z/i and $OldName) { $Device{"Device"} = $OldName; } else { if($Device{"Device"}) { $Device{"Device"} .= addCapacity($Device{"Device"}, $HW{"usb:".$ID}{"Capacity"}); } } if($Opt{"UsbIDs"}) { if(not $Device{"Device"}) { if(my $Name = $UsbInfo{$V}{$D}) { if($Vendor) { if($Name ne $Vendor) { $Device{"Device"} = $Name; } } else { if($Name ne $OldVendor) { $Device{"Device"} = $Name; } } } } } my $FinalName = $Device{"Device"}; if(not $FinalName) { $FinalName = $OldName; } if($FinalName!~/root hub/i) { if($Info=~/iProduct[ ]+\w+[ ]+(.+)/) { if(my $SubDevice = fmtVal($1)) { if($FinalName) { my $N1 = $FinalName; my $N2 = $SubDevice; $N2=~s/\AUSB //g; if($N1!~/\Q$N2\E/i and $N2!~/\Q$N1\E/i) { $Device{"SDevice"} = $SubDevice; } } else { $Device{"Device"} = $SubDevice; } } } elsif($OldName) { if($FinalName!~/\Q$OldName\E/i and $OldName!~/\Q$FinalName\E/i) { $Device{"SDevice"} = $OldName; } } if($Info=~/iManufacturer[ ]+\w+[ ]+(.+)/) { if(my $SubVendor = fmtVal($1)) { $SubVendor=~s/\AManufacturer\s+//ig; if($Vendor and $SubVendor!~/usb/i and $SubVendor!~/generic/ and $SubVendor ne $Device{"SDevice"} and $SubVendor ne $FinalName) { $Device{"SVendor"} = $SubVendor; } } } } if(not $HW{"usb:".$ID}{"Type"}) { $Device{"Type"} = getDefaultType("usb", $D, \%Device); if(not $Device{"Type"}) { if($Info=~/Camera Sensor/i) { $Device{"Type"} = "camera"; } elsif($Info=~/Uninterruptible Power Supply/i) { $Device{"Type"} = "ups"; } elsif($Info=~/Card Reader/i) { $Device{"Type"} = "card reader"; } } if(not $Device{"Type"}) { if(@Class) { $Device{"Type"} = getClassType("usb", devID(@Class)); } } } cleanValues(\%Device); foreach my $Attr (keys(%Device)) { if(my $Val = $Device{$Attr}) { $HW{"usb:".$ID}{$Attr} = $Val; } } } my $UsbDevs = ""; if($Opt{"FixProbe"}) { $UsbDevs = readFile($FixProbe_Logs."/usbdevs"); } elsif(enabledLog("usbdevs") and checkCmd("usbdevs")) { listProbe("logs", "usbdevs"); $UsbDevs = runCmd("usbdevs -vv 2>/dev/null"); $UsbDevs=~s/(serial\s+)([^\s]+)/$1.../g; if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/usbdevs", $UsbDevs); } } $UsbDevs=~s/(addr |Controller |\s+port \d+ addr)/\n$1/g; my $UsbController = undef; my @UsbCtrls = (); foreach my $Info (split(/\n\n/, $UsbDevs)) { my ($V, $D) = (); my %Device = (); my $UsbAddr = undef; if($Info=~/Controller (.+):/) { push(@UsbCtrls, $1); $UsbController = basename($1); next; } if($Info=~/addr\s+(\d+):.*?,\s*([^,]+?)\(0x([a-f\d]{4})\),\s*([^()]+?)\(0x([a-f\d]{4})\)/i) { # NetBSD, FreeBSD < 8.0, OpenBSD < 6.3 ($V, $D) = ($5, $3); $Device{"Vendor"} = $4; $Device{"Device"} = $2; $UsbAddr = $1; if($Info=~/ ([^,]+)\(0x([a-f\d]{2})\),\s*([^,]+?)\(0x([a-f\d]{2})\)/i) { $Device{"BSDType"} = lc($1); $Device{"SubType"} = lc($3); $Device{"Class"} = devID(($2, $4)); if($Device{"BSDType"}=~/vendor specific/) { $Device{"BSDType"} = undef; } } } elsif($Info=~/addr\s+\d+:\s*([a-f\d]{4}):([a-f\d]{4})\s+([^,]+),\s*(.+)/i) { # OpenBSD ($V, $D) = ($1, $2); $Device{"Vendor"} = $3; $Device{"Device"} = $4; } my @Drs = ($Info=~/driver:\s*([^\s]+)/g); foreach (@Drs) { $Device{"File"} = $_; $Device{"Driver"} = $_; $Device{"Driver"}=~s/\d+\Z//; } if(not $V and not $D) { next; } if($Device{"Vendor"} eq "vendor $V") { $Device{"Vendor"} = undef; } ($V, $D) = fixRootHub($V, $D, \%Device); $Device{"Type"} = getDefaultType("usb", $D, \%Device); if(not $Device{"Type"} and $Device{"Class"} and $Device{"Class"}!~/\Af[fe]/) { $Device{"Type"} = getClassType("usb", $Device{"Class"}); } if(not $Device{"Type"}) { $Device{"Type"} = $Device{"BSDType"}; } if(not $Device{"File"}) { # NetBSD, FreeBSD < 8.0, OpenBSD < 6.3 my $DevFile = undef; if(defined $UsbAddrDev{$UsbController} and defined $UsbAddrDev{$UsbController}{$UsbAddr}) { $DevFile = $UsbAddrDev{$UsbController}{$UsbAddr}; } if(not $DevFile) { LOOP: foreach my $SDev (keys(%{$DevAttached_R{$UsbController}})) { if(defined $UsbAddrDev{$SDev}{$UsbAddr}) { $DevFile = $UsbAddrDev{$SDev}{$UsbAddr}; last; } foreach my $SSDev (keys(%{$DevAttached_R{$SDev}})) { if(defined $UsbAddrDev{$SSDev}{$UsbAddr}) { $DevFile = $UsbAddrDev{$SSDev}{$UsbAddr}; last LOOP; } foreach my $SSSDev (keys(%{$DevAttached_R{$SSDev}})) { if(defined $UsbAddrDev{$SSSDev}{$UsbAddr}) { $DevFile = $UsbAddrDev{$SSSDev}{$UsbAddr}; last LOOP; } foreach my $SSSSDev (keys(%{$DevAttached_R{$SSSDev}})) { if(defined $UsbAddrDev{$SSSSDev}{$UsbAddr}) { $DevFile = $UsbAddrDev{$SSSSDev}{$UsbAddr}; last LOOP; } } } } } } if($DevFile) { $Device{"File"} = $DevFile; $Device{"Driver"} = $DevFile; $Device{"Driver"}=~s/\d+\Z//; } } if(not $Device{"Class"}) { # FreeBSD < 8.0 if(defined $UsbAddrClass{$UsbController} and defined $UsbAddrClass{$UsbController}{$UsbAddr}) { $Device{"Class"} = $UsbAddrClass{$UsbController}{$UsbAddr}; $Device{"Type"} = getClassType("usb", $Device{"Class"}); } } my $ID = devID(($V, $D)); my $BusID = "usb:".$ID; foreach my $Attr (keys(%Device)) { $HW{$BusID}{$Attr} = $Device{$Attr}; } countDevice($BusID, $Device{"Type"}); } my $UsbCtl = ""; if($Opt{"FixProbe"}) { $UsbCtl = readFile($FixProbe_Logs."/usbctl"); } elsif(enabledLog("usbctl") and checkCmd("usbctl")) { listProbe("logs", "usbctl"); foreach (@UsbCtrls) { $UsbCtl .= runCmd("usbctl -f $_ 2>/dev/null")."\n"; } $UsbCtl=~s/(iSerialNumber=)([^\s]+)/$1.../g; if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/usbctl", $UsbCtl); } } if(not (isOpenBSD() or $FreeBSD7 or isNetBSD())) { $UsbCtl = ""; } $UsbCtl=~s/(-----\n)(\w)/$1\n$2/g; $UsbCtl=~s/(\nDEVICE addr )/\n$1/g; foreach my $Info (split(/-----|\n\n\n/, $UsbCtl)) { # detect USB class on OpenBSD if($Info=~/idVendor=0x([a-f\d]{4})\s+idProduct=0x([a-f\d]{4})/) { my ($V, $D) = ($1, $2); my ($C1, $C2, $C3) = (); if($Info=~/bDeviceClass=([^\s+]+)\s+bDeviceSubClass=([^\s+]+)/) { ($C1, $C2) = ($1, $2); if($Info=~/bDeviceProtocol=([^\s+]+)/) { $C3 = $1; } } if($Info=~/bInterfaceClass=([^\s+]+)\s+bInterfaceSubClass=([^\s+]+)/) { ($C1, $C2) = ($1, $2); if($Info=~/bInterfaceProtocol=([^\s+]+)/) { $C3 = $1; } } my %Device = (); if($Info=~/iProduct=.*?\(([^()]+?)\)/) { $Device{"Device"} = $1; } ($V, $D) = fixRootHub($V, $D, \%Device); my $BusId = "usb:".devID(($V, $D)); my $Class = devID((fNum(sprintf('%x', $C1)), fNum(sprintf('%x', $C2)), fNum(sprintf('%x', $C3)))); if($Class eq "03-01-01") { if(defined $DevAttached_R{$HW{$BusId}{"File"}}{"ums0"}) { $Class = "03-01-02" } } my $OldClass = $HW{$BusId}{"Class"}; $HW{$BusId}{"Class"} = $Class; if((not $HW{$BusId}{"Type"} or $OldClass ne $Class) and $Class!~/\Af[fe]/) { $HW{$BusId}{"Type"} = getDefaultType("usb", $D, $HW{$BusId}); if(not $HW{$BusId}{"Type"}) { $HW{$BusId}{"Type"} = getClassType("usb", $Class); } } } } my $UsbConf = ""; if($Opt{"FixProbe"}) { $UsbConf = readFile($FixProbe_Logs."/usbconfig"); } elsif(enabledLog("usbconfig") and checkCmd("usbconfig")) { listProbe("logs", "usbconfig"); $UsbConf = runCmd("usbconfig dump_device_desc show_ifdrv dump_all_config_desc 2>/dev/null"); $UsbConf = hideTags($UsbConf, "iSerialNumber"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/usbconfig", $UsbConf); } } my @UsbConfBlocks = (); if($UsbConf=~/Configuration index/) { $UsbConf=~s/\n(\n\n\n[ ]+Interface \d)/$1/g; @UsbConfBlocks = split(/\n\n\n(\n)+/, $UsbConf); } else { # Support for old probes $UsbConf=~s/(\n\w)/\n$1/g; @UsbConfBlocks = split(/\n\n\n/, $UsbConf); } foreach my $Info (@UsbConfBlocks) { my ($V, $D) = (); my %Device = (); if($Info=~/idVendor\s*=\s*0x([a-f\d]{4})/) { $V = $1; } if($Info=~/idProduct\s*=\s*0x([a-f\d]{4})/) { $D = $1; } if(not $V and not $D) { next; } if($Info=~/iManufacturer\s*=.*<(.+)>/) { $Device{"Vendor"} = $1; } if($Info=~/iProduct\s*=.*<(.+)>/) { $Device{"Device"} = $1; } if($Info=~/:\s+((\w+?)\d+):\s+/) { $Device{"File"} = $1; $Device{"Driver"} = $2; } if($Info=~/bDeviceClass\s*=.*<(.+)>/) { $Device{"BSDType"} = lc($1); if($Device{"BSDType"}=~/probed by (.+) class|vendor specific/) { $Device{"BSDType"} = undef; } } my ($C1, $C2, $C3) = (); if($Info=~/bDeviceClass\s*=\s*0x0*([a-f\d]{2})/) { $C1 = $1; } if($Info=~/bDeviceSubClass\s*=\s*0x0*([a-f\d]{2})/) { $C2 = $1; } if($Info=~/bDeviceProtocol\s*=\s*0x0*([a-f\d]{2})/) { $C3 = $1; } if($Info=~/bInterfaceClass\s*=\s*0x0*([a-f\d]{2})/) { $C1 = $1; } if($Info=~/bInterfaceSubClass\s*=\s*0x0*([a-f\d]{2})/) { $C2 = $1; } if($Info=~/bInterfaceProtocol\s*=\s*0x0*([a-f\d]{2})/) { $C3 = $1; } cleanValues(\%Device); ($V, $D) = fixRootHub($V, $D, \%Device); $Device{"Class"} = devID(($C1, $C2, $C3)); if($Device{"Class"}=~/\Af[fe]/ and my $ExtName = $UsbInfo{$V}{$D}) { $Device{"Device"} = $ExtName; } elsif(not $Device{"BSDType"}) { if(my @Details = $Info=~/iInterface\s*=\s*.*?<(.+)>/g) { @Details = grep {$_!~/no string|Bulk|Interface/} @Details; if(@Details) { $Device{"Device"} = join(" ", $Device{"Device"}, @Details); } } } $Device{"Type"} = getDefaultType("usb", $D, \%Device); if(not $Device{"Type"} and $Device{"Class"} and $Device{"Class"}!~/\Af[fe]/) { $Device{"Type"} = getClassType("usb", $Device{"Class"}); } if(not $Device{"Type"}) { $Device{"Type"} = $Device{"BSDType"}; } my $ID = devID(($V, $D)); my $BusID = "usb:".$ID; foreach my $Attr (keys(%Device)) { $HW{$BusID}{$Attr} = $Device{$Attr}; } countDevice($BusID, $Device{"Type"}); } my $Usb_devices = ""; if($Opt{"FixProbe"}) { $Usb_devices = readFile($FixProbe_Logs."/usb-devices"); } elsif(enabledLog("usb-devices")) { if(checkCmd("usb-devices")) { listProbe("logs", "usb-devices"); $Usb_devices = runCmd("usb-devices -v 2>&1"); $Usb_devices = encryptSerials($Usb_devices, "SerialNumber", "usb-devices"); } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/usb-devices", $Usb_devices); } } foreach my $Info (split(/\n\n/, $Usb_devices)) { my ($V, $D) = (); if($Info=~/Vendor=([^ ]+)/) { $V = $1; } if($Info=~/ProdID=([^ ]+)/) { $D = $1; } my %Driver = (); while($Info=~s/Driver=([\w\-]+)//) { my $Dr = $1; $Dr=~s/\-/_/g; if(not defined $Driver{$Dr}) { $Driver{$Dr} = keys(%Driver); } } if($V and $D) { my $ID = devID($V, $D); if(defined $HW{"usb:".$ID} and not defined $HW{"usb:".$ID}{"Driver"}) { if(my @Dr = keys(%Driver)) { @Dr = sort {$Driver{$a} <=> $Driver{$b}} @Dr; $HW{"usb:".$ID}{"Driver"} = join(", ", @Dr); } } } } # Fix incorrectly detected drivers foreach my $ID (sort keys(%HW)) { my $Driver = $HW{$ID}{"Driver"}; if(not $Driver) { next; } my %Drivers = (); my $Num = 0; foreach my $Dr (split(/\,\s+/, $Driver)) { $Drivers{$Dr} = $Num++; } if(defined $Drivers{"nouveau"}) { if(defined $WorkMod{"nvidia"}) { delete($Drivers{"nouveau"}); $Drivers{"nvidia"} = 1; } } if(defined $Drivers{"nvidia"} and defined $WorkMod{"nvidia"}) { foreach ("nvidiafb", "nvidia_drm") { if(defined $Drivers{$_}) { delete($Drivers{$_}); } } } if(defined $Drivers{"radeon"}) { if(defined $Drivers{"amdgpu"} and defined $WorkMod{"amdgpu"}) { delete($Drivers{"radeon"}); } } foreach my $Dr (@G_DRIVERS) { if(defined $Drivers{$Dr}) { if(defined $KernMod{$Dr} and not defined $WorkMod{$Dr}) { delete($Drivers{$Dr}); } } } foreach my $Dr (sort keys(%Drivers)) { if($Dr eq "nvidiafb") { if(defined $KernMod{$Dr} and not defined $WorkMod{$Dr}) { delete($Drivers{$Dr}); } } elsif($Dr=~/\Anvidia/) { # nvidia346, nvidia_375, etc. if(defined $KernMod{$Dr} and not defined $WorkMod{"nvidia"}) { delete($Drivers{$Dr}); } } } if($Driver ne "wl" and defined $Drivers{"wl"}) { if(not defined $WorkMod{"wl"}) { delete($Drivers{"wl"}); } } $HW{$ID}{"Driver"} = join(", ", sort {$Drivers{$a}<=>$Drivers{$b}} keys(%Drivers)); } # Fix incorrectly detected types foreach my $ID (sort keys(%HW)) { my $Type = $HW{$ID}{"Type"}; my $Type_New = undef; if($Type eq "cdrom" or $Type eq "serial controller") { my $Device = $HW{$ID}{"Device"}; my $SDevice = $HW{$ID}{"SDevice"}; my $Vendor = $HW{$ID}{"Vendor"}; if($Vendor=~/Huawei/i and ($Device=~/modem|mobile|broadband/i or $SDevice=~/modem|mobile|broadband/i)) { $Type_New = "modem"; } } if(defined $Type_New) { $HW{$ID}{"Type"} = $Type_New; } } # Fix status of graphics cards, network devices, etc. my $PCIDrivers = 0; foreach my $ID (sort keys(%HW)) { if($HW{$ID}{"Driver"} and $ID=~/\Apci/) { $PCIDrivers = 1; last; } } my $BSD = isBSD(); foreach my $ID (sort keys(%HW)) { my $DevType = $HW{$ID}{"Type"}; my $Dr = $HW{$ID}{"Driver"}; my $Class = $HW{$ID}{"Class"}; my $Count = getDeviceCount($ID); if(not $Count) { $Count = 1; } if($BSD) { if($DevType eq "network") { if($ID=~/pci:/) { if($Sys{"NICs"}) { $Sys{"NICs"} += $Count; } else { $Sys{"NICs"} = $Count; } } } elsif($DevType=~/camera|video/) { # user-space drivers next; } } if($DevType eq "graphics card") { if($ID=~/\w+:(.+?)\-/) { $GraphicsCards{$1}{$ID} = $Dr; $GraphicsCards_All{$ID} = $Dr; if($Dr) { $GraphicsCards_InUse{$ID} = $Dr; } } } elsif(grep { $DevType eq $_ } ("bluetooth", "camera", "card reader", "chipcard", "communication controller", "dvb card", "fingerprint reader", "smartcard reader", "firewire controller", "flash memory", "modem", "multimedia controller", "network", "sd host controller", "sound", "storage", "system peripheral", "tv card", "video", "wireless", "unclassified device", "unassigned class", "vendor specific", "wireless controller") or not $DevType) { if(grep { $DevType eq $_ } ("sd host controller", "system peripheral") and $HW{$ID}{"Vendor"}=~/Intel/) { next; } if(grep { $DevType eq $_ } ("unclassified device", "unassigned class") and $HW{$ID}{"Device"}=~/ MROM /) { next; } if(grep { $Class eq $_ } ("06-04-01")) { next; } if($ID=~/\A(usb|pci|ide|sdio):/) { if($1 ne "pci" or $PCIDrivers) { if(not $HW{$ID}{"Driver"}) { $HW{$ID}{"Status"} = "failed"; } if($DevType eq "network") { my @Files = ($HW{$ID}{"File"}); if(defined $HW{$ID}{"Files"}) { push(@Files, keys(%{$HW{$ID}{"Files"}})); } foreach my $File (@Files) { if($HW{$ID}{"Driver"}) { if(defined $UsedNetworkDev{$File} or (keys(%UsedNetworkDev)==1 and length(grep {$HW{$_}{"Type"} eq "network"} keys(%HW))==1)) { $HW{$ID}{"Status"} = "works"; $HW{$ID}{"Link detected"} = "yes"; } } if($EthernetInterface{$File} or $HW{$ID}{"Device"}=~/Ethernet/i) { $HW{$ID}{"Kind"} = "Ethernet"; } elsif($WLanInterface{$File} or $HW{$ID}{"Device"}=~/802\.11|Wireless|Wi-?Fi/i) { $HW{$ID}{"Kind"} = "WiFi"; } elsif($HW{$ID}{"Device"}=~/broadband/i) { $HW{$ID}{"Kind"} = "Modem"; } if($HW{$ID}{"Class"}=~/\A02-80/ or $HW{$ID}{"Device"}=~/Wireless/ or $File=~/\A(ath|iwn)/) { if($File=~s/\A[^\d]+/wlan/) { if($HW{$ID}{"Driver"}) { if(defined $UsedNetworkDev{$File} or (keys(%UsedNetworkDev)==1 and length(grep {$HW{$_}{"Type"} eq "network"} keys(%HW))==1)) { $HW{$ID}{"Status"} = "works"; $HW{$ID}{"Link detected"} = "yes"; } } if($EthernetInterface{$File}) { $HW{$ID}{"Kind"} = "Ethernet"; } elsif($WLanInterface{$File}) { $HW{$ID}{"Kind"} = "WiFi"; } } } } } } } if($HW{$ID}{"Status"} eq "works") { setAttachedStatus($ID, "works"); } } } foreach my $V (sort keys(%GraphicsCards)) { foreach my $ID (sort keys(%{$GraphicsCards{$V}})) { if(index($HW{$ID}{"Device"}, "Secondary")!=-1) { next; } if($HW{$ID}{"Class"} eq "03-80" and keys(%{$GraphicsCards{$V}})>=2) { next; } if(not $GraphicsCards{$V}{$ID} and ($Sys{"Type"}!~/$MOBILE_TYPE/ or keys(%GraphicsCards_All)>=3)) { # not a hybrid graphics # or external full-size PCI card attached to the notebook if(grep { $GraphicsCards_All{$_} } keys(%GraphicsCards_All)) { # some of them are connected next; } } if(grep {$V eq $_} ("1002", "8086")) { if(not $GraphicsCards{$V}{$ID}) { $HW{$ID}{"Status"} = "failed"; } } elsif($V eq "10de") { if(not defined $GraphicsCards{"8086"}) { if(not $GraphicsCards{$V}{$ID}) { $HW{$ID}{"Status"} = "failed"; } } } } } # DMI my $Dmidecode = ""; if($Opt{"FixProbe"}) { $Dmidecode = readFile($FixProbe_Logs."/dmidecode"); } else { if(checkCmd("dmidecode")) { listProbe("logs", "dmidecode"); $Dmidecode = runCmd("dmidecode 2>&1"); $Dmidecode = encryptSerials($Dmidecode, "UUID"); $Dmidecode = encryptSerials($Dmidecode, "Serial Number"); $Dmidecode = encryptSerials($Dmidecode, "Asset Tag"); if(not $Dmidecode and isOpenBSD()) { printMsg("WARNING", "failed to run dmidecode"); } } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/dmidecode", $Dmidecode); } } my $MemIndex = 0; my %MemIDs = (); my ($CPU_Sockets, $CPU_Cores, $CPU_Threads, $CPU_Family, $CPU_ModelNum, $CPU_Family_Name) = (0, 0, 0, undef, undef, undef); foreach my $Info (split(/\n\n/, $Dmidecode)) { my %Device = (); my $D = ""; my $ID = ""; $Info=~s/[ ]{2,}/ /g; if($Info=~/Chassis Information\n/) { # notebook or desktop if($Info=~/Type:[ ]*(.+?)[ ]*(\n|\Z)/) { if(my $CType = getChassisType($1)) { $Sys{"Type"} = $CType; } } } elsif($Info=~/System Information\n/) { if($Info=~/Manufacturer:[ ]*(.+?)[ ]*(\n|\Z)/) { $Sys{"Vendor"} = fmtVal($1); } if($Info=~/Product Name:[ ]*(.+?)[ ]*(\n|\Z)/) { $Sys{"Model"} = $1; } if($Info=~/Version:[ ]*(.+?)[ ]*(\n|\Z)/) { $Sys{"Version"} = $1; } if($Info=~/SKU Number:[ ]*(.+?)[ ]*(\n|\Z)/) { $Sys{"Sku_number"} = $1; } # clear if(emptyProduct($Sys{"Vendor"})) { $Sys{"Vendor"} = ""; } if(emptyProduct($Sys{"Model"})) { $Sys{"Model"} = ""; } if(emptyProduct($Sys{"Version"})) { $Sys{"Version"} = ""; } ($Sys{"Vendor"}, $Sys{"Model"}) = fixVendorModel($Sys{"Vendor"}, $Sys{"Model"}); $Sys{"Model"} = fixModel($Sys{"Vendor"}, $Sys{"Model"}, $Sys{"Version"}); } elsif($Info=~/Memory Device\n/) # $Info=~/Memory Module Information\n/ { while($Info=~s/([\w ]+):[ \t]*(.+?)[ \t]*(\n|\Z)//) { my ($Key, $Val) = ($1, fmtVal($2)); if(grep { lc($Val) eq $_ } ("unknown", "other")) { next; } if(grep { $Val=~/$_/i } ("OUT OF SPEC", "NOT AVAILABLE")) { next; } if($Key eq "Manufacturer") { $Device{"Vendor"} = nameID($Val, "memory"); } elsif($Key eq "Part Number") { $Device{"Device"} = $Val; } elsif($Key eq "Serial Number") { $Device{"Serial"} = $Val; } elsif($Key eq "Type") { if($Val eq "Reserved") { next; } if(my $FF = $Device{"FF"}) { $Val=~s/ \Q$FF\E\Z//; } $Device{"Kind"} = $Val; } elsif($Key eq "Size") { $Device{"Size"} = $Val; } elsif($Key eq "Speed") { $Device{"Speed"} = $Val; } # Memory Module elsif($Key eq "Installed Size") { $Device{"Size"} = $Val; } elsif($Key eq "Current Speed") { $Device{"Speed"} = $Val; } elsif($Key eq "Form Factor") { $Device{"FF"} = $Val; } elsif($Key eq "Locator" and not $Device{"FF"}) { if($Val=~/\ADIMM/) { $Device{"FF"} = "DIMM"; } } } cleanValues(\%Device); if($Device{"Size"} eq "No Module Installed") { next; } if($Device{"Size"} eq "Not Installed") { next; } if(grep { $Device{"FF"} eq $_ } ("TSOP") # Chip or $Device{"Kind"} eq "Flash") { # TODO: add this kind of devices next; } if($Device{"FF"} eq "DIMM" and $Sys{"Type"}=~/$MOBILE_TYPE/) { $Device{"FF"} = "SODIMM"; } $Device{"Type"} = "memory"; $Device{"Status"} = "works"; my $Inc = 0; if($Device{"Vendor"}) { if($Device{"Vendor"}=~/\A(JEDEC|Unknown) ID:(.+)/) { $Device{"Vendor"} = $2; $Device{"Vendor"}=~s/ //g; } elsif($Device{"Vendor"}=~/\AUnknown - \[0x(.+)\]/) { $Device{"Vendor"} = $1; } elsif($Device{"Vendor"}=~/\AUnknown \((.+)\)/) { $Device{"Vendor"} = $1; } if(defined $JedecVendor{$Device{"Vendor"}} or defined $JedecVendor{uc($Device{"Vendor"})}) { $Device{"Vendor"} = $JedecVendor{$Device{"Vendor"}}; } elsif($Device{"Vendor"}=~/\A0x(.+)\Z/ and defined $JedecVendor{$1}) { $Device{"Vendor"} = $JedecVendor{$1}; } elsif($Device{"Vendor"}=~/\A(0x|)([A-F\d]{4})/i and defined $JedecVendor{$2}) { $Device{"Vendor"} = $JedecVendor{$2}; } } if(not $Device{"Vendor"} or isUnknownRam($Device{"Vendor"}) or isJedecRam($Device{"Vendor"})) { if(my $GuessVendor = guessRamVendor($Device{"Device"})) { $Device{"Vendor"} = $GuessVendor; } } if(not $Device{"Vendor"} or isUnknownRam($Device{"Vendor"}) or isJedecRam($Device{"Vendor"})) { if(defined $RamVendor{$Device{"Device"}}) { $Device{"Vendor"} = $RamVendor{$Device{"Device"}}; } } if(not $Device{"Vendor"}) { $Device{"Vendor"} = "Manufacturer".$MemIndex; $Inc = 1; } if(not $Device{"Device"}) { $Device{"Device"} = "Partnum".$MemIndex; $Inc = 1; } if(not $Device{"Serial"}) { $Device{"Serial"} = "Sernum".$MemIndex; $Inc = 1; } $Device{"Size"}=~s/ //g; $Device{"Speed"}=~s/ (MHz|MT\/s)//; if($Inc) { $MemIndex++; } if(isUnknownRam($Device{"Vendor"})) { $Device{"Vendor"} = undef; } $Device{"Device"} = duplVendor($Device{"Vendor"}, $Device{"Device"}); if($Device{"Device"}=~/\A(\s*)\Z/ or $Device{"Device"}=~/\A(SODIMM)\d+\Z/i or $Device{"Device"}=~/\AArray\d+_(Part)Number\d+\Z/i or $Device{"Device"}=~/\A(Part)Num\d+\Z/i or $Device{"Device"}=~/\A(0x)[\dA-F]+\Z/i or $Device{"Device"}=~/\A(0)0+\Z/i or $Device{"Device"}=~/Module(Part)Number/i or $Device{"Device"}=~/NOT AVAILABLE/i) { $Device{"Device"} = $1; if(not $Device{"Device"} or grep { lc($Device{"Device"}) eq $_ } ("part", "0x", "0", "sodimm")) { $Device{"Device"} = "RAM Module"; } $ID = devID(nameID($Device{"Vendor"}), $Device{"Device"}); if($Device{"Size"} or $Device{"Kind"} or $Device{"Speed"}) { $ID = devID($ID, $Device{"Size"}, $Device{"Kind"}, $Device{"Speed"}, $Device{"FF"}); } if($Device{"Serial"}) { $ID = devID($ID, "serial", $Device{"Serial"}); } } else { $ID = devID(nameID($Device{"Vendor"}), devSuffix(\%Device)); $Device{"Device"} = "RAM ".$Device{"Device"}; } $ID = fmtID($ID); if(defined $MemIDs{$ID}) { # ERROR: the same ID of RAM memory module $ID .= "-".keys(%MemIDs); } $MemIDs{$ID} = 1; my @Add = (); if(my $Size = $Device{"Size"}) { $Size=~s/ //g; $Size=~s/\(.+\)//g; push(@Add, $Size); } if(my $FF = $Device{"FF"}) { push(@Add, $FF); } if(my $Kind = $Device{"Kind"}) { push(@Add, $Kind); } if(my $Speed = $Device{"Speed"}) { $Speed=~s/ //g; push(@Add, $Speed."MT/s"); } if(@Add) { # additionals $Device{"Device"} .= " ".join(" ", @Add); $Device{"Device"}=~s/\A\s+//g; } if($ID) { $HW{"mem:".$ID} = \%Device; # countDevice("mem:".$ID, "memory"); } } elsif($Info=~/Base Board Information\n/) { while($Info=~s/([\w ]+):[ \t]*(.+?)[ \t]*(\n|\Z)//) { my ($Key, $Val) = ($1, $2); if($Key eq "Manufacturer") { $Device{"Vendor"} = fmtVal($Val); } elsif($Key eq "Product Name") { $Device{"Device"} = fmtVal($Val); } elsif($Key eq "Version") { $Device{"Version"} = $Val; } } if($Board_ID) { delete($HW{$Board_ID}); } $Board_ID = registerBoard(\%Device); } elsif($Info=~/BIOS Information\n/) { while($Info=~s/([\w ]+):[ \t]*(.+?)[ \t]*(\n|\Z)//) { my ($Key, $Val) = ($1, $2); if($Key eq "Vendor") { $Device{$Key} = fmtVal($Val); } elsif($Key eq "Version" or $Key eq "Release Date") { $Device{$Key} = $Val; } } if(not $Bios_ID) { $Bios_ID = registerBIOS(\%Device); } } elsif($Info=~/Processor Information\n/) { while($Info=~s/([\w ]+):[ \t]*(.+?)[ \t]*(\n|\Z)//) { my ($Key, $Val) = ($1, $2); if($Key eq "Manufacturer") { $Device{"Vendor"} = fmtVal($Val); $Device{"Vendor"} = fixCpuVendor($Device{"Vendor"}); } elsif($Key eq "Signature") { # Family 6, Model 42, Stepping 7 my @Model = (); if($Val=~/Family\s+(\w+),/) { push(@Model, $1); $CPU_Family = $1; } if($Val=~/Model\s+(\w+),/) { push(@Model, $1); $CPU_ModelNum = $1; } if($Val=~/Stepping\s+(\w+)/) { push(@Model, $1); } $D = join(".", @Model); } elsif($Key eq "Version") { $Device{"Device"} = fmtVal($Val); } elsif($Key eq "Core Count") { $CPU_Cores += $Val; } elsif($Key eq "Thread Count") { $CPU_Threads += $Val; } elsif($Key eq "Family") { $CPU_Family_Name = $Val; } } if(not $Device{"Vendor"}) { next; } if($Device{"Device"} eq "C1") { next; } $CPU_Sockets += 1; cleanValues(\%Device); $Device{"Device"} = duplVendor($Device{"Vendor"}, $Device{"Device"}); if(not $Device{"Device"} and $CPU_Family_Name) { $Device{"Device"} = $CPU_Family_Name; } $Device{"Type"} = "cpu"; $Device{"Status"} = "works"; if(not $CPU_ID) { $ID = devID(nameID($Device{"Vendor"}), $D, devSuffix(\%Device)); $ID = fmtID($ID); if($ID) { $CPU_ID = "cpu:".$ID; $HW{$CPU_ID} = \%Device; } if($CPU_Threads) { setDevCount($CPU_ID, "cpu", $CPU_Threads); } elsif($CPU_Cores) { setDevCount($CPU_ID, "cpu", $CPU_Cores); } } else { # add info foreach (keys(%Device)) { my $Val1 = $HW{$CPU_ID}{$_}; my $Val2 = $Device{$_}; if($Val2 and not $Val1) { $HW{$CPU_ID}{$_} = $Val2; } } } if(my $Microarch = detectMicroarch($Device{"Vendor"}, $CPU_Family, $CPU_ModelNum, $Device{"Device"})) { $Sys{"Microarch"} = $Microarch; } } } if($CPU_Sockets) { $Sys{"Sockets"} = $CPU_Sockets; } if($CPU_Sockets and $CPU_Cores and $CPU_Threads) { $Sys{"Cores"} = $CPU_Cores; if($CPU_Threads>=$CPU_Cores) { $Sys{"Threads"} = $CPU_Threads/$CPU_Cores; } elsif($CPU_Threads>=$CPU_Sockets) { $Sys{"Threads"} = $CPU_Threads/$CPU_Sockets; } } # fix missed or incorrect computer type from DMI if($CPU_ID) { fixFFByCPU($HW{$CPU_ID}{"Device"}); } foreach (keys(%{$ComponentID{"graphics card"}})) { fixFFByGPU($HW{$_}{"Device"}); } foreach (keys(%{$ComponentID{"cdrom"}})) { fixFFByCDRom($HW{$_}{"Device"}); } foreach (keys(%{$ComponentID{"disk"}})) { fixFFByDisk($HW{$_}{"Device"}); } foreach (keys(%{$ComponentID{"monitor"}})) { fixFFByMonitor($HW{$_}{"Device"}); } foreach (keys(%{$ComponentID{"touchpad"}})) { fixFFByTouchpad($_); } if($Sys{"Vendor"} or $Sys{"Model"}) { fixFFByModel($Sys{"Vendor"}, $Sys{"Model"}); } if($Board_ID) { fixFFByBoard($HW{$Board_ID}{"Device"}); if($Sys{"Type"}=~/$DESKTOP_TYPE|$SERVER_TYPE/ or not $Sys{"Type"}) { my ($MVendor, $MModel) = ($HW{$Board_ID}{"Vendor"}, shortModel($HW{$Board_ID}{"Device"})); if(emptyProduct($MVendor)) { $MVendor = undef; } if(emptyProduct($MModel)) { $MModel = undef; } if($MVendor and $MModel or (not $Sys{"Vendor"} and not $Sys{"Model"})) { $Sys{"Subvendor"} = $Sys{"Vendor"}; $Sys{"Submodel"} = $Sys{"Model"}; $Sys{"Vendor"} = $MVendor; $Sys{"Model"} = $MModel; if($Sys{"Subvendor"} eq $Sys{"Vendor"} and $Sys{"Submodel"} eq $Sys{"Model"}) { delete($Sys{"Subvendor"}); delete($Sys{"Submodel"}); } } if($Sys{"Vendor"}) { ($Sys{"Vendor"}, $Sys{"Model"}) = fixVendorModel($Sys{"Vendor"}, $Sys{"Model"}); $Sys{"Model"} = fixModel($Sys{"Vendor"}, $Sys{"Model"}, undef); } ($Sys{"Subvendor"}, $Sys{"Submodel"}) = fixVendorModel($Sys{"Subvendor"}, $Sys{"Submodel"}); $Sys{"Submodel"} = fixModel($Sys{"Subvendor"}, $Sys{"Submodel"}, undef); } } if($Sys{"Vendor"} or $Sys{"Model"}) { fixFFByModel($Sys{"Vendor"}, $Sys{"Model"}); } if($Sysctl and (not $Sys{"Type"} or $Sys{"Type"} eq "desktop")) { if($Sysctl=~/\.acpibat\d+\./) { $Sys{"Type"} = "notebook"; } else { $Sys{"Type"} = "desktop"; } } if(not $Sys{"Type"}) { if(not keys(%WLanInterface)) { $Sys{"Type"} = "desktop"; } } if($Sysctl and (not $Sys{"Model"} or not $Sys{"Vendor"})) { if($Sysctl=~/hw\.product=(.+)/) { $Sys{"Model"} = $1; } if($Sysctl=~/hw\.vendor=(.+)/) { $Sys{"Vendor"} = $1; } if($Sysctl=~/hw\.version=(.+)/) { $Sys{"Version"} = $1; } $Sys{"Model"} = fixModel($Sys{"Vendor"}, $Sys{"Model"}, $Sys{"Version"}); if(not $Board_ID) { $Board_ID = registerBoard({"Vendor"=>fmtVal($Sys{"Vendor"}), "Device"=>$Sys{"Model"}}); if($Board_ID) { fixFFByBoard($HW{$Board_ID}{"Device"}); } } if($Sys{"Vendor"} or $Sys{"Model"}) { fixFFByModel($Sys{"Vendor"}, $Sys{"Model"}); } } if($Sysctl and not $CDROM_ID) { if($Sysctl=~/dev.acd.0.%desc:\s*(.+)/) { my $CdromDescr = $1; $CdromDescr=~s{/.+}{}; $CDROM_ID = registerCdrom($CdromDescr, "acd0"); } } if($Sysctl=~/hw\.physmem[:=]\s*([^\s]+)/) { $Sys{"Ram_total"} = $1/1024; if($Sysctl=~/Free Memory:\s+(.+)/) { $Sys{"Ram_used"} = $Sys{"Ram_total"} - $1; } registerRAM($Sys{"Ram_total"}); } # Printers my %Pr; my $HP_probe = ""; if($Opt{"FixProbe"}) { $HP_probe = readFile($FixProbe_Logs."/hp-probe"); } elsif($Opt{"Printers"} and enabledLog("hp-probe") and checkCmd("hp-probe")) { listProbe("logs", "hp-probe"); # Net $HP_probe = runCmd("hp-probe -bnet -g 2>&1"); $HP_probe .= "\n"; # Usb $HP_probe .= runCmd("hp-probe -busb -g 2>&1"); $HP_probe = clearLog($HP_probe); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/hp-probe", $HP_probe); } } foreach my $Line (split(/\n/, $HP_probe)) { if($Line=~/Found device/) { my %Device = (); my %Attr = (); while($Line=~s/\'([^']*?)\'\s*:\s*\'([^']*?)\'//) { my ($Key, $Val) = ($1, $2); if($Val=~/MDL:(.*?);/) { $Device{"Device"} = $1; } #if($Val=~/MFG:(.*?);/) { # $Device{"Vendor"} = $1; #} $Attr{$Key} = $Val; } $Pr{$Device{"Device"}} = 1; if(not $Device{"Vendor"}) { if(my $Vnd = guessDeviceVendor($Device{"Device"})) { $Device{"Vendor"} = $Vnd; } } if(my $Vendor = $Device{"Vendor"}) { $Device{"Device"} = duplVendor($Vendor, $Device{"Device"}); $Pr{$Device{"Device"}} = 1; } $Device{"Type"} = "printer"; if($Device{"Device"}=~/(\A| )MFP( |\Z)/) { $Device{"Type"} = "mfp"; } # $Device{"Driver"} = "hplip"; my $ID = devID($Device{"Vendor"}, $Device{"Device"}); $ID = fmtID($ID); # additional info if(my $D = $Attr{"product_id"}) { $Device{"Device"} .= " ".$D; } if($ID) { $HW{"net:".$ID} = \%Device; } } } my $Avahi = ""; if($Opt{"FixProbe"}) { if(-f "$FixProbe_Logs/hp-probe") { # i.e. executed with -printers option (-fix) $Avahi = readFile("$FixProbe_Logs/avahi"); } } elsif($Opt{"Printers"} and enabledLog("avahi") and checkCmd("avahi-browse")) { listProbe("logs", "avahi-browse"); $Avahi = runCmd("avahi-browse -a -t 2>&1 | grep 'PDL Printer'"); if($Opt{"HWLogs"} and $Avahi) { writeLog($LOG_DIR."/avahi", $Avahi); } } foreach my $Line (split(/\n/, $Avahi)) { if($Line=~/IPv\d\s+(.*?)\s+PDL Printer/) { my %Device; $Device{"Device"} = $1; $Device{"Device"}=~s/\s*[\(\[].+[\)\]]//g; if($Pr{$Device{"Device"}}) { # already registered next; } if(not $Device{"Vendor"}) { if(my $Vnd = guessDeviceVendor($Device{"Device"})) { $Device{"Vendor"} = $Vnd; } } if(my $Vendor = $Device{"Vendor"}) { $Device{"Device"} = duplVendor($Vendor, $Device{"Device"}); } $Device{"Type"} = "printer"; if($Device{"Device"}=~/(\A| )MFP( |\Z)/) { $Device{"Type"} = "mfp"; } my $ID = devID($Device{"Vendor"}, $Device{"Device"}); $ID = fmtID($ID); if($ID) { $HW{"net:".$ID} = \%Device; } } } # Monitors my $Edid = ""; if($Opt{"FixProbe"}) { $Edid = readFile($FixProbe_Logs."/edid"); my $XRandrLog = $FixProbe_Logs."/xrandr"; my $XOrgLog = $FixProbe_Logs."/xorg.log"; if($Opt{"FixEdid"} and ($Edid or -s $XRandrLog or -s $XOrgLog)) { my %EdidHex = (); my %FoundEdid = (); if(-s $XRandrLog) { my $RCard = undef; foreach my $L (split(/\n/, readFile($XRandrLog))) { if($L=~/([^\s]+)\s+connected /) { $RCard = $1."/edid"; } elsif($RCard) { if($L=~/\s+(\w{32})\Z/) { $FoundEdid{$RCard} .= $1."\n"; } } } } if(not keys(%FoundEdid) and -s $XOrgLog) { my $XCard = "DEFAULT1"; foreach my $L (split(/\n/, readFile($XOrgLog))) { if($L=~/EDID for output ([\w\-]+)/) { $XCard = $1."/edid"; } elsif($XCard) { if($L=~/\s+(\w{32})\Z/) { $FoundEdid{$XCard} .= $1."\n"; } } } } if(index($Edid, "edid-decode")!=-1) { my %OldEdid = (); foreach my $Block (split(/edid-decode /, $Edid)) { if($Block=~/\A\"(.+?)\"/) { my $Card = $1; if($Card!~/edid/) { $Card .= "/edid"; } if(not $OldEdid{$Card}) { foreach my $L (split(/\n/, $Block)) { if($L=~/([a-f0-9]{32})/) { if(not defined $OldEdid{$Card}) { $OldEdid{$Card} = $1; } else { $OldEdid{$Card} .= " ".$1; } } } } if(not $OldEdid{$Card}) { foreach my $B (split(/\n\n/, $Block)) { if($B=~/serial number:/) { foreach my $L (split(/\n/, $B)) { if($L=~/\A[a-z\d\s]+:\s+([a-f\d\s]+?)\Z/) { if(not defined $OldEdid{$Card}) { $OldEdid{$Card} = $1; } else { $OldEdid{$Card} .= " ".$1; } } } last; } } } } } foreach my $C (keys(%OldEdid)) { if($C!~/\A\//) { # from Xrandr or Xorg next; } my $Hex = $OldEdid{$C}; $Hex=~s/\s//g; $Hex=~s/(\w{32})/$1\n/g; if(grep {$FoundEdid{$_}=~/\A$Hex\w+/} keys(%FoundEdid)) { # extended EDID is available next; } $FoundEdid{$C} = $Hex; } } my $FixedContent = ""; foreach my $C (sort {$b=~/\A\// cmp $a=~/\A\//} sort {lc($a) cmp lc($b)} keys(%FoundEdid)) { my $Hex = $FoundEdid{$C}; if(defined $EdidHex{$Hex}) { next; } $EdidHex{$Hex} = 1; my $Decoded = decodeEdid($Hex); if($Decoded=~/No header found/i) { next; } $FixedContent .= "edid-decode \"$C\":\n"; $FixedContent .= "\nEDID (hex):\n".$Hex."\n"; $FixedContent .= $Decoded; $FixedContent .= "\n\n"; } if($FixedContent) { $Edid = $FixedContent; writeFile($FixProbe_Logs."/edid", $FixedContent); } else { if($Edid) { printMsg("WARNING", "failed to fix EDID"); } else { printMsg("WARNING", "failed to detect EDID"); } } } } elsif(enabledLog("edid")) { # NOTE: works for KMS video drivers only listProbe("logs", "edid"); my $EdidDecode = checkCmd("edid-decode"); my $MDir = "/sys/class/drm"; foreach my $Dir (listDir($MDir)) { my $Path = $MDir."/".$Dir."/edid"; if(-f $Path) { my $Dec = ""; my $EdidHex = readFileHex($Path); $EdidHex=~s/(.{32})/$1\n/g; if($EdidDecode) { $Dec = runCmd("edid-decode \"$Path\" 2>/dev/null"); } if($EdidHex) { $Edid .= "edid-decode \"$Path\"\n\n"; $Edid .= "EDID (hex):\n"; $Edid .= $EdidHex."\n"; $Edid .= $Dec."\n\n"; } } } if(not $Edid) { # for nvidia, fglrx if(my $MonEdid = checkCmd("monitor-get-edid")) { if($Admin) { if($EdidDecode) { $Edid .= runCmd("monitor-get-edid 2>/dev/null | edid-decode 2>&1"); } else { # LTS $Edid .= runCmd("monitor-get-edid 2>/dev/null | monitor-parse-edid 2>/dev/null"); } $Edid=~s/\n\n/\n/g; } } } if($Opt{"HWLogs"} and $Edid) { writeLog($LOG_DIR."/edid", $Edid); } } my @Mons = (); if(index($Edid, "edid-decode")!=-1) { @Mons = grep { /\S/ } split(/edid\-decode /, $Edid); } else { @Mons = ($Edid); } foreach my $Info (@Mons) { detectMonitor($Info); } # Battery my $Apm = ""; if($Opt{"FixProbe"}) { $Apm = readFile($FixProbe_Logs."/apm"); } elsif(enabledLog("apm") and checkCmd("apm")) { listProbe("logs", "apm"); $Apm = runCmd("apm 2>/dev/null"); $Apm = encryptSerials($Apm, "Serial number"); if($Opt{"HWLogs"} and $Apm) { writeLog($LOG_DIR."/apm", $Apm); } } my $AcpiConf = ""; if($Opt{"FixProbe"}) { $AcpiConf = readFile($FixProbe_Logs."/acpiconf"); } elsif($Apm and enabledLog("acpiconf") and checkCmd("acpiconf")) { listProbe("logs", "acpiconf"); my @Bats = ($Apm=~/Battery (.+?):/g); foreach my $Bat (@Bats) { $AcpiConf .= "# acpiconf -i $Bat\n"; $AcpiConf .= runCmd("acpiconf -i $Bat 2>/dev/null"); $AcpiConf .= "\n"; } if($Opt{"HWLogs"} and $AcpiConf) { writeLog($LOG_DIR."/acpiconf", $AcpiConf); } } my $Upower = ""; if($Opt{"FixProbe"}) { $Upower = readFile($FixProbe_Logs."/upower"); } elsif(enabledLog("upower") and checkCmd("upower")) { listProbe("logs", "upower"); $Upower = runCmd("upower -d 2>/dev/null"); $Upower = encryptSerials($Upower, "serial"); if($Opt{"HWLogs"} and $Upower) { writeLog($LOG_DIR."/upower", $Upower); } } if($Upower) { foreach my $UPInfo (split(/\n\n/, $Upower)) { if($UPInfo=~/devices\/battery_/ and $UPInfo!~/$HID_BATTERY/i) { my %Device = (); foreach my $Line (split(/\n/, $UPInfo)) { if($Line=~/vendor:[ ]*(.+?)[ ]*\Z/) { $Device{"Vendor"} = fmtVal($1); } elsif($Line=~/model:[ ]*(.+?)[ ]*\Z/) { $Device{"Device"} = fmtVal($1); } elsif($Line=~/serial:[ ]*(.+?)[ ]*\Z/) { $Device{"Serial"} = $1; } elsif($Line=~/energy-full-design:[ ]*(.+?)[ ]*\Z/) { $Device{"Size"} = $1; $Device{"Size"}=~s/\,/\./g; } elsif($Line=~/energy-full:[ ]*(.+?)[ ]*\Z/) { $Device{"CurSize"} = $1; $Device{"CurSize"}=~s/\,/\./g; } elsif($Line=~/technology:[ ]*(.+?)[ ]*\Z/) { $Device{"Technology"} = $1; } elsif($Line=~/capacity:[ ]*(.+?)[ ]*\Z/) { $Device{"Capacity"} = $1; } } if($Device{"Device"}=~/Keyboard|Mouse/i) { next; } if(not $Device{"Size"} or $Device{"Size"} eq "0 Wh") { if(my $C = $Device{"Capacity"}) { $C=~s/\%//; my $F = $Device{"CurSize"}; $F=~s/ Wh//; $Device{"Size"} = ($F*100/$C)." Wh"; } } cleanValues(\%Device); registerBattery(\%Device); } } } my $PSDir = "/sys/class/power_supply"; my $PowerSupply = ""; if($Opt{"FixProbe"}) { $PowerSupply = readFile($FixProbe_Logs."/power_supply"); } elsif(-d $PSDir) { listProbe("logs", "power_supply"); foreach my $Bat (listDir($PSDir)) { my $PSPath = $PSDir."/".$Bat; $PowerSupply .= $PSPath.":\n"; $PowerSupply .= readFile($PSPath."/uevent"); $PowerSupply .= "\n"; } $PowerSupply = encryptSerials($PowerSupply, "SERIAL_NUMBER"); if($Opt{"HWLogs"} and $PowerSupply) { writeLog($LOG_DIR."/power_supply", $PowerSupply); } } if(not $Upower and $PowerSupply) { foreach my $Block (split(/\n\n/, $PowerSupply)) { if(($Block=~/$PSDir\/BAT/i or $Block=~/POWER_SUPPLY_CAPACITY\=/i) and $Block!~/$HID_BATTERY/i) { my %Device = (); if($Block=~/POWER_SUPPLY_MODEL_NAME=(.+)/i) { $Device{"Device"} = $1; } if($Device{"Device"}=~/Keyboard|Mouse/i) { next; } if($Block=~/POWER_SUPPLY_MANUFACTURER=(.+)/i) { $Device{"Vendor"} = $1; } else { if($Device{"Device"}=~s/\A(DELL)\s+//i) { $Device{"Vendor"} = $1; } } if($Block=~/POWER_SUPPLY_TECHNOLOGY=(.+)/i) { $Device{"Technology"} = $1; } if($Block=~/POWER_SUPPLY_ENERGY_FULL_DESIGN=(.+)/i) { if(my $EFullDesign = $1) { $Device{"Size"} = ($EFullDesign/1000000)." Wh"; if($Block=~/POWER_SUPPLY_ENERGY_FULL=(.+)/i) { $Device{"Capacity"} = $1*100/$EFullDesign; } } } if($Block=~/POWER_SUPPLY_CHARGE_FULL=(.+)/i) { $Device{"Charge"} = $1; } if($Block=~/POWER_SUPPLY_CHARGE_FULL_DESIGN=(.+)/i) { $Device{"DesignCharge"} = $1; if($Device{"Charge"} and $Device{"DesignCharge"}) { $Device{"Capacity"} = $Device{"Charge"}*100/$Device{"DesignCharge"}; } } if($Block=~/POWER_SUPPLY_SERIAL_NUMBER=\s*(.+)/i) { $Device{"Serial"} = $1; } if($Block=~/POWER_SUPPLY_VOLTAGE_MIN_DESIGN=(.+)/i) { $Device{"MinVoltage"} = $1; } if($Block=~/POWER_SUPPLY_VOLTAGE_MAX_DESIGN=(.+)/i) { $Device{"MaxVoltage"} = $1; } if(not $Device{"Size"}) { if($Device{"MinVoltage"} and $Device{"DesignCharge"}) { $Device{"Size"} = (($Device{"DesignCharge"}/1000000)*($Device{"MinVoltage"}/1000000))." Wh"; } elsif($Device{"MaxVoltage"} and $Device{"Charge"}) { $Device{"Size"} = (($Device{"Charge"}/1000000)*($Device{"MaxVoltage"}/1000000))." Wh"; } } if(not $Device{"Capacity"}) { if($Block=~/POWER_SUPPLY_HEALTH=Good/i) { $Device{"Status"} = "works"; } } registerBattery(\%Device); } } } # PNP my $Lspnp = ""; if($Opt{"FixProbe"}) { $Lspnp = readFile($FixProbe_Logs."/lspnp"); } elsif(enabledLog("lspnp") and checkCmd("lspnp")) { listProbe("logs", "lspnp"); $Lspnp = runCmd("lspnp -vv 2>&1"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/lspnp", $Lspnp); } } # HDD my $Hdparm = ""; if($Opt{"FixProbe"}) { $Hdparm = readFile($FixProbe_Logs."/hdparm"); } elsif($Opt{"HWLogs"} and enabledLog("hdparm")) { if($Admin and checkCmd("hdparm")) { listProbe("logs", "hdparm"); foreach my $Dev (sort keys(%HDD)) { if($Dev=~/\A\/dev\/sr\d+\Z/) { next; } my $Id = $HDD{$Dev}; if(index($Id, "usb:")==0 or index($Id, "scsi:")==0) { next; } my $Output = runCmd("hdparm -I \"$Dev\" 2>/dev/null"); $Output = encryptSerials($Output, "Serial Number"); $Output = encryptSerials($Output, "Unique ID"); $Output = hideTags($Output, "WWN Device Identifier"); if(length($Output)<30) { # empty next; } $Hdparm .= $Output; } } writeLog($LOG_DIR."/hdparm", $Hdparm); } if($Opt{"HWLogs"}) { if(enabledLog("hddtemp") and checkCmd("hddtemp")) { listProbe("logs", "hddtemp"); if(my $HddTemp = runCmd("hddtemp 2>/dev/null")) { writeLog($LOG_DIR."/hddtemp", $HddTemp); } } } my %Smartctl = (); my $SmartctlCmd = undef; if(not $Opt{"FixProbe"} and $Opt{"HWLogs"}) { if(checkCmd("smartctl")) { $SmartctlCmd = "smartctl"; } if($Opt{"Snap"} or $Opt{"AppImage"} or $Opt{"Flatpak"}) { $SmartctlCmd = findCmd("smartctl"); } } if($Opt{"FixProbe"}) { $Smartctl{"Normal"} = readFile($FixProbe_Logs."/smartctl"); my $CurDev = undef; my %DriveDesc = (); foreach my $SL (split(/\n/, $Smartctl{"Normal"})) { if(index($SL, "/dev/")==0) { $CurDev = $SL; } elsif($CurDev) { $DriveDesc{$CurDev} .= $SL."\n"; } } foreach my $Dev (sort keys(%DriveDesc)) { my $Id = $HDD{$Dev}; if(not $Id) { $Id = detectDrive($DriveDesc{$Dev}, $Dev); } if($Id) { setDriveStatus($DriveDesc{$Dev}, $Id); } } } elsif($Opt{"HWLogs"} and enabledLog("smartctl")) { if($Admin and $SmartctlCmd) # $Admin or $Opt{"Snap"} ? { listProbe("logs", "smartctl"); my %ProbedRAID = (); foreach my $Dev (sort keys(%HDD)) { if($Dev=~/\A\/dev\/sr\d+\Z/) { next; } my $Id = $HDD{$Dev}; if($HW{$Id}{"Driver"}=~/megaraid|hpsa/) { my $RAID = $HW{$Id}{"Device"}; $RAID=~s/\s+\d.+?B\Z//; if($Opt{"ListProbes"}) { printMsg("INFO", "Probing $RAID"); } if(defined $ProbedRAID{$RAID}) { # Do not probe same RAID twice next; } my $RaidMax = 23; if($HW{$Id}{"Driver"}=~/hpsa/) { $RaidMax = 15; } foreach my $N (0 .. $RaidMax) { if($HW{$Id}{"Driver"}=~/megaraid/) { $Smartctl{"MegaRAID"} .= runSmartctl($SmartctlCmd, undef, $Dev, $Dev, "MegaRAID", "-d megaraid,$N", $N); } elsif($HW{$Id}{"Driver"}=~/hpsa/) { $Smartctl{"HPSA"} .= runSmartctl($SmartctlCmd, undef, $Dev, $Dev, "HPSA", "-d cciss,$N", $N); } } $ProbedRAID{$RAID} = 1; next; } my $DiskReport = runSmartctl($SmartctlCmd, $Id, $Dev, $Dev); if(isBSD()) { my $TryNvme = $Dev; if(not $DiskReport and $TryNvme=~s{(nvd|nda)(\d+)\Z}{nvme$2}) { $DiskReport = runSmartctl($SmartctlCmd, $Id, $TryNvme, $Dev); } if(not $DiskReport) { if(isNetBSD()) { $DiskReport = runSmartctl($SmartctlCmd, $Id, $Dev."d", $Dev); } elsif(isOpenBSD()) { $DiskReport = runSmartctl($SmartctlCmd, $Id, $Dev."c", $Dev); } } } $Smartctl{"Normal"} .= $DiskReport; } if($Smartctl{"Normal"}) { writeLog($LOG_DIR."/smartctl", $Smartctl{"Normal"}); } if($Smartctl{"MegaRAID"}) { writeLog($LOG_DIR."/smartctl_megaraid", $Smartctl{"MegaRAID"}); } if($Smartctl{"HPSA"}) { writeLog($LOG_DIR."/smartctl_hpsa", $Smartctl{"HPSA"}); } } else { # write empty writeLog($LOG_DIR."/smartctl", ""); } } my $AtaCtl = ""; if($Opt{"FixProbe"}) { $AtaCtl = readFile($FixProbe_Logs."/atactl"); } elsif($Opt{"HWLogs"} and enabledLog("atactl") and checkCmd("atactl")) { listProbe("logs", "atactl"); foreach my $Dev (sort keys(%HDD)) { if($Dev=~/[dc]\Z/) { next; } my $AtaDevCtl = runCmd("atactl ".basename($Dev)." identify 2>/dev/null"); if($AtaDevCtl) { $AtaDevCtl .= "\n"; $AtaDevCtl .= runCmd("atactl ".basename($Dev)." smart status 2>/dev/null"); $AtaDevCtl .= "\n"; $AtaCtl .= $Dev."\n"; $AtaCtl .= $AtaDevCtl; } } $AtaCtl = encryptSerials($AtaCtl, "Serial #"); writeLog($LOG_DIR."/atactl", $AtaCtl); } my $Diskinfo = ""; if($Opt{"FixProbe"}) { $Diskinfo = readFile($FixProbe_Logs."/diskinfo"); } elsif($Opt{"HWLogs"} and enabledLog("diskinfo") and checkCmd("diskinfo")) { listProbe("logs", "diskinfo"); foreach my $Dev (sort keys(%HDD)) { $Diskinfo .= runCmd("diskinfo -v $Dev 2>/dev/null"); } $Diskinfo=~s/[^\s]+(\s+# Disk ident.+\n)/...$1/g; $Diskinfo=~s/( SN ).+?( MFG )/$1...$2/g; writeLog($LOG_DIR."/diskinfo", $Diskinfo); } my $Disklabel = ""; if($Opt{"FixProbe"}) { $Disklabel = readFile($FixProbe_Logs."/disklabel"); } elsif($Opt{"HWLogs"} and enabledLog("disklabel") and checkCmd("disklabel")) { listProbe("logs", "disklabel"); foreach my $Dev (sort keys(%HDD)) { my $DiskDevLabel = runCmd("disklabel $Dev 2>/dev/null"); if($DiskDevLabel) { $Disklabel .= $DiskDevLabel; $Disklabel .= "\n"; } } $Disklabel=~s/(label:\s+)(.+?)\n/$1...\n/g; $Disklabel = encryptSerials($Disklabel, "duid"); if($Disklabel) { writeLog($LOG_DIR."/disklabel", $Disklabel); } } my $Camcontrol = ""; if($Opt{"FixProbe"}) { $Camcontrol = readFile($FixProbe_Logs."/camcontrol"); } elsif($Opt{"HWLogs"} and enabledLog("camcontrol") and checkCmd("camcontrol")) { listProbe("logs", "camcontrol"); foreach my $Dev (sort keys(%HDD)) { if(my $CCRes = runCmd("camcontrol identify $Dev 2>/dev/null")) { $Camcontrol .= "$Dev\n"; $Camcontrol .= $CCRes; } } $Camcontrol=~s/(serial number\s+)(.+?)\n/$1...\n/g; $Camcontrol=~s/(WWN\s+[a-f\d]{7})[a-f\d]{9}/$1.../g; writeLog($LOG_DIR."/camcontrol", $Camcontrol); } my $MfiUtil = ""; if($Opt{"FixProbe"}) { $MfiUtil = readFile($FixProbe_Logs."/mfiutil"); } elsif($Opt{"HWLogs"} and enabledLog("mfiutil") and checkCmd("mfiutil")) { listProbe("logs", "mfiutil"); $MfiUtil .= runCmd("mfiutil show config 2>/dev/null"); if($MfiUtil) { writeLog($LOG_DIR."/mfiutil", $MfiUtil); } } my $Hwstat = ""; if($Opt{"FixProbe"}) { $Hwstat = readFile($FixProbe_Logs."/hwstat"); } elsif($Opt{"HWLogs"} and enabledLog("hwstat") and checkCmd("hwstat")) { listProbe("logs", "hwstat"); $Hwstat .= runCmd("hwstat 2>/dev/null"); $Hwstat = encryptSerials($Hwstat, "Serial number"); writeLog($LOG_DIR."/hwstat", $Hwstat); } foreach my $Info (split(/\n\n/, $Hwstat)) { if($Info=~/$HID_BATTERY/i) { next; } my %Bat = (); if($Info=~/Model number:\s+(.+)/i) { $Bat{"Device"} = $1; } if($Bat{"Device"}=~/Keyboard|Mouse/i) { next; } if($Info=~/OEM info:\s+(.+)/i) { $Bat{"Vendor"} = $1; } else { if($Bat{"Device"}=~s/\A(DELL)\s+//i) { $Bat{"Vendor"} = $1; } } if($Info=~/Type:\s+(.+)/i) { $Bat{"Technology"} = $1; } if($Info=~/Design voltage\s+(\d+)/i) { $Bat{"Voltage"} = $1/1000; } if($Info=~/Remaining capacity:\s+(\d+)/i) { $Bat{"Capacity"} = $1; } if($Info=~/Design capacity:\s+(\d+)\s+([^\s]+)/i) { if(my $EFullDesign = $1) { my $Unit = $2; if($Unit eq "mWh") { $Bat{"Size"} = ($EFullDesign/1000)." Wh"; } elsif($Unit eq "mAh") { if($Bat{"Voltage"}) { $Bat{"Size"} = ($EFullDesign*$Bat{"Voltage"}/1000)." Wh"; } } # if(not $Bat{"Capacity"} and $Info=~/Last full capacity:\s+(\d+)/i) { # $Bat{"Capacity"} = $1*100/$EFullDesign; # } } } if(not $Bat{"Capacity"}) { next; } if($Info=~/Serial number:\s+(.+)/i) { $Bat{"Serial"} = $1; } registerBattery(\%Bat); } if(not $Opt{"FixProbe"}) { if($Admin and enabledLog("smart-log") and checkCmd("nvme")) { listProbe("logs", "smart-log"); my $NvmeCli = ""; foreach my $Dev (sort keys(%HDD)) { if($Dev=~/nvme/) { my $Output = runCmd("nvme smart-log \"".$Dev."\" 2>/dev/null"); my $OutputAdd = runCmd("nvme smart-log-add \"".$Dev."\" 2>/dev/null"); if($Output or $OutputAdd) { $NvmeCli .= $Dev."\n"; if($Output) { $NvmeCli .= $Output."\n"; } if($OutputAdd) { $NvmeCli .= $OutputAdd."\n"; } $NvmeCli .= "\n"; } } } if($NvmeCli) { writeLog($LOG_DIR."/smart-log", $NvmeCli); } } } my @DrSer = (); foreach my $Dev (keys(%HDD)) { if(not $HDD{$Dev}) { if(index($Dev, "nvme")!=-1) { my %Drv = ( "Type"=>"disk" ); if(defined $HDD_Info{$Dev}) { foreach ("Capacity", "Driver", "Model", "Vendor", "File") { $Drv{$_} = $HDD_Info{$Dev}{$_}; } } if($Drv{"Model"} and my $Vnd = guessDeviceVendor($Drv{"Model"})) { $Drv{"Vendor"} = $Vnd; $Drv{"Model"} = duplVendor($Vnd, $Drv{"Model"}); } if($Drv{"Model"} and $Drv{"Model"} ne "Disk") { $Drv{"Device"} = $Drv{"Model"}; } else { $Drv{"Device"} = "NVMe SSD Drive"; } $Drv{"Device"} .= addCapacity($Drv{"Device"}, $Drv{"Capacity"}); $Drv{"Kind"} = "NVMe"; my $DiskId = undef; if($Drv{"Vendor"}) { $DiskId = devID(nameID($Drv{"Vendor"}), "solid-state-drive", $Drv{"Capacity"}); } else { $DiskId = devID("solid-state-drive", $Drv{"Capacity"}); } $DiskId = $PCI_DISK_BUS.":".fmtID($DiskId); $HW{$DiskId} = \%Drv; countDevice($DiskId, $Drv{"Type"}); } } else { if(my $DSer = $HW{$HDD{$Dev}}->{"Serial"}) { if(not $HW{$HDD{$Dev}}->{"Class"}) { push(@DrSer, $DSer); } } } } if(@DrSer) { $Sys{"Uuid"} = getSysUUID(@DrSer); } foreach my $Dev (keys(%MMC)) { if(not $MMC{$Dev}) { if(index($Dev, "mmcblk")!=-1) { my %Drv = ( "Type"=>"disk" ); if(defined $MMC_Info{$Dev}) { foreach ("Capacity", "Driver", "Vendor", "Device", "Serial") { $Drv{$_} = $MMC_Info{$Dev}{$_}; } } if(defined $VendorByModel{$Drv{"Device"}}) { $Drv{"Vendor"} = $VendorByModel{$Drv{"Device"}}; } $Drv{"Capacity"} = fixCapacity($Drv{"Capacity"}); if($Drv{"Device"}) { $Drv{"Device"} .= " ".addCapacity($Drv{"Device"}, $Drv{"Capacity"}); $Drv{"Kind"} = "MMC"; my $MmcId = "mmc:".fmtID(devID(nameID($Drv{"Vendor"}), devSuffix(\%Drv))); $HW{$MmcId} = \%Drv; countDevice($MmcId, $Drv{"Type"}); $MMC{$Dev} = $MmcId; } } } } if($Opt{"FixProbe"}) { foreach my $RAID_Vendor ("MegaRAID", "HPSA") { my $RAID_Prefix = lc($RAID_Vendor); $Smartctl{$RAID_Vendor} = readFile($FixProbe_Logs."/smartctl_$RAID_Prefix"); my ($CurDev, $CurDid) = (undef, undef); my %DriveDesc = (); foreach my $SL (split(/\n/, $Smartctl{$RAID_Vendor})) { if(index($SL, "/dev/")==0) { if($SL=~/(.+),($RAID_Prefix)_disk_(.+)/) { ($CurDev, $CurDid) = ($1, int($3)); } } elsif($CurDev) { $DriveDesc{$CurDev}{$CurDid} .= $SL."\n"; } } foreach my $Dev (sort keys(%DriveDesc)) { foreach my $Did (sort keys(%{$DriveDesc{$Dev}})) { my $Desc = $DriveDesc{$Dev}{$Did}; if(my $Id = detectDrive($Desc, $Dev, $RAID_Vendor, $Did)) { setDriveStatus($Desc, $Id); } } } } } elsif($Admin and not $Smartctl{"MegaRAID"}) { # try by storcli my $StorcliCmd = undef; foreach my $Cmd ("storcli64", "storcli") { if(checkCmd($Cmd)) { $StorcliCmd = $Cmd; last; } } if($StorcliCmd) { # MegaRAID listProbe("logs", "storcli"); my $Storcli = runCmd($StorcliCmd." /call /vall /eall /sall show 2>&1"); if($Storcli=~/No Controller found/i) { $Storcli = undef; } $Storcli = encryptSerials($Storcli, "SCSI NAA Id"); if($Storcli) { writeLog($LOG_DIR."/storcli", $Storcli); } if(index($Storcli, "unexpected TOKEN_SLASH")!=-1) { $Storcli = undef; } if($Storcli) { my %DInfo = (); my $Ctrl = undef; foreach my $L (split(/\n/, $Storcli)) { if($L=~/Controller = (\d+)/) { $Ctrl = $1; } elsif($Ctrl and $L=~/SCSI NAA Id = (\w+)/) { $DInfo{$Ctrl}{"NAA"} = $1; } elsif($Ctrl and $L=~/\d+:\d+\s+(\d+)/) { $DInfo{$Ctrl}{"DID"}{$1} = 1; } } my %DID = (); foreach my $Controller (sort {int($a)<=>int($b)} keys(%DInfo)) { if(my $NAA = $DInfo{$Controller}{"NAA"}) { if(my $Dev = $DevNameById{"wwn-0x".$NAA}) { foreach my $D (keys(%{$DInfo{$Controller}{"DID"}})) { $DID{$Dev}{$D} = 1; } } } } if($SmartctlCmd) { foreach my $Dev (sort keys(%DID)) { foreach my $Did (sort {int($a)<=>int($b)} keys(%{$DID{$Dev}})) { $Smartctl{"MegaRAID"} .= runSmartctl($SmartctlCmd, undef, $Dev, $Dev, "MegaRAID", "-d megaraid,$Did", $Did); } } } if($Smartctl{"MegaRAID"}) { writeLog($LOG_DIR."/smartctl_megaraid", $Smartctl{"MegaRAID"}); } } } } if(not $Opt{"FixProbe"} and not $Smartctl{"MegaRAID"} and enabledLog("megacli")) { my $MegacliCmd = undef; foreach my $Cmd ("megacli", "MegaCli64", "MegaCli") { if(checkCmd($Cmd)) { $MegacliCmd = $Cmd; last; } } if($MegacliCmd) { listProbe("logs", "megacli"); my $Megacli = runCmd($MegacliCmd." -PDList -aAll 2>/dev/null"); $Megacli=~s/(Inquiry Data\s*:\s*)[^\s]+/$1.../g; # Hide serial $Megacli = encryptSerials($Megacli, "WWN"); if($Megacli) { writeLog($LOG_DIR."/megacli", $Megacli); } # my %DIDs = (); # while($Megacli=~/Device Id\s*:\s*(\d+)/g) { # $DIDs{$1} = 1; # } } } if(not $Opt{"FixProbe"}) { if(enabledLog("megactl") and checkCmd("megactl")) { listProbe("logs", "megactl"); my $Megactl = runCmd("megactl 2>&1"); if($Megactl) { writeLog($LOG_DIR."/megactl", $Megactl); } } } if(not $Opt{"FixProbe"}) { if(enabledLog("arcconf") and checkCmd("arcconf")) { # Adaptec RAID listProbe("logs", "arcconf"); my @Controllers = (); my $ArcconfList = runCmd("arcconf LIST 2>&1"); while($ArcconfList=~s/Controller\s+(\d+)//) { push(@Controllers, $1); } my $Arcconf = ""; foreach my $Cn (@Controllers) { $Arcconf .= "Controller $Cn:\n"; $Arcconf .= runCmd("arcconf GETCONFIG $Cn PD 2>&1"); $Arcconf .= "\n"; } if($Arcconf) { $Arcconf = encryptSerials($Arcconf, "Serial number"); $Arcconf = encryptSerials($Arcconf, "World-wide name", "arcconf", 1); writeLog($LOG_DIR."/arcconf", $Arcconf); } listProbe("logs", "arcconf_smart"); my $Arcconf_Smart = ""; foreach my $Cn (@Controllers) { $Arcconf_Smart .= "Controller $Cn:\n"; $Arcconf_Smart .= runCmd("arcconf GETSMARTSTATS $Cn TABULAR 2>&1"); $Arcconf_Smart .= "\n"; } if($Arcconf_Smart) { $Arcconf_Smart=~s/\.{4,}/:/g; $Arcconf_Smart = encryptSerials($Arcconf_Smart, "serialNumber"); $Arcconf_Smart = encryptSerials($Arcconf_Smart, "vendorProductID"); writeLog($LOG_DIR."/arcconf_smart", $Arcconf_Smart); } } } if((not $Sys{"System"} or $Sys{"System"}=~/freedesktop/) and $Dmesg) { if($Dmesg=~/Linux version (.+)/) { my $LinVer = $1; foreach my $Lin ("endless", "ubuntu", "debian", "arch", "suse linux", "centos", "artix", "nixos") { if($LinVer=~/$Lin/i) { $Sys{"System"} = $Lin; if($Sys{"System"} eq "suse linux") { $Sys{"System"} = "opensuse"; } $Sys{"System_version"} = undef; last; } } if(index($LinVer, "neverware\@cloudready-builder") != -1) { $Sys{"System"} = "chrome_os"; $Sys{"System_version"} = undef; } elsif(index($LinVer, "Binutils for Uos") != -1) { $Sys{"System"} = "deepin"; $Sys{"System_version"} = undef; } } } if(index($Dmesg, "Secure boot enabled")!=-1) { # or index($Dmesg, "Secure boot could not be determined")!=-1 $Sys{"Secureboot"} = "enabled"; } elsif(defined $Sys{"Secureboot"}) { delete($Sys{"Secureboot"}); } if(-e $FixProbe_Logs."/boot_efi" or index($Dmesg, "] efi:")!=-1) { $Sys{"Boot_mode"} = "EFI"; } else { $Sys{"Boot_mode"} = "BIOS"; } if(not $Sys{"Microarch"} and $Dmesg=~/, ([\w\s\-]+) events, /) { $Sys{"Microarch"} = $1; if($Sys{"Microarch"}=~/disabled/) { $Sys{"Microarch"} = undef; } if($Sys{"Microarch"} eq "Core2") { $Sys{"Microarch"} = "Core"; } elsif($Sys{"Microarch"} eq "Atom") { $Sys{"Microarch"} = undef; } } if($Dmesg=~/microcode:.*?(sig|patch_level)=(0x\w+)/) { $Sys{"Microcode"} = $2; if(not $Sys{"Microarch"} and defined $MicroCodeMicroArch{$Sys{"Microcode"}}) { $Sys{"Microarch"} = $MicroCodeMicroArch{$Sys{"Microcode"}}; } } if($Dmesg=~/Memory usable by graphics device = (\d+)M/) { $Sys{"Video_memory"} = $1/1024.0; } elsif($Dmesg=~/DRM: VRAM: (\d+) MiB/) { $Sys{"Video_memory"} = $1/1024.0; } elsif($Dmesg=~/(\d+)M of VRAM memory ready/) { $Sys{"Video_memory"} = $1/1024.0; } if($Dmesg=~/Memory: \d+k\/(\d+)k available/) { $Sys{"Ram_total"} = $1; } elsif(isBSD() and $Dmesg=~/real (mem|memory)\s*=.+?\(([^()]+?)\s*MB\)/) { $Sys{"Ram_total"} = $2*1024.0; if($Dmesg=~/avail (mem|memory)\s*=.+?\(([^()]+?)\s*MB\)/) { $Sys{"Ram_used"} = $Sys{"Ram_total"} - $2*1024.0; } } if((not $Sys{"Model"} or $Sys{"Model"} eq "rpi") and $Sys{"Arch"}=~/arm|aarch/i) { if($Dmesg=~/(Machine(| model)|Hardware name): (.+)/) { $Sys{"Model"} = $3; if($Sys{"Model"}=~/(Orange Pi|Banana Pi|Raspberry Pi|Odroid|rockchip|AM335x)/i) { $Sys{"Type"} = "system on chip"; } if($Sys{"Model"}=~/\A(Raspberry Pi) /) { $Sys{"Vendor"} = "Raspberry Pi Foundation"; } elsif($Sys{"Model"}=~/\Arockchip,(.+)\Z/) { $Sys{"Model"} = $1; $Sys{"Vendor"} = "Rockchip"; $Sys{"System"} = "android"; } elsif($Sys{"Model"}=~s/\A(FriendlyElec|Hardkernel|NextThing|NVIDIA|Olimex|Radxa|TI|Xunlong) //) { $Sys{"Vendor"} = $1; $Sys{"Type"} = "system on chip"; } elsif($Sys{"Model"}=~/Pinebook/) { $Sys{"Type"} = "notebook"; $Sys{"Vendor"} = "Pine Microsystems"; } elsif($Sys{"Model"}=~/PinePhone/) { $Sys{"Type"} = "smartphone"; $Sys{"Vendor"} = "Pine Microsystems"; } elsif($Sys{"Model"}=~/Pine64/) { $Sys{"Type"} = "system on chip"; $Sys{"Vendor"} = "Pine Microsystems"; } $Sys{"Model"}=~s/\s+Board\Z//i; if($Sys{"Vendor"} or $Sys{"Model"}) { fixFFByModel($Sys{"Vendor"}, $Sys{"Model"}); } } elsif($Dmesg=~/(Raspberry Pi)/) { $Sys{"Model"} = $1; $Sys{"Type"} = "system on chip"; } ($Sys{"Vendor"}, $Sys{"Model"}) = fixVendorModel($Sys{"Vendor"}, $Sys{"Model"}); } my $XLog = ""; if($Opt{"FixProbe"}) { $XLog = readFile($FixProbe_Logs."/xorg.log"); } else { listProbe("logs", "xorg.log"); $XLog = readFile("/var/log/Xorg.0.log"); if(my $SessUser = getUser()) { # Xorg.0.log in X11/XWayland (Ubuntu >= 18.04) if(my $XLog_U = readFile("/home/".$SessUser."/.local/share/xorg/Xorg.0.log")) { $XLog = $XLog_U; } } else { # Live if(my $XLog_U = readFile("/home/ubuntu/.local/share/xorg/Xorg.0.log")) { $XLog = $XLog_U; } } if($XLog) { $XLog = hideTags($XLog, "Serial#"); $XLog = hidePaths($XLog); $XLog = encryptUUIDs($XLog); if(my $HostName = $ENV{"HOSTNAME"}) { $XLog=~s/ \Q$HostName\E / NODE /g; } $XLog = hideHost($XLog); $XLog = hideByRegexp($XLog, qr/\s?([\w\s]+\’s)/); } if(not $Opt{"Docker"} or $XLog) { writeLog($LOG_DIR."/xorg.log", $XLog); } } my $X11LogMatch = index($XLog, $Sys{"Kernel"})!=-1; if(not $Sys{"Display_server"} and $X11LogMatch) { $Sys{"Display_server"} = "X11"; } my $CmdLine = ""; my ($Nomodeset, $ForceVESA) = (undef, undef); if($XLog) { if($XLog=~/NVIDIA\(\d+\): Memory: (\d+) kBytes/) { $Sys{"Video_memory"} = $1/(1024.0*1024.0); } elsif($XLog=~/Video RAM: (\d+) kByte/) { $Sys{"Video_memory"} = $1/(1024.0*1024.0); } elsif(isBSD() and $XLog=~/VideoRAM: (\d+) KB/) { # SIS $Sys{"Video_memory"} = $1/(1024.0*1024.0); } if($XLog=~/Kernel command line:(.*)/) { $CmdLine = $1; } if(not $Sys{"System"} or $Sys{"System"}=~/freedesktop/ or isBSD()) { my @OSes = ("deepin", "clearlinux", "debian", "opensuse", "alt linux", "ubuntu", "manjaro", "artix", "arch"); if(isBSD()) { @OSes = @KNOWN_BSD; } my $Matched = undef; foreach my $Prefix ("Build Operating System", "Current Operating System", "Kernel command line") { if($XLog=~/$Prefix:(.*)/) { my $Linux = lc($1); $Linux=~s{/arch/}{/}g; foreach my $Lin (@OSes) { if(index($Linux, $Lin) != -1) { $Matched = lc($Lin); last; } } if($Linux=~/alt linux (p\d+)/) { $Matched = "alt-$1"; } } } if($Matched) { if(isBSD()) { $Sys{"System"}=~s/\A(\w+)-/$Matched-/; } else { $Sys{"System"} = $Matched; $Sys{"System_version"} = undef; } } } my @CheckDrivers = @G_DRIVERS; if(not defined $GraphicsCards{"10de"}) { rmArrayVal(\@CheckDrivers, ["nouveau", "nvidia"]); } if(not defined $GraphicsCards{"1002"}) { rmArrayVal(\@CheckDrivers, ["radeon", "amdgpu", "fglrx"]); } if(not defined $GraphicsCards{"8086"}) { rmArrayVal(\@CheckDrivers, \@G_DRIVERS_INTEL); } if($Sys{"Kernel"} and not $X11LogMatch) { # Do not check old X11 log @CheckDrivers = (); } else { $Nomodeset = (index($CmdLine, " nomodeset")!=-1 or index($CmdLine, " nokmsboot")!=-1); $ForceVESA = (index($CmdLine, "xdriver=vesa")!=-1); } foreach my $D (@CheckDrivers) { if($Nomodeset or index($CmdLine, "$D.modeset=0")!=-1) { if($ForceVESA or isIntelDriver($D)) { # can't check setCardStatus($D, "detected"); next; } } if(defined $KernMod{$D} and defined $WorkMod{$D}) { my @Loaded = (); my @Drs = ($D); if(isIntelDriver($D)) { @Drs = ("intel"); } elsif($D eq "nouveau") { # Manjaro 17 @Drs = ("nouveau", "nvidia"); } if(keys(%GraphicsCards_InUse)==1) { # Ubuntu 18 push(@Drs, "modesetting"); } foreach my $Dr (@Drs) { if(index($XLog, "LoadModule: \"$Dr\"")!=-1) { push(@Loaded, $Dr); } } if(@Loaded) { my @Unloaded = (); foreach my $Dr (@Loaded) { if(index($XLog, "UnloadModule: \"$Dr\"")!=-1) { push(@Unloaded, $Dr); } } if(isIntelDriver($D) and defined $GraphicsCards{"1002"} and defined $WorkMod{"fglrx"}) { # fglrx by intel, intel is unloaded setCardStatus($D, "works"); next; } if($#Unloaded==$#Loaded) { setCardStatus($D, "failed"); } else { setCardStatus($D, "works"); } } elsif(grep {$D eq $_} ("nvidia") and defined $GraphicsCards{"8086"}) { # no entries in the Xorg.0.log setCardStatus($D, "works"); } } my @DrLabels = (uc($D)); my @DrIds = ($D); if(isIntelDriver($D)) { @DrLabels = ("intel"); push(@DrIds, "i965"); } elsif($D eq "radeon") { push(@DrIds, ("r600", "r300", "radeonsi")); } elsif($D eq "amdgpu") { push(@DrIds, "radeonsi"); } if(keys(%GraphicsCards_InUse)==1) { push(@DrLabels, "modeset"); } foreach my $DrLabel (@DrLabels) { if(index($XLog, ") ".$DrLabel."(")!=-1) { # (II) RADEON(0) # (II) NOUVEAU(0) # (II) intel(0) # (II) modeset(0) setCardStatus($D, "works"); last; } } foreach my $DrId (@DrIds) { if(index($XLog, "): [DRI2] DRI driver: $DrId")!=-1) { # (II) modeset(G0): [DRI2] DRI driver: nouveau # (II) modeset(0): [DRI2] DRI driver: i965 setCardStatus($D, "works"); last; } } if(keys(%GraphicsCards_InUse)==1 and index($XLog, ") FBDEV(")!=-1) { setCardStatus($D, "failed"); } } if(isBSD()) { if($XLog=~/ modeset\(.+Intel/ or $XLog=~/ intel\(0\): /) { setCardStatusByVendor("8086", "works", "i915"); } elsif($XLog=~/ NVIDIA\(0\): /) { setCardStatusByVendor("10de", "works", "nvidia"); } elsif($XLog=~/ NV\(0\): /) { setCardStatusByVendor("10de", "works", "nv"); } elsif($XLog=~/ RADEON\(0\): Chipset:/) { setCardStatusByVendor("1002", "works", "radeon"); } elsif($XLog=~/ modeset\(0\): Output/ and keys(%GraphicsCards_InUse)==1) { if((keys(%GraphicsCards_InUse))[0]=~/pci:([a-f\d]{4})/) { setCardStatusByVendor($1, "works", undef); } } } } else { # No Xorg log if($Dmesg) { if($Dmesg=~/Command line:(.*)/) { $CmdLine = $1; } $Nomodeset = (index($CmdLine, " nomodeset")!=-1 or index($CmdLine, " nokmsboot")!=-1); $ForceVESA = (index($CmdLine, "xdriver=vesa")!=-1); } foreach my $D (@G_DRIVERS) { if($Nomodeset or index($CmdLine, "$D.modeset=0")!=-1) { if($ForceVESA or isIntelDriver($D)) { # can't check setCardStatus($D, "detected"); next; } } if(defined $WorkMod{$D}) { setCardStatus($D, "works"); } } } if($Nomodeset) { $Sys{"Nomodeset"} = "enabled"; } elsif(defined $Sys{"Nomodeset"}) { delete($Sys{"Nomodeset"}); } if($Sys{"Video_memory"}) { $Sys{"Video_memory"} = roundFloat($Sys{"Video_memory"}, 2); } if(not grep {$HW{$_}{"Type"} eq "monitor"} keys(%HW)) { if(my @LCDs = $XLog=~/\:\s+([^:]+?) \((\w+-?\d+)\)(\: connected| \(boot, connected\)| \(connected\))/g) { # Nvidia foreach my $MPos (0 .. $#LCDs) { if($MPos % 3 != 0) { next; } my ($MName, $MPort, $MConn) = ($LCDs[$MPos], $LCDs[$MPos + 1], $LCDs[$MPos + 2]); my %Mon = (); $Mon{"Device"} = $MName; if($MConn=~/boot/ or index($XLog, "$MPort (boot)")!=-1) { if($XLog=~/Virtual screen size determined to be (\d+) x (\d+)/) { $Mon{"Resolution"} = $1."x".$2; } } my $MID = "eisa:".fmtID(devID(nameID($Mon{"Device"}), $Mon{"Resolution"})); if(defined $HW{$MID}) { last; } if($Mon{"Device"}=~s/\A($ALL_MON_VENDORS)([ \-]|\Z)//) { $Mon{"Vendor"} = $1; } $Mon{"Type"} = "monitor"; $Mon{"Status"} = "works"; if($MPort=~/DFP|LVDS/) { $Mon{"Kind"} = "Digital" } elsif($MPort=~/CRT/) { $Mon{"Kind"} = "Analog" } if($Mon{"Device"}) { $Mon{"Device"} = "LCD Monitor ".$Mon{"Device"}; } else { $Mon{"Device"} = "LCD Monitor"; } if($Mon{"Resolution"}) { $Mon{"Device"} .= " ".$Mon{"Resolution"}; } $HW{$MID} = \%Mon; $HW{$MID}{"Status"} = "works"; } } elsif(my @LCDs = $XLog=~/Output (.+?) using initial mode (\d+x\d+)/g) { foreach my $MPos (0 .. $#LCDs) { if($MPos % 2 != 0) { next; } my ($MPort, $MRes) = ($LCDs[$MPos], $LCDs[$MPos + 1]); my %Mon = (); $Mon{"Type"} = "monitor"; $Mon{"Status"} = "works"; $Mon{"Device"} = "LCD Monitor"; if($MPort=~/DFP|LVDS/) { $Mon{"Kind"} = "Digital" } elsif($MPort=~/CRT/) { $Mon{"Kind"} = "Analog" } $Mon{"Resolution"} = $MRes; my $MID = "eisa:".fmtID(devID(nameID($Mon{"Device"}), $MRes)); $Mon{"Device"} .= " ".$MRes; $HW{$MID} = \%Mon; } } } foreach my $ID (sort keys(%HW)) { if($HW{$ID}{"Type"} eq "monitor") { $Sys{"Monitors"} += 1; } } my $HciConfig = ""; if($Opt{"FixProbe"}) { $HciConfig = readFile($FixProbe_Logs."/hciconfig"); } elsif(enabledLog("hciconfig") and checkCmd("hciconfig")) { listProbe("logs", "hciconfig"); $HciConfig = runCmd("hciconfig -a 2>&1"); $HciConfig = hideMACs($HciConfig); $HciConfig = hideTags($HciConfig, "Name"); if($HciConfig) { writeLog($LOG_DIR."/hciconfig", $HciConfig); } } if($HciConfig) { foreach my $HCI (split(/\n\n/, $HciConfig)) { if(index($HCI, "UP RUNNING ")!=-1) { if($HCI=~/\A[^:]+:?\s/) { foreach my $ID (sort grep {defined $HW{$_}{"Type"} and $HW{$_}{"Type"} eq "bluetooth"} keys(%HW)) { # TODO: identify particular bt devices by lsusb if($HW{$ID}{"Driver"}) { $HW{$ID}{"Status"} = "works"; setAttachedStatus($ID, "works"); } } } } } } my $MmCli = ""; if($Opt{"FixProbe"}) { $MmCli = readFile($FixProbe_Logs."/mmcli"); } elsif(enabledLog("mmcli") and checkCmd("mmcli")) { listProbe("logs", "mmcli"); my $Modems = runCmd("mmcli -L 2>&1"); if($Modems=~/No modems were found/i) { $Modems = ""; } my %MNums = (); while($Modems=~s/Modem\/(\d+)//) { $MNums{$1} = 1; } foreach my $Modem (sort {int($a)<=>int($b)} keys(%MNums)) { my $MInfo = runCmd("mmcli -m $Modem"); $MInfo = hideTags($MInfo, "own|imei|equipment id"); $MmCli .= $MInfo; $MmCli .= "\n"; } if($MmCli) { writeLog($LOG_DIR."/mmcli", $MmCli); } } if($MmCli) { foreach my $MM (split(/\n\n/, $MmCli)) { if($MM=~/model:.*\[(\w+):(\w+)\]/) { if(my $ID = "usb:".lc($1."-".$2)) { if(defined $HW{$ID} and $HW{$ID}{"Driver"}) { $HW{$ID}{"Status"} = "works"; setAttachedStatus($ID, "works"); } } } } } my $OpenscTool = ""; if($Opt{"FixProbe"}) { $OpenscTool = readFile($FixProbe_Logs."/opensc-tool"); } elsif(enabledLog("opensc-tool") and checkCmd("opensc-tool")) { listProbe("logs", "opensc-tool"); $OpenscTool = runCmd("opensc-tool --list-readers"); if($OpenscTool and $OpenscTool!~/No smart card readers/) { $OpenscTool=~s/ \([^\(\)]+\)//g; writeLog($LOG_DIR."/opensc-tool", $OpenscTool); } } if($OpenscTool) { foreach my $SCReader (split(/\n\n/, $OpenscTool)) { if(index($SCReader, "Driver")!=-1) { foreach my $ID (sort grep {defined $HW{$_}{"Type"} and $HW{$_}{"Type"} eq "chipcard"} keys(%HW)) { # TODO: match particular chipcard devices by name if($HW{$ID}{"Driver"}) { $HW{$ID}{"Status"} = "works"; setAttachedStatus($ID, "works"); } } } } } my $Lscpu = ""; if($Opt{"FixProbe"}) { $Lscpu = readFile($FixProbe_Logs."/lscpu"); } elsif(checkCmd("lscpu")) { listProbe("logs", "lscpu"); $Lscpu = runCmd("lscpu 2>&1"); writeLog($LOG_DIR."/lscpu", $Lscpu); } my $CoresPerSocket = undef; if($Lscpu) { my ($Sockets, $Cores, $Threads, $CPUs) = (); my ($CPU_Vendor, $CPU_Name, $CPU_Family, $CPU_ModelNum, $CPU_Stepping) = (); my @CpuVals = (); foreach (split(/\n/, $Lscpu)) { my @CpuAttr = split(":", $_); my $Attr = $CpuAttr[0]; my $Val = $CpuAttr[1]; $Val=~s/\A\s+//; if($Attr eq "Address sizes") { next; } if($Attr eq "Socket(s)") { $Sockets = $Val; } elsif($Attr eq "Core(s) per socket") { $Cores = $Val; $CoresPerSocket = $Val; } elsif($Attr eq "Thread(s) per core") { $Threads = $Val; } elsif($Attr eq "CPU op-mode(s)") { $Sys{"Op_modes"} = $Val; } elsif($Attr eq "Vendor ID" or $Attr eq "Vendor") { $CPU_Vendor = $Val; } elsif($Attr eq "Model name") { $CPU_Name = fmtVal($Val); } elsif($Attr eq "CPU family") { $CPU_Family = $Val; } elsif($Attr eq "Model") { $CPU_ModelNum = $Val; } elsif($Attr eq "Stepping") { $CPU_Stepping = $Val; } elsif($Attr eq "Total CPU(s)") { $CPUs = $Val; } elsif($Attr eq "Architecture") { if(not $Sys{"Arch"}) { $Sys{"Arch"} = $Val; } } push(@CpuVals, $Val); } if($Sockets eq "0") { $Sockets = 1; } if($Sockets and $Cores and $Threads) { $Sys{"Sockets"} = $Sockets; $Sys{"Cores"} = $Cores*$Sockets; $Sys{"Threads"} = $Threads; } elsif(not isBSD()) { if($Lscpu=~/\s((32|64)-bit.*?)\n/) { $Sys{"Op_modes"} = $1; } } if(my $Microarch = detectMicroarch($CPU_Vendor, $CPU_Family, $CPU_ModelNum, $CPU_Name)) { $Sys{"Microarch"} = $Microarch; } if(isBSD()) { if(not $Cores and $CPUs==1) { $Sys{"Cores"} = $CPUs; } if(not $CPU_ID and $CPU_Name) { my %CpuDev = (); if($CPU_Name=~s/\A(ARM) //) { $CPU_Vendor = $1; } elsif($CPU_Name=~/\A(7447A) /) { $CPU_Vendor = "PowerPC"; } $CpuDev{"Vendor"} = fixCpuVendor($CPU_Vendor); $CpuDev{"Device"} = $CPU_Name; $CpuDev{"Device"} = duplVendor($CpuDev{"Vendor"}, $CpuDev{"Device"}); $CpuDev{"Type"} = "cpu"; $CpuDev{"Status"} = "works"; $CPU_ID = "cpu:".fmtID(devID(nameID($CpuDev{"Vendor"}), join(".", ($CPU_Family, $CPU_ModelNum, $CPU_Stepping)), devSuffix(\%CpuDev))); $HW{$CPU_ID} = \%CpuDev; } setDevCount($CPU_ID, "cpu", $Sys{"Threads"}*$Sys{"Cores"}); } } my $CpuInfo = ""; if($Opt{"FixProbe"}) { $CpuInfo = readFile($FixProbe_Logs."/cpuinfo"); } elsif(enabledLog("cpuinfo") and -e "/proc/cpuinfo") { listProbe("logs", "cpuinfo"); $CpuInfo = readFile("/proc/cpuinfo"); $CpuInfo=~s/\n\n(.|\n)+\Z/\n/g; # for one core writeLog($LOG_DIR."/cpuinfo", $CpuInfo); } if(not $Sys{"Cores"}) { if($CpuInfo=~/siblings\s*:\s*(\d+)/) { my $Siblings = $1; if($CpuInfo=~/cpu cores\s*:\s*(\d+)/) { $CoresPerSocket = $1; $Sys{"Threads"} = $Siblings / $CoresPerSocket; if(my $TotalThreads = getDeviceCount($CPU_ID)) { $Sys{"Sockets"} = $TotalThreads/($CoresPerSocket*$Sys{"Threads"}); $Sys{"Cores"} = $Sys{"Sockets"}*$CoresPerSocket; } } } } if($CpuInfo) { my ($CPU_Vendor, $CPU_Family, $CPU_ModelNum) = (); foreach my $L (split(/\n/, $CpuInfo)) { $L=~s/\s*:\s*/:/; my @CpuAttr = split(":", $L); my $Attr = $CpuAttr[0]; my $Val = $CpuAttr[1]; if($Attr eq "vendor_id") { $CPU_Vendor = $Val; } elsif($Attr eq "cpu family") { $CPU_Family = $Val; } elsif($Attr eq "model") { $CPU_ModelNum = $Val; } elsif($Attr eq "cpu model") { if(not $CPU_ID and $Val=~s/\A(MIPS) //) { my %CpuDev = (); $CpuDev{"Vendor"} = fixCpuVendor($1); $CpuDev{"Device"} = $Val; $CpuDev{"Type"} = "cpu"; $CpuDev{"Status"} = "works"; $CPU_ID = "cpu:".fmtID(devID(nameID($CpuDev{"Vendor"}), $CpuDev{"Device"})); $HW{$CPU_ID} = \%CpuDev; } } elsif($Attr eq "machine") { if(not $Sys{"Vendor"} and $Val=~s/\A(TP-LINK) //) { $Sys{"Vendor"} = $1; $Sys{"Model"} = $Val; } } elsif($Attr eq "system type") { if(not $Board_ID and $Val=~s/\A(Qualcomm) //) { my %BoardDev = (); $BoardDev{"Vendor"} = $1; $BoardDev{"Device"} = $Val; $BoardDev{"Type"} = "motherboard"; $Board_ID = "board:".fmtID(devID(nameID($BoardDev{"Vendor"}), $BoardDev{"Device"})); $HW{$Board_ID} = \%BoardDev; } } } if(my $Microarch = detectMicroarch($CPU_Vendor, $CPU_Family, $CPU_ModelNum)) { $Sys{"Microarch"} = $Microarch; } } my $Cpuid = ""; if($Opt{"FixProbe"}) { $Cpuid = readFile($FixProbe_Logs."/cpuid"); } elsif(enabledLog("cpuid") and checkCmd("cpuid")) { listProbe("logs", "cpuid"); if(isBSD()) { $Cpuid = runCmd("cpuid 2>/dev/null"); $Cpuid = encryptSerials($Cpuid, "Processor serial"); if($Cpuid=~/usage: cpuid code/) { $Cpuid = ""; } } else { $Cpuid = runCmd("cpuid -1 2>/dev/null"); $Cpuid = encryptSerials($Cpuid, "serial number"); } writeLog($LOG_DIR."/cpuid", $Cpuid); } if($Cpuid and not $Lscpu and isBSD() and not $CPU_ID) { my %CpuDev = (); if($Cpuid=~/Vendor ID: "(.+?)"/) { $CpuDev{"Vendor"} = $1; } if($Cpuid=~/Extended brand string: "\s*(.+?)\s*"/) { $CpuDev{"Device"} = $1; } if($Cpuid=~/Family (\d+)/) { $CpuDev{"Family"} = $1; } if($Cpuid=~/Model (\d+)/) { $CpuDev{"ModelNum"} = $1; } if($Cpuid=~/Stepping (\d+)/) { $CpuDev{"Stepping"} = $1; } if($CpuDev{"Device"}) { $CPU_ID = registerCPU(\%CpuDev); if($CPU_ID and not getDeviceCount($CPU_ID) and $Cpuid=~/siblings: (\d+)/) { setDevCount($CPU_ID, "cpu", $1); } } if(my $Microarch = detectMicroarch($CpuDev{"Vendor"}, $CpuDev{"Family"}, $CpuDev{"ModelNum"}, $CpuDev{"Device"})) { $Sys{"Microarch"} = $Microarch; } } if(isNetBSD() and not $CPU_ID) { my @Cpus = $Dmesg=~/(cpu\d+ at \w+\d+: .+), id/g; foreach (@Cpus) { if(/cpu(\d+) at \w+\d+: ([^\s]+) (.+)/) { my ($CpuCount, $CpuVendor, $CpuDevice) = ($1, $2, $3); my %CpuDev = (); $CpuDev{"Vendor"} = $CpuVendor; $CpuDev{"Device"} = $CpuDevice; $CPU_ID = registerCPU(\%CpuDev); if($CPU_ID) { setDevCount($CPU_ID, "cpu", $CpuCount+1); } } } } if(isBSD() and not $CPU_ID) { if($Sysctl=~/hw.model\s*[:=]\s*(.+)/) { my $HWModel = $1; $HWModel=~s/\(R\)//g; if($HWModel=~/\A(Genuine Intel|[^\s]+) (.+)/) { my %CpuDev = (); $CpuDev{"Vendor"} = $1; $CpuDev{"Device"} = $2; $CpuDev{"Vendor"} = fmtVal($CpuDev{"Vendor"}); $CpuDev{"Device"} = fmtVal($CpuDev{"Device"}); $CPU_ID = registerCPU(\%CpuDev); if($CPU_ID and $Sysctl=~/hw.ncpu\s*[:=]\s*(\d+)/) { setDevCount($CPU_ID, "cpu", $1); } if(my $Microarch = detectMicroarch($CpuDev{"Vendor"}, undef, undef, $CpuDev{"Device"})) { $Sys{"Microarch"} = $Microarch; } } } } my $Meminfo = ""; if($Opt{"FixProbe"}) { $Meminfo = readFile($FixProbe_Logs."/meminfo"); } else { listProbe("logs", "meminfo"); $Meminfo = readFile("/proc/meminfo"); if($Meminfo) { writeLog($LOG_DIR."/meminfo", $Meminfo); } } if($Meminfo) { if($Meminfo=~/MemTotal:\s+(\d+) kB/) { $Sys{"Ram_total"} = $1; if($Meminfo=~/MemAvailable:\s+(\d+) kB/) { $Sys{"Ram_used"} = $Sys{"Ram_total"} - $1; } registerRAM($Sys{"Ram_total"}); } } my $Df = ""; if($Opt{"FixProbe"}) { $Df = readFile($FixProbe_Logs."/df"); } elsif(not $Opt{"Docker"} and enabledLog("df") and checkCmd("df")) { listProbe("logs", "df"); $Df = runCmd("df -Th 2>/dev/null"); if(not $Df) { # OpenBSD, NetBSD, FreeBSD < 8.0 $Df = runCmd("df -h 2>/dev/null"); } $Df = hidePaths($Df); $Df = hideIPs($Df); $Df = hideUrls($Df); $Df = encryptUUIDs($Df); $Df = hideDf($Df); writeLog($LOG_DIR."/df", $Df); } my ($SpaceTotal, $SpaceUsed) = (0.0, 0.0); my $NewDf = ""; if(index($Df, " Type ")!=-1) { $NewDf = "[^\\s]+\\s+"; } my $BsdDf = ""; if(isBSD()) { $BsdDf = "|[a-z]\\w+\\d|ufsid|gpt|ufs"; } foreach my $DfL (split(/\n/, $Df)) { if($DfL=~/\A\/dev\/([sh]d|nvme|mapper|mmcblk|root$BsdDf).*?\s+$NewDf([\w\.\,]+)\s+([\w\.\,]+)/) { my ($PSize, $PUsed) = ($2, $3); if($PSize) { $SpaceTotal += toGb($PSize); } if($PUsed) { $SpaceUsed += toGb($PUsed); } } } if(isBSD() and $Df=~/ zfs /) { if($Df=~/ zfs\s+([\w\.\,]+)\s+([\w\.\,]+).+?\/\n/) { my ($PSize, $PUsed) = ($1, $2); if($PSize) { $SpaceTotal = toGb($PSize); } if($PUsed) { $SpaceUsed = toGb($PUsed); } } } if($SpaceTotal and $SpaceUsed) { $Sys{"Space_total"} = roundFloat($SpaceTotal, 2); $Sys{"Space_used"} = roundFloat($SpaceUsed, 2); } if($NewDf and $Df=~/^[^\s]+[ \t]+([^\s\/]+)[ \t]+.*[ \t]+\/$/m) { if($1 ne "squashfs") { $Sys{"Filesystem"} = $1; } } $Sys{"Dual_boot"} = 0; $Sys{"Dual_boot_win"} = 0; if($Lsblk) { foreach my $Line (split(/\n/, $Lsblk)) { if($Line=~/\blive-/) { next; } if($Line=~/ (ext[234]) / and index($Line, "/")==-1) { $Sys{"Dual_boot"} = 1; } } if(index($Lsblk, " ntfs ")!=-1) { $Sys{"Dual_boot_win"} = 1; } if(index($Lsblk, " LABEL ")!=-1) { # old format if(index($Lsblk, "/snap/")!=-1) { if($Lsblk=~/^[^\s]+[ \t]+[^\s]+[ \t]+[^\s]+[ \t]+(\w+)[ \t]+.*\/var\/lib\/snapd\/hostfs[ \t]/m) { $Sys{"Filesystem"} = $1; } } else { if($Lsblk=~/^[^\s]+[ \t]+[^\s]+[ \t]+[^\s]+[ \t]+(\w+)[ \t]+.*\/[ \t]/m) { $Sys{"Filesystem"} = $1; } } } else { if(index($Lsblk, "/snap/")!=-1) { if($Lsblk=~/(\w+)\s+[a-f\d\-]+\s+\/var\/lib\/snapd\/hostfs\s/) { $Sys{"Filesystem"} = $1; } } else { if($Lsblk=~/(\w+)\s+[a-f\d\-]+\s+\/\s/) { $Sys{"Filesystem"} = $1; } } } if(isBSD()) { # TODO: detect fs } } my $Findmnt = ""; if($Opt{"FixProbe"}) { $Findmnt = readFile($FixProbe_Logs."/findmnt"); } elsif(not $Opt{"Docker"} and enabledLog("findmnt") and checkCmd("findmnt")) { listProbe("logs", "findmnt"); my $FindmntCmd = "findmnt"; if($Opt{"Flatpak"}) { $FindmntCmd .= " 2>/dev/null"; } else { $FindmntCmd .= " 2>&1"; } $Findmnt = runCmd($FindmntCmd); if($Opt{"Snap"} and $Findmnt=~/Permission denied/) { $Findmnt = ""; } $Findmnt=~s/\[[^\s]+\]/[XXXXX]/g; $Findmnt = hidePaths($Findmnt); $Findmnt = hideIPs($Findmnt); $Findmnt = hideUrls($Findmnt); writeLog($LOG_DIR."/findmnt", $Findmnt); } my $Fstab = ""; if($Opt{"FixProbe"}) { $Fstab = readFile($FixProbe_Logs."/fstab"); $Fstab=~s/#.*\n//g; } elsif(not $Opt{"Docker"} and enabledLog("fstab")) { listProbe("logs", "fstab"); $Fstab = readFile("/etc/fstab"); $Fstab = hidePaths($Fstab); $Fstab = hideIPs($Fstab); $Fstab = hideUrls($Fstab); $Fstab = hidePass($Fstab); $Fstab = encryptUUIDs($Fstab); $Fstab=~s/LABEL=[^\s]+/LABEL=XXXX/g; $Fstab=~s/sshfs#.+/sshfs.../g; $Fstab=~s/#.*\n//g; writeLog($LOG_DIR."/fstab", $Fstab); } my $LocaleConf = ""; if($Opt{"FixProbe"}) { $LocaleConf = readFile($FixProbe_Logs."/locale"); } elsif(enabledLog("locale")) { listProbe("logs", "locale"); if(isBSD()) { if(checkCmd("locale")) { $LocaleConf = runCmd("locale"); } } else { $LocaleConf = readFile("/etc/locale.conf"); } if($LocaleConf) { writeLog($LOG_DIR."/locale", $LocaleConf); } } if(not $Sys{"Lang"}) { if($LocaleConf=~/LANG="(.+)"/) { $Sys{"Lang"} = $1; } elsif($LocaleConf=~/LANG=(.+)/) { $Sys{"Lang"} = $1; } } my $Mount = ""; if($Opt{"FixProbe"}) { $Mount = readFile($FixProbe_Logs."/mount"); } elsif(not $Opt{"Docker"} and enabledLog("mount") and checkCmd("mount")) { listProbe("logs", "mount"); $Mount = runCmd("mount -v 2>&1 | column -t"); if($Opt{"Snap"} and $Mount=~/Permission denied/) { $Mount = ""; } $Mount = hidePaths($Mount); $Mount = hideIPs($Mount); $Mount = hideUrls($Mount); writeLog($LOG_DIR."/mount", $Mount); } if(not $Sys{"Filesystem"}) { if($Fstab=~/\s+\/\s+([^\s]+)\s+/) { if($1 ne "auto") { $Sys{"Filesystem"} = $1; } } } if(not $Sys{"Filesystem"}) { if($Mount=~/\s+on\s+(\/|\/usr)\s+type\s+([^\s]+)/) { $Sys{"Filesystem"} = $2; } } if(not $Sys{"Filesystem"}) { my @Filesystems = ("btrfs", "jfs", "reiserfs", "xfs", "zfs", "aufs", "ext[234]", "overlay", "hammer2", "ufs", "ffs"); LOOP: foreach my $Log ($Df, $Lsblk, $Findmnt) { foreach my $Fs (@Filesystems) { if($Log=~/\s+($Fs)\s+/) { $Sys{"Filesystem"} = $1; last LOOP; } } } } if(isBSD()) { if(not $Sys{"Filesystem"}) { if($Sysctl=~/vfs\.mounts\.ffs has [1-9]/) { $Sys{"Filesystem"} = "ffs"; } } if(not $Sys{"Filesystem"}) { if($Disklabel=~/ 4\.2BSD /) { $Sys{"Filesystem"} = "ufs"; } } if(not $Sys{"Filesystem"}) { if($Dmesg=~/(root file system type:|mount root from)\s+(\w+)/) { $Sys{"Filesystem"} = $2; if($Sys{"Filesystem"} eq "ffs") { $Sys{"Filesystem"} = "ufs"; } } } } my $XInput = ""; if($Opt{"FixProbe"}) { $XInput = readFile($FixProbe_Logs."/xinput"); } elsif(enabledLog("xinput") and checkCmd("xinput")) { listProbe("logs", "xinput"); $XInput = runCmd("xinput list --long 2>&1"); writeLog($LOG_DIR."/xinput", clearLog_X11($XInput)); } if($XInput=~/xwayland/i) { $Sys{"Display_server"} = "Wayland"; } my $BootLog = ""; if($Opt{"FixProbe"}) { $BootLog = readFile($FixProbe_Logs."/boot.log"); } elsif(enabledLog("boot.log") and -f "/var/log/boot.log" and -s "/var/log/boot.log" < $MAX_LOG_SIZE*50) { listProbe("logs", "boot.log"); $BootLog = clearLog(readFile("/var/log/boot.log")); $BootLog=~s&(Mounted|Mounting)\s+/.+&$1 XXXXX&g; $BootLog=~s&(Setting hostname\s+).+:&$1XXXXX:&g; $BootLog=~s&(File System Check on) .+&$1 XXX&g; $BootLog=~s& [^\s]+ (NET\[)& XXX $1&g; $BootLog = hideLVM($BootLog); $BootLog = encryptUUIDs($BootLog); $BootLog = hideDevDiskUUIDs($BootLog); writeLog($LOG_DIR."/boot.log", $BootLog); } if(not $Sys{"System"} or $Sys{"System"}=~/freedesktop/) { if($BootLog=~/Endless OS/) { $Sys{"System"} = "endless"; $Sys{"System_version"} = undef; } } my $Sctl = ""; if($Opt{"FixProbe"}) { $Sctl = readFile($FixProbe_Logs."/systemctl"); } elsif(not $Opt{"Docker"} and enabledLog("systemctl") and checkCmd("systemctl")) { listProbe("logs", "systemctl"); if($Sctl = runCmd("systemctl 2>/dev/null")) { $Sctl = hideByRegexp($Sctl, qr/\/home\/([^\s]+)/); $Sctl = hideByRegexp($Sctl, qr/\/media\/([^\s]+)/); $Sctl = hideByRegexp($Sctl, qr/home-([^\s]+)/); $Sctl = hideByRegexp($Sctl, qr/media-([^\s]+)/); $Sctl = hideByRegexp($Sctl, qr/ cluster ([^\s]+)/); $Sctl = hidePaths($Sctl); $Sctl=~s/(User Slice of|Session \d+ of user|Synchronization for).+/$1 XXXXX/g; if(my $SessUser = getUser()) { $Sctl=~s/( of user)\s+\Q$SessUser\E/$1 USER/g; $Sctl=~s/\@$SessUser\./\@USER\./g; } $Sctl = decorateSystemd($Sctl); $Sctl = encryptUUIDs($Sctl); $Sctl = hideDevDiskUUIDs($Sctl); writeLog($LOG_DIR."/systemctl", $Sctl); } } if((not $Sys{"Display_manager"} or $Sys{"Display_manager"} eq "TDM") and $Sctl) { foreach my $DM (@ALL_DISPLAY_MANAGERS) { if(index($Sctl, $DM.".service")!=-1 and $Sctl=~/\b$DM\.service\s+loaded.+\s+running/) { $Sys{"Display_manager"} = fixDisplayManager($DM); last; } } } my $Gpart = ""; if($Opt{"FixProbe"}) { $Gpart = readFile($FixProbe_Logs."/gpart"); } elsif(enabledLog("gpart") and checkCmd("gpart")) { listProbe("logs", "gpart"); $Gpart = runCmd("gpart show 2>/dev/null"); $Gpart = hidePaths($Gpart); writeLog($LOG_DIR."/gpart", $Gpart); } if(isBSD() and $Gpart) { if($Gpart=~/ efi /) { $Sys{"Boot_mode"} = "EFI"; } else { $Sys{"Boot_mode"} = "BIOS"; } if($Gpart=~/ GPT /) { $Sys{"Part_scheme"} = "GPT"; } elsif($Gpart=~/ MBR /) { $Sys{"Part_scheme"} = "MBR"; } elsif($Gpart=~/ BSD /) { $Sys{"Part_scheme"} = "BSD"; } } if(enabledLog("gpart_list") and checkCmd("gpart")) { listProbe("logs", "gpart_list"); my $GpartList = runCmd("gpart list -a 2>/dev/null"); $GpartList = hidePaths($GpartList); $GpartList = encryptUUIDs($GpartList); if($GpartList) { writeLog($LOG_DIR."/gpart_list", $GpartList); } } my $Fdisk = ""; if($Opt{"FixProbe"}) { $Fdisk = readFile($FixProbe_Logs."/fdisk"); } elsif(enabledLog("fdisk") and checkCmd("fdisk") and (isOpenBSD() or isNetBSD())) { listProbe("logs", "fdisk"); foreach my $Dev (sort keys(%HDD)) { if($Dev=~/[dc]\Z/) { next; } if(my $FdiskDev = runCmd("fdisk -v ".basename($Dev)." 2>/dev/null")) { $Fdisk .= "$Dev\n".$FdiskDev."\n\n"; } } if($Fdisk) { $Fdisk = encryptUUIDs($Fdisk); writeLog($LOG_DIR."/fdisk", $Fdisk); } } if(isBSD() and $Fdisk) { if($Fdisk=~/ EFI /) { $Sys{"Boot_mode"} = "EFI"; } else { $Sys{"Boot_mode"} = "BIOS"; } foreach (split(/\n\n/, $Fdisk)) { if(/Not Found/) { next; } if(/GPT:| GPT /) { $Sys{"Part_scheme"} = "GPT"; last; } elsif(/MBR:| MBR /) { $Sys{"Part_scheme"} = "MBR"; last; } } } if($Fdisk=~/Disk\s?label type: gpt/) { $Sys{"Part_scheme"} = "GPT"; } elsif($Fdisk=~/Disk\s?label type: dos/) { $Sys{"Part_scheme"} = "MBR"; } my $X86info = ""; if($Opt{"FixProbe"}) { $X86info = readFile($FixProbe_Logs."/x86info"); } elsif(enabledLog("x86info") and checkCmd("x86info")) { listProbe("logs", "x86info"); $X86info = runCmd("x86info -a 2>/dev/null"); if($X86info) { writeLog($LOG_DIR."/x86info", $X86info); } } my $Getprop = ""; if($Opt{"FixProbe"}) { $Getprop = readFile($FixProbe_Logs."/getprop"); } elsif(enabledLog("getprop") and checkCmd("getprop")) { # Android (Termux) listProbe("logs", "getprop"); $Getprop = runCmd("getprop"); if($Getprop) { writeLog($LOG_DIR."/getprop", $Getprop); } } my $Ofwdump = ""; if($Opt{"FixProbe"}) { $Ofwdump = readFile($FixProbe_Logs."/ofwdump"); } elsif(defined $Sys{"Freebsd_release"} and enabledLog("ofwdump") and checkCmd("ofwdump")) { listProbe("logs", "ofwdump"); $Ofwdump = runCmd("ofwdump -a"); writeLog($LOG_DIR."/ofwdump", $Ofwdump); } # TODO: add new fixes here print "Ok\n"; } sub identifyVideoDriver_BSD($$) { my ($Driver, $File) = @_; if($File!~/vgapci/ or not defined $DrmAttached{$File}) { return $Driver; } my %VgaDr = (); $VgaDr{$Driver} = 1; foreach my $DrmFile (sort keys(%{$DrmAttached{$File}})) { if($DrmFile=~/drm/) { foreach my $DrmDrv (sort keys(%{$DrmAttached{$DrmFile}})) { $VgaDr{$DrmDrv} = 1; } } else { $DrmFile=~s/\d+\Z//; $VgaDr{$DrmFile} = 1; } } if(defined $VgaDr{"i915"}) { $Driver = "i915"; } elsif(defined $VgaDr{"radeon"}) { $Driver = "radeon"; } elsif(defined $VgaDr{"amdgpu"}) { $Driver = "amdgpu"; } elsif(defined $VgaDr{"nvidia"}) { $Driver = "nvidia"; } elsif(defined $VgaDr{"agp"}) { $Driver = "agp"; } else { $Driver = join(", ", keys(%VgaDr)); } return $Driver; } sub getSysUUID(@) { return strToUUID(clientHash("_".join("_", sort @_))); } sub detectMicroarch(@) { my $V = shift(@_); my $F = shift(@_); my $M = shift(@_); my $N = undef; if(@_) { $N = shift(@_); } $V = fixCpuVendor($V); if($V and $F) { if(defined $FamilyMicroArch{$V}{$F}{$M}) { return $FamilyMicroArch{$V}{$F}{$M}; } elsif(defined $FamilyMicroArch{$V}{$F}{"*"}) { return $FamilyMicroArch{$V}{$F}{"*"}; } } if($V and $N) { if(defined $ModelMicroArch{$V}{$N}) { return $ModelMicroArch{$V}{$N}; } } return undef; } sub getLongPCI($) { my $ID = $_[0]; if(not defined $LongID{$ID}) { return undef; } my @L_IDs = keys(%{$LongID{$ID}}); if($#L_IDs==0) { return $L_IDs[0]; } return undef; } sub runSmartctl(@) { my $SmartctlCmd = shift(@_); my $Id = shift(@_); my $Dev = shift(@_); my $OrigDev = shift(@_); my ($Raid, $AddOpt, $RNum) = (); if(@_) { $Raid = shift(@_); } if(@_) { $AddOpt = shift(@_); } if(@_) { $RNum = shift(@_); } my $Cmd = $SmartctlCmd." -x \"".$Dev."\""; if(isBSD()) { if(not defined $Sys{"Freebsd_release"} or $Sys{"Freebsd_release"} < 7.0) { $Cmd = $SmartctlCmd." -a \"".$Dev."\""; } } if($AddOpt) { $Cmd .= " ".$AddOpt; } my $Output = undef; if($Sys{"System"}=~/dragonfly/) { $Output = runCmd($Cmd." -d sat 2>/dev/null"); } else { $Output = runCmd($Cmd." 2>/dev/null"); } if($Output=~/Unknown USB bridge|Device Identity failed|Unable to detect device type|failed: Device busy|To monitor NVMe disks use/) { return ""; } if(not $Output or $Output=~/Operation not permitted|Permission denied/) { if($Opt{"Snap"} and not $SnapNoBlockDevices) { print STDERR "\nWARNING: Make sure 'block-devices' interface is connected to verify SMART attributes of your drives:\n\n"; print STDERR " sudo snap connect hw-probe:block-devices :block-devices\n"; $SnapNoBlockDevices = 1; } return ""; } if(isBSD() and $Output=~/No such file|Device not configured|Operation not supported/) { return ""; } if($Raid) { if(index($Output, "failed: cannot open")!=-1 or index($Output, "INQUIRY failed")!=-1 or index($Output, "Input/output error")!=-1) { # empty N slot return ""; } } if($Id and index($Id, "usb:")==0 and $Output=~/Unsupported USB|Unknown USB/i) { # device doesn't provide SMART return ""; } if($Id and index($Id, "nvme:")==0 and $Output=~/Unable to detect device type/i) { # old version of smartctl return ""; } if($Id and index($Id, "scsi:")==0 and $Output=~/Unsupported|Unknown|Unable/i) { # unsupported scsi drive return ""; } $Output = encryptSerials($Output, "Serial Number"); $Output = encryptSerials($Output, "Serial number"); $Output = hideWWNs($Output); if(not $Id) { $Id = detectDrive($Output, $OrigDev, $Raid, $RNum); } if($Id) { setDriveStatus($Output, $Id); } if($Raid and $Raid eq "MegaRAID") { $Output = $OrigDev.",megaraid_disk_".fNum($RNum)."\n".$Output."\n"; } elsif($Raid and $Raid eq "HPSA") { $Output = $OrigDev.",hpsa_disk_".fNum($RNum)."\n".$Output."\n"; } else { $Output = $OrigDev."\n".$Output."\n"; } return $Output; } sub registerCPU($) { my $Device = $_[0]; $Device->{"Vendor"} = fixCpuVendor($Device->{"Vendor"}); $Device->{"Device"} = fmtVal($Device->{"Device"}); $Device->{"Device"} = duplVendor($Device->{"Vendor"}, $Device->{"Device"}); $Device->{"Type"} = "cpu"; $Device->{"Status"} = "works"; $CPU_ID = "cpu:".fmtID(devID(nameID($Device->{"Vendor"}), join(".", ($Device->{"Family"}, $Device->{"ModelNum"}, $Device->{"Stepping"})), devSuffix($Device))); $HW{$CPU_ID} = $Device; return $CPU_ID; } sub registerRAM($) { my $TotalKb = $_[0]; if(grep {$_=~/\Amem:/} keys(%HW)) { return undef; } my %Device = (); $Device{"FF"} = "DIMM"; if($Sys{"Type"}=~/$MOBILE_TYPE/) { $Device{"FF"} = "SODIMM"; } $Device{"Type"} = "memory"; $Device{"Status"} = "works"; $Device{"Size"} = sprintf("%.0f", $TotalKb/1048576); if(grep {$_ eq $Device{"Size"}} (63, 47, 31, 15, 7)) { $Device{"Size"} += 1; } $Device{"Size"} .= "GB"; if($Device{"Size"} eq "0GB") { $Device{"Size"} = sprintf("%.2f", $TotalKb/1048576)."GB"; } $Device{"Device"} = "RAM Module(s) ".$Device{"Size"}." ".$Device{"FF"}; my $RAM_ID = "mem:ram-modules-".lc($Device{"Size"})."-".lc($Device{"FF"}); $HW{$RAM_ID} = \%Device; return $RAM_ID; } sub registerCdrom($$) { my ($Descr, $DevFile) = @_; my %CDDev = (); $CDDev{"Device"} = $Descr; $CDDev{"Vendor"} = guessDeviceVendor($CDDev{"Device"}); $CDDev{"Device"} = duplVendor($CDDev{"Vendor"}, $CDDev{"Device"}); $CDDev{"Type"} = "cdrom"; $CDDev{"Status"} = "detected"; $CDDev{"File"} = $DevFile; my @Dr = (); if($DevFile=~/\A(cd|acd)\d\Z/) { @Dr = ($1); } if(my $ADr = $DevAttached{$DevFile}) { $ADr=~s/\d+\Z//; push(@Dr, $ADr); } if(@Dr) { $CDDev{"Driver"} = join(", ", @Dr); } $CDROM_ID = "scsi:".fmtID(devID(nameID($CDDev{"Vendor"}), $CDDev{"Device"})); $HW{$CDROM_ID} = \%CDDev; } sub registerBattery($) { my $Device = $_[0]; $Device->{"Type"} = "battery"; if(not $Sys{"Type"} or $Sys{"Type"}=~/$DESKTOP_TYPE|$SERVER_TYPE|other/) { if(not grep {$Sys{"Type"} eq $_} ("mini pc", "all in one") and $Device->{"Device"}!~/CRB/) { $Sys{"Type"} = "notebook"; } } if(defined $BatType{$Device->{"Technology"}}) { $Device->{"Technology"} = $BatType{$Device->{"Technology"}}; } if($Device->{"Technology"} eq "Unknown") { $Device->{"Technology"} = undef; } if(not $Device->{"Device"}) { $Device->{"Device"} = "Battery"; } if($Device->{"Size"}=~/(.+)( Wh)/) { $Device->{"Size"} = sprintf("%.1f", $1).$2; } if($Device->{"Size"} eq "0.0 Wh") { $Device->{"Size"} = undef; } my $ID = undef; if($Device->{"Device"}=~/\A(Battery|Primary|Dell|Bat)\d*\Z/i or not $Device->{"Vendor"}) { $Device->{"Device"} = $1; if($Device->{"Size"}=~/(.+)( Wh)/) { $Device->{"Size"} = sprintf("%.0f", $1).$2; } $ID = devID(nameID($Device->{"Vendor"}), lc($Device->{"Device"}), $Device->{"Technology"}, $Device->{"Size"}); if($Device->{"Serial"} and $Device->{"Serial"} ne " ") { $ID = devID($ID, "serial", $Device->{"Serial"}); } } else { $ID = devID(nameID($Device->{"Vendor"}), devSuffix($Device)); $Device->{"Device"} = "Battery ".$Device->{"Device"}; } $ID = fmtID($ID); if($Device->{"Technology"}) { $Device->{"Device"} .= " ".$Device->{"Technology"}; } if($Device->{"Size"}) { $Device->{"Device"} .= " ".$Device->{"Size"}; } if($Device->{"Capacity"}=~/\A(\d+)/) { if($1>$MIN_BAT_CAPACITY) { $Device->{"Status"} = "works"; } else { $Device->{"Status"} = "malfunc"; } } if($ID) { $HW{"bat:".$ID} = $Device; } } sub rmArrayVal($$) { my ($Arr, $Vals) = @_; foreach my $Val (@{$Vals}) { @{$Arr} = grep {$_ ne $Val} @{$Arr}; } } sub fixCapacity($) { my $Capacity = $_[0]; if($Capacity=~/\A([\d\.]+)GB\Z/) { my $Gb = $1; if($Gb=~/\./) { $Gb = roundToNearest($Gb); } if($Gb>24 and $Gb % 16 != 0) { my $Nearest = int(($Gb + 15)/16)*16; if($Nearest-$Gb<=5) { $Gb = $Nearest; } } elsif($Gb=~/\A1[345]\Z/) { $Gb = 16; } elsif($Gb==23) { $Gb = 24; } return $Gb."GB"; } return $Capacity; } sub isIntelDriver($) { return grep {$_[0] eq $_} @G_DRIVERS_INTEL; } sub setDriveStatus($$) { my ($Desc, $Id) = @_; my $Status = undef; if($Desc=~/result:\s*(PASSED|FAILED)/i) { my $Res = $1; if($Res eq "PASSED") { $Status = "works"; } elsif($Res eq "FAILED") { $Status = "failed"; } } elsif($Desc=~/SMART Health Status:\s*(.+)/i) { my $Res = $1; if($Res eq "OK") { $Status = "works"; } elsif($Res=~/FAIL/) { $Status = "failed"; } } if($Status) { $HW{$Id}{"Status"} = $Status; } if($USE_IA) { LHW::IA::parseSMART($Desc, $HW{$Id}); } setAttachedStatus($Id, "works"); # got SMART } sub setAttachedStatus(@) { my $Id = shift(@_); my $Status = shift(@_); if(isBSD()) { my %DevID = (); foreach (keys(%HW)) { if(defined $HW{$_} and defined $HW{$_}{"File"}) { $DevID{$HW{$_}{"File"}} = $_; } } if(my $File = $HW{$Id}{"File"}) { foreach my $Parent (keys(%{$DevAttachedRecursive{$File}})) { if(defined $DevID{$Parent}) { $HW{$DevID{$Parent}}{"Status"} = $Status; } } } return; } my $Recur = {}; if(@_) { $Recur = shift(@_); } if(defined $Recur->{$Id}) { return; } $Recur->{$Id} = 1; if(my $DevNum = $DeviceNumByID{$Id}) { if(my $AttachedTo = $DeviceAttached{$DevNum}) { if(my $AttachedId = $DeviceIDByNum{$AttachedTo}) { if(my $L_ID = getLongPCI($AttachedId)) { $AttachedId = "pci:".$L_ID; } $HW{$AttachedId}{"Status"} = $Status; if($Status eq "works") { setAttachedStatus($AttachedId, $Status, $Recur); } } } } } sub shortModel($) { my $M = $_[0]; $M=~s/\AMotherboard\s+//gi; $M=~s/\s+\Z//g; $M=~s/\s*\(.+\)//g; $M=~s/\s+Rev\s+.+//ig; $M=~s/\s+REV\:[^\s]+//ig; # REV:0A $M=~s/(\s+|\/)[x\d]+\.[x\d]+//i; $M=~s/\s*[\.\*]\Z//; $M=~s/\s*\d\*.*//; # Motherboard C31 1*V1.* $M=~s/\s+(Unknow|INVALID|Default string)\Z//; $M=~s/\s+Board\Z//g; # $M=~s/\s+R\d+\.\d+\Z//ig; # R2.0 return $M; } sub shortOS($) { my $Name = $_[0]; $Name=~s/\s+(linux|project|amd64|x86_64)\s+/ /i; $Name=~s/\s*(linux|project|amd64|x86_64)\Z//i; $Name=~s/\s+/\-/g; $Name=~s/\.\Z//g; return $Name; } sub registerBoard($) { my $Device = $_[0]; $Device->{"Vendor"}=~s{\Ahttp://www\.}{}i; # http://www.abit.com.tw as vendor if(index($Device->{"Vendor"}, "abit.com.tw")!=-1) { $Device->{"Vendor"} = "ABIT"; } cleanValues($Device); if(emptyProduct($Device->{"Version"})) { delete($Device->{"Version"}); } if($Device->{"Device"}=~/\bName\d*\b/i) { $Device->{"Device"} = "Board"; } if(my $Ver = $Device->{"Version"}) { $Device->{"Device"} .= " ".$Ver; } $Device->{"Device"} = duplVendor($Device->{"Vendor"}, $Device->{"Device"}); $Device->{"Type"} = "motherboard"; $Device->{"Status"} = "works"; if(not $Device->{"Vendor"} and not $Device->{"Device"}) { return undef; } if($Device->{"Device"}) { if(not $Device->{"Vendor"}) { $Device->{"Vendor"} = $VendorByModel{shortModel($Device->{"Device"})}; } if(not $Device->{"Vendor"}) { if($Device->{"Device"}=~/\AMS\-\d+\Z/) { $Device->{"Vendor"} = "MSI"; } elsif($Device->{"Device"}=~/\ASiS\-\d+/) { $Device->{"Vendor"} = "SiS Technology"; } elsif($Device->{"Device"}=~/\A(4CoreDual|4Core1600|775XFire|ALiveNF|ConRoe[A-Z\d])/) { # ConRoe1333, ConRoeXFire $Device->{"Vendor"} = "ASRock"; } } } else { $Device->{"Device"} = "Board"; } my $ID = devID(nameID($Device->{"Vendor"}), devSuffix($Device)); $ID = fmtID($ID); if($Device->{"Device"} ne "Board") { $Device->{"Device"} = "Motherboard ".$Device->{"Device"}; } my $MID = "board:".$ID; $HW{$MID} = $Device; return $MID; } sub registerBIOS($) { my $Device = $_[0]; cleanValues($Device); my @Name = (); if($Device->{"Version"}) { push(@Name, $Device->{"Version"}); } if(my $BiosDate = $Device->{"Release Date"}) { push(@Name, $Device->{"Release Date"}); if($BiosDate=~/\b(19\d\d|20\d\d)\b/) { $Sys{"Year"} = $1; } elsif($BiosDate=~/\b\d\d\/\d\d\/([01]\d)\b/) { $Sys{"Year"} = "20".$1; } else { delete($Sys{"Year"}); } if($Sys{"Year"} and ($Sys{"Year"} > getYear(time) + 1 or $Sys{"Year"} < 1993)) { delete($Sys{"Year"}); } } $Device->{"Device"} = join(" ", @Name); if(not $Device->{"Vendor"} or not $Device->{"Device"}) { return undef; } $Device->{"Type"} = "bios"; $Device->{"Status"} = "works"; my $ID = devID(nameID($Device->{"Vendor"}), devSuffix($Device)); $ID = fmtID($ID); my $BusID = "bios:".$ID; $Device->{"Device"} = "BIOS ".$Device->{"Device"}; if($ID) { $HW{"bios:".$ID} = $Device; return $BusID; } return undef; } sub detectMonitor($) { my $Info = $_[0]; my ($V, $D) = (); my %Device = (); if($Info=~/Digital display/) { $Device{"Kind"} = "Digital"; } elsif($Info=~/Analog display/) { $Device{"Kind"} = "Analog"; } if($Info=~/Made in:? (.+)/) { $Device{"Made"} = $1; } if($Info=~/Manufacturer:\s*(.+?)\s+Model\s+(.+?)\s+Serial/) { ($V, $D) = ($1, $2); } elsif($Info=~/EISA ID:\s*(\w{3})(\w+)/) { ($V, $D) = (uc($1), uc($2)); } if(not $V and not $D) { # edid-decode 2020 if($Info=~/Manufacturer:\s*(.+)/) { $V = $1; } if($Info=~/Model:\s*(.+)/) { $D = $1; } if($Info=~/Product Serial Number:\s*(.+)/) { $Device{"Serial"} = $1; $Device{"Serial"}=~s/\A\'(.+)\'\Z/$1/; } } if($D=~/\A\d+\Z/ and $Info!~/\(valid\)/) { # new format by edid-decode c498d2224d (2019-11-30) # revert to HEX $D = sprintf('%x', $D); } if(length($D)<4) { foreach (1 .. 4 - length($D)) { $D = "0".$D; } } if(not $V or not $D) { return; } if($V eq "\@\@\@") { return; } if($Info=~/(Monitor name|Display Product Name):[ ]*(.*?)(\n|\Z)/) { $Device{"Device"} = $2; } else { # if($Info=~s/(ASCII string|Alphanumeric Data String):\s*(.*?)(\n|\Z)//) # { # broken data # if($Info=~s/(ASCII string|Alphanumeric Data String):\s*(.*?)(\n|\Z)//) # { # $Device{"Device"} = $2; # } # } } $Device{"Device"}=~s/\A\'(.+)\'\Z/$1/; foreach my $Attr ("Maximum image size", "Screen size", "Detailed mode", "DTD 1", "DTD 2") { if($Info=~/$Attr:(.+?)\n/i) { my $MonSize = $1; if($MonSize=~/(\d+)\s*mm\s*x\s*(\d+)\s*mm/) { $Device{"Size"} = $1."x".$2."mm"; } elsif($MonSize=~/([\d\.]+)\s*cm\s*x\s*([\d\.]+)\s*cm/) { $Device{"Size"} = ($1*10)."x".($2*10)."mm"; } if($Device{"Size"}) { last; } } } if(grep {$Device{"Size"} eq $_} ("1600x900mm", "160x90mm", "16x9mm", "0x0mm")) { $Device{"Size"} = undef; } $Info=~s/(CTA extension block|CTA-861 Extension Block|CEA extension block).+//s; my %Resolutions = (); while($Info=~s/(\d+)x(\d+)\@\d+//) { $Resolutions{$1} = $2; } while($Info=~s/\n\s+(\d+)\s+.+?\s+hborder//) { my $W = $1; if($Info=~s/\n\s+(\d+)\s+.+?\s+vborder//) { my $H = $1; if(not defined $Resolutions{$W} or $H>$Resolutions{$W}) { $Resolutions{$W} = $H; } } } if(not keys(%Resolutions)) { # edid-decode 2020 while($Info=~s/ (\d+)x(\d+) //) { $Resolutions{$1} = $2; } } if(my @Res = sort {int($b)<=>int($a)} keys(%Resolutions)) { $Device{"Resolution"} = $Res[0]."x".$Resolutions{$Res[0]}; } if(not $Device{"Resolution"}) { # monitor-parse-edid if($Info=~s/"(\d+x\d+)"//) { $Device{"Resolution"} = $1; } } if($V) { if(my $Vendor = getPnpVendor($V)) { $Device{"Vendor"} = $Vendor; $Device{"Device"}=~s/\A\Q$Vendor\E(\s+|\-)//ig; } elsif(not $Device{"Vendor"}) { $Device{"Vendor"} = $V; } } my $MName = $Device{"Device"}; if(not $MName or $Device{"Vendor"}=~/\Q$MName\E/i) { $Device{"Device"} = "LCD Monitor"; } my $ID = undef; if($Device{"Vendor"}) { if($Device{"Vendor"} ne $V) { $ID = devID(nameID($Device{"Vendor"})); } } $ID = devID($ID, $V.$D); $ID = fmtID($ID); if(my $OldID = $Monitor_ID{uc($V.$D)}) { my $OldID_F = "eisa:".$OldID; my $Name = $Device{"Device"}; if($Name ne "LCD Monitor") { if($HW{$OldID_F}{"Vendor"}!~/\Q$Name\E/i) { $HW{$OldID_F}{"Device"}=~s/LCD Monitor/$Name/; } } $HW{$OldID_F}{"Status"} = "works"; # got EDID if(my $Res = $Device{"Resolution"}) { $HW{$OldID_F}{"Device"}=~s/ \d+x\d+ / $Res /; } return; } if($D) { $Device{"Device"} .= " ".uc($V.$D); } if($Device{"Resolution"}) { $Device{"Device"} .= " ".$Device{"Resolution"}; } if($Device{"Size"}) { $Device{"Device"} .= " ".$Device{"Size"}; } if(my $Inches = computeInch($Device{"Size"})) { $Device{"Inches"} = sprintf("%.1f", $Inches); $Device{"Device"} .= " ".$Device{"Inches"}."-inch"; if(my $Density = computeDensity($Device{"Resolution"}, $Inches)) { $Device{"Density"} = roundFloat($Density, 1); } if(my $Ratio = computeRatio($Device{"Size"})) { $Device{"Ratio"} = $Ratio; } if(my $Area = computeArea($Device{"Size"})) { $Device{"Area"} = $Area; } if($Device{"Size"}=~/\A(\d+)/) { $Device{"Width"} = $1; } } if(not $Device{"Ratio"}) { if(my $RatioByRes = computeRatio($Device{"Resolution"})) { $Device{"Ratio"} = $RatioByRes; } } $Device{"Type"} = "monitor"; if($Opt{"IdentifyMonitor"}) { $Device{"Vendor"} = nameID($Device{"Vendor"}); if(not defined $MonVendor{$V}) { $Device{"Unknown"} = 1; } } if($ID) { if(not defined $HW{"eisa:".$ID}) { $HW{"eisa:".$ID} = \%Device; $HW{"eisa:".$ID}{"Status"} = "works"; # got EDID } } } sub detectDrive(@) { my $Desc = shift(@_); my $Dev = shift(@_); my $Raid = undef; my $RNum = undef; if(@_) { $Raid = shift(@_); } if(@_) { $RNum = shift(@_); } my $Device = { "Type"=>"disk" }; if($Raid) { $Device->{"RAID"} = $Raid; if($Raid eq "MegaRAID") { $Device->{"MegaRAID_Disk"} = fNum($RNum); } elsif($Raid eq "HPSA") { $Device->{"HPSA_Disk"} = fNum($RNum); } $Device->{"File"} = $Dev; $Dev .= ",".fNum($RNum); } my $Bus = "ide"; # SATA, PATA, M.2, mSATA, etc. if($Dev=~/\A(nvme|nvd|nda)/) { $Bus = $PCI_DISK_BUS; $Device->{"Kind"} = "NVMe"; } if(not $Opt{"IdentifyDrive"} and not $Raid and defined $HDD_Info{$Dev}) { foreach ("Capacity", "Driver", "File") { $Device->{$_} = $HDD_Info{$Dev}{$_}; } } if($Desc=~/Serial [Nn]umber:\s*(.+?)(\Z|\n)/) { $Device->{"Serial"} = $1; } if($Desc=~/Device Model:\s*(.+?)(\Z|\n)/) { # ATA $Device->{"Device"} = $1; } elsif($Desc=~/Model Number:\s*(.+?)(\Z|\n)/) { # NVMe $Device->{"Device"} = $1; } elsif($Desc=~/Product:\s*(.+?)(\Z|\n)/) { # SAS $Device->{"Device"} = $1; } if($Desc=~/Model Family:\s*(.+?)(\Z|\n)/) { $Device->{"Family"} = $1; } if($Desc=~/Firmware Version:\s*(.+?)(\Z|\n)/) { $Device->{"Firmware"} = $1; } if($Desc=~/Form Factor:\s*(.+?)(\Z|\n)/) { # ATA $Device->{"FF"} = $1; } if($Desc=~/LU WWN Device Id:\s*\w\s(\w{6})\s(\w+|\.\.\.)(\Z|\n)/) { $Device->{"IEEE_OUI"} = $1; } elsif($Desc=~/IEEE OUI Identifier:\s*0x(\w+)/) { $Device->{"IEEE_OUI"} = $1; } elsif($Desc=~/IEEE EUI-64:\s*(\w{6})\s(\w+|\.\.\.)(\Z|\n)/) { $Device->{"IEEE_OUI"} = $1; } if(not $Device->{"Kind"}) { if($Desc=~/NVM Commands|NVMe Log/ or $Device->{"Device"}=~/\bNVMe\b/i) { $Device->{"Kind"} = "NVMe"; $Bus = $PCI_DISK_BUS; } elsif($Desc=~/Rotation Rate:.*Solid State Device/ or $Device->{"Device"}=~/\bSSD/ or $Device->{"Family"}=~/\bSSD/) { $Device->{"Kind"} = "SSD"; } else { $Device->{"Kind"} = "HDD"; } } if($Desc=~/User Capacity:.*\[(.+?)\]/) { # ATA $Device->{"Capacity"} = $1; } elsif($Desc=~/Size\/Capacity:.*\[(.+?)\]/) { # NVMe $Device->{"Capacity"} = $1; } if($Desc=~/Vendor:\s*(.+?)(\Z|\n)/) { $Device->{"Vendor"} = $1; } $Device->{"Capacity"}=~s/,/./g; $Device->{"Capacity"}=~s/\.0+ //g; $Device->{"Capacity"}=~s/\s+//g; $Device->{"Device"}=~s/\//-/g; $Device->{"Device"}=~s/"/-inch/g; $Device->{"Device"}=~s/\ASSD\s+//g; $Device->{"Device"}=~s/\A(m\.2\s)([^\s]+\s)/$2$1/g; $Device->{"Device"}=~s/\Am\.2\s+//g; $Device->{"Device"}=~s/\s{2,}/ /g; $Device->{"Device"}=~s/\.\Z//g; fixDrive_Pre($Device, $Bus); if(not $Device->{"Vendor"}) { # NVMe if($Desc=~/PCI Vendor ID:\s*0x(\w+)/) { $Device->{"Vendor"} = nameID(getPciVendor($1)); } elsif($Desc=~/PCI Vendor\/Subsystem ID:\s*0x(\w+)/) { $Device->{"Vendor"} = nameID(getPciVendor($1)); } if($Device->{"Vendor"} and my $Vnd = guessDeviceVendor($Device->{"Vendor"})) { $Device->{"Vendor"} = $Vnd; $Device->{"Device"} = duplVendor($Vnd, $Device->{"Device"}); } } if(not $Opt{"IdentifyDrive"}) { if(not $Device->{"Vendor"} or not $Device->{"Device"}) { return; } } $Device->{"Device"} = duplVendor($Device->{"Vendor"}, $Device->{"Device"}); $Device->{"Device"}=~s/[\[\]]/ /g; $Device->{"Device"}=~s/\A //g; $Device->{"Device"}=~s/ \Z//g; fixDrive($Device); # HUA7210SASUN1.0T XXXXXXXXXX # SD88SA024SA0 SUN24G XXXXXXXXXX # ST31000NSSUN1.0T XXXXXXXXXX $Device->{"Device"}=~s/(\s+\d\d\w{8,})\Z//; $Device->{"Model"} = $Device->{"Device"}; if(isBSD()) { my @Dr = (); if($Dev=~/\/(\w+?)\d+[cd]?\Z/) { push(@Dr, $1); } my $ShortDev = $Dev; $ShortDev=~s/(\d)[cd]\Z/$1/; if(my $ADr = $DevAttached{basename($ShortDev)}) { $ADr=~s/\d+\Z//; push(@Dr, $ADr); } if(@Dr) { $Device->{"Driver"} = join(", ", @Dr); } $Device->{"File"} = basename($ShortDev); } my $ID = devID(nameID($Device->{"Vendor"})); $ID = devID($ID, devSuffix($Device)); $Device->{"Device"} .= addCapacity($Device->{"Device"}, $Device->{"Capacity"}); foreach (keys(%{$Device})) { if(not $Device->{$_}) { delete($Device->{$_}); } } my $HWId = $Bus.":".fmtID($ID); $HW{$HWId} = $Device; $HDD{$Dev} = $HWId; $DeviceNumByID{$HWId} = $DriveNumByFile{$Dev}; countDevice($HWId, $Device->{"Type"}); return $HWId; } sub fixDrive_Pre($$) { my ($Device, $Bus) = @_; if($Bus eq $PCI_DISK_BUS) { $Device->{"Kind"} = "NVMe"; } if($Device->{"Vendor"} and nonVendor($Device->{"Vendor"})) { $Device->{"Device"} = $Device->{"Vendor"}." ".$Device->{"Device"}; $Device->{"Vendor"} = undef; } if(not $Device->{"Vendor"} and not $Device->{"Family"} and $Device->{"Device"}) { if($Device->{"Device"}=~/\ASATA (32GB |)SSD\Z/) { $Device->{"Vendor"} = $DEFAULT_VENDOR; } } my %FixName = ( "ASUS-PHISON SSD" => "ASUS PHISON SSD", "kingpower1108 SSD" => "KingPower 1108 SSD" ); if(defined $FixName{$Device->{"Device"}}) { $Device->{"Device"} = $FixName{$Device->{"Device"}}; } if(not $Device->{"Vendor"} and $Device->{"Device"}) { if(my $Vnd = guessDeviceVendor($Device->{"Device"})) { $Device->{"Vendor"} = $Vnd; $Device->{"Device"} = duplVendor($Vnd, $Device->{"Device"}); } my $FamilyVnd = undef; if($Device->{"Family"}=~/\A([^ ]+)\s+/) { $FamilyVnd = $1; } if($FamilyVnd) { if($Device->{"Device"}=~s/\A\Q$FamilyVnd\E([\s_\-]+|\Z)//i) { $Device->{"Vendor"} = $FamilyVnd; } } if(not $Device->{"Vendor"}) { if(my $VndDr = guessDriveVendor($Device->{"Device"})) { $Device->{"Vendor"} = $VndDr; $Device->{"Device"} = duplVendor($Device->{"Vendor"}, $Device->{"Device"}); } } if(not $Device->{"Vendor"} and $FamilyVnd) { $Device->{"Vendor"} = $FamilyVnd; } } if(not $Device->{"Vendor"} or grep {$Device->{"Vendor"} eq $_} ("Generic", "ZALMAN")) { if(my $VndS = guessSerialVendor($Device->{"Serial"})) { # Obsolete - we don't collect serials $Device->{"Vendor"} = $VndS; } elsif(my $VndF = guessFirmwareVendor($Device->{"Firmware"})) { $Device->{"Vendor"} = $VndF; } } } sub guessDriveKind($$) { my ($Vendor, $Name) = @_; my $Model = $Vendor." ".$Name; if($Name=~/SSD|Solid State/) { return "SSD"; } if($Model=~/\A(ADATA|AMD|Apacer|Corsair|Crucial|Goodram|Intel|Kingston|LITEON|Micron|Mushkin|OCZ|Patriot|Plextor|PNY|SanDisk|SK hynix|Smartbuy|SPCC|Team|Transcend|HGST HUSM|HP VK0|Samsung (MM|MZ|PM|SG|SM)|Seagate ST(120H|400F|480F|800F)|Teclast|Toshiba (A100|KSG|Q\d|THNS|T[LR]\d|V[TX]\d)|TSA \d|WDC WD[BS])/i) { # TODO: list mechanical drive vendors instead? return "SSD"; } if($Name=~/\b(SSHD|HDD)\b/) { return "HDD"; } if($Model=~/\A(Fujitsu M|HGST H[A-Z]{2}\d|Hitachi|HP [FGMV]B\d|IBM\/Hitachi|IBM DTLA|Maxtor|Quantum|Samsung (H[DEMNS]|MP|SP|SV)|Seagate (ST\d|STM\d|Expansion|BUP )|Toshiba (DT|HD|M)|WDC WD\d)/i) { return "HDD"; } return undef; # HDD? } sub nonVendor($) { return (length($_[0])<2 or $_[0]=~/\A\d+GB\Z/ or grep { lc($_[0]) eq lc($_) } ("SSD", "mSATA", "SATAII", "SATAIII", "SATA", "SATA2", "SATA3", "PATA", "M.2", "PCIe", "Series", "SC2", "SB")); } sub fixDrive($) { my $Device = $_[0]; if($Device->{"Vendor"}=~/\A(WD|ST)\d+/) { # model name instead of vendor name $Device->{"Device"} = $Device->{"Vendor"}." ".$Device->{"Device"}; if(defined $DiskVendor{$1}) { $Device->{"Vendor"} = $DiskVendor{$1}; } } elsif($Device->{"Vendor"}=~s/\AWDC (WD\d+)\Z/WDC/) { # model name instead of vendor name $Device->{"Vendor"} = "WDC"; $Device->{"Device"} = $1." ".$Device->{"Device"}; } elsif(defined $DiskVendor{$Device->{"Vendor"}} and $Device->{"Vendor"} ne $DiskVendor{$Device->{"Vendor"}}) { $Device->{"Device"} = $Device->{"Vendor"}." ".$Device->{"Device"}; $Device->{"Vendor"} = $DiskVendor{$Device->{"Vendor"}}; $Device->{"Device"} = duplVendor($Device->{"Vendor"}, $Device->{"Device"}); } if(not $Device->{"Kind"} or $Device->{"Kind"} eq "HDD") { # kind of several models is not detected properly by smartmontools # or smartmontools output is not collected if(my $FixedKind = guessDriveKind($Device->{"Vendor"}, $Device->{"Device"})) { $Device->{"Kind"} = $FixedKind; } } if(not $Device->{"Device"}) { # no model name $Device->{"Device"} = $Device->{"Capacity"}; $Device->{"Device"}=~s/\.\d+//g; if($Device->{"Kind"} eq "SSD") { $Device->{"Device"} = "SSD ".$Device->{"Device"}; } } if($Device->{"Kind"} eq "SSD") { if($Device->{"Device"} eq "DISK") { $Device->{"Device"} = "SSD DISK"; } elsif($Device->{"Device"}=~/\A(\d{3})\Z/) { $Device->{"Device"} = "SSD $1"; } elsif($Device->{"Device"}=~/\A\d+\s*(GB|TB|G|T)\Z/) { $Device->{"Device"} = "SSD ".$Device->{"Device"}; } } $Device->{"Capacity"} = fixCapacity($Device->{"Capacity"}); if($Device->{"Kind"} eq "SSD" or $Device->{"Kind"} eq "NVMe") { if(grep {$Device->{"Device"} eq $_} ("SSD", "SATA SSD", "SATA-III SSD", "Solid State Disk", "SSD Sata III", "DISK", "SSD DISK") or (grep {uc($Device->{"Vendor"}) eq $_} @DRIVE_ADD_SIZE and $Device->{"Device"}!~/\A(THNS)/)) { # Modify device ID to distinguish SSDs if($Device->{"Capacity"}=~/\A([\d\.]+)([GT]B)\Z/) { my ($C, $Suffix) = ($1, $2); my $Cap = undef; if($Suffix eq "TB") { $C = int($C); $Cap = $Device->{"Capacity"}; } elsif($Suffix eq "GB") { if($C>=7) { if($C % 2 != 0) { $C += 1; } if(!isPowerOfTwo($C)) { if(isPowerOfTwo($C + 2)) { $C = $C + 2; } elsif(isPowerOfTwo($C + 4)) { $C = $C + 4; } } } $Cap = $C."GB"; } if($Device->{"Device"}!~/[^1-9]+$C([^\d]+|\Z)/) { $Device->{"Device"} .= addCapacity($Device->{"Device"}, $Cap); } } } } elsif($Device->{"Device"} eq "ZALMAN") { $Device->{"Device"} .= addCapacity($Device->{"Device"}, $Device->{"Capacity"}); } if(not $Device->{"Vendor"}) { if(grep {$Device->{"Device"} eq $_} ("T60", "T120", "V-16", "SSD-512G", "BR 64GB") or $Device->{"Device"}=~/\A\d+(G|GB|T|TB) SSD\Z/ or $Device->{"Device"}=~/\ASSD\s*\d+(G|GB|T|TB)\Z/ or $Device->{"Device"}=~/\ASATA3\s+\d+(G|GB|T|TB)\s+SSD\Z/) { # SSD32G, SSD60G # 64GB SSD # SATA3 128GB SSD $Device->{"Vendor"} = $DEFAULT_VENDOR; } } if(not $Device->{"Vendor"} or $Device->{"Vendor"} eq $DEFAULT_VENDOR) { if(my $Oui = $Device->{"IEEE_OUI"}) { if(defined $IeeeOui{$Oui}) { if($Opt{"IdentifyDrive"}) { $Device->{"Err"} = "identifying by IEEE OUI"; } else { printMsg("ERROR", "identifying unknown vendor by IEEE OUI for drive ".$Device->{"Device"}); } $Device->{"Vendor"} = $IeeeOui{$Oui}; } } } } sub isPowerOfTwo($) { return not $_[0] & $_[0]-1; } sub isUnknownRam($) { my $Vendor = $_[0]; if($Vendor=~/(Mfg |Manufacturer|A1_AssetTagNum)/) { return 1; } if($Vendor=~/\A(0x|)(0+|F+)\Z/) { return 1; } if(grep {$Vendor eq $_} ("8313", "7F7F", "ADCD", "M0", "M1", "K", "K1", "U", "6", "G u", "Unknown")) { return 1; } return 0; } sub isJedecRam($) { my $Vendor = $_[0]; if($Vendor=~/\A[A-F0-9]{16}\Z/ or $Vendor=~/\A[A-F0-9]{4}\Z/) { return 1; } return 0; } sub guessRamVendor($) { my $Name = $_[0]; if($Name=~/\A99[A-Z\d]{5}\-\d{3}\.[A-Z\d]{4,}\Z/) { return "Kingston"; } if($Name=~/\A($ALL_MEM_VENDORS)/i) { return $1; } foreach my $Len (reverse(2 .. 8)) { my $Prefix = substr($Name, 0, $Len); if(defined $RamVendor{$Prefix}) { return $RamVendor{$Prefix}; } } return undef; } sub guessDriveVendor($) { my ($Name, $NameOrig) = ($_[0], $_[0]); if(defined $DiskModelVendor{$Name}) { return $DiskModelVendor{$Name}; } if($Name=~/\A(.+?)[-_ ]\d+GB?\Z/) { if(defined $DiskModelVendor{$1}) { return $DiskModelVendor{$1}; } } foreach my $Len (reverse(3 .. length($Name))) { if($Name=~/\A([A-Z\d\-\_]{$Len})([A-Z\d\-\s]+|\Z)/ and defined $DiskVendor{$1}) { return $DiskVendor{$1}; } } if($Name=~/\A([A-Z]{2})[A-Z\d\-]+/ and defined $DiskVendor{$1}) { return $DiskVendor{$1}; } foreach my $Len (3, 2) { if($Name=~/\A[A-Z\d]{2,}\-([A-Z]{$Len})[A-Z\d]+/ and defined $DiskVendor{$1}) { # C400-MTFDDAT064MAM # M4-CT256M4SSD2 return $DiskVendor{$1}; } } foreach my $P (sort {$b cmp $a} keys(%DiskVendor)) { if(length($P)>=4) { if(index($Name, $P)==0) { return $DiskVendor{$P}; } } } if($Name=~/\A(MT|MSH|NT|P3|P3D|P4|T|PA25)\-(60|64|120|128|240|256|480|512|960|1TB|2TB)\Z/ or grep { $Name eq $_ } ("V-32", "NT-256", "NT-512", "Q-360", "Q-720")) { # MT-64 MSH-256 P3-128 P3D-240 P3-2TB T-60 V-32 PA25-128 NT-64 return "KingSpec"; } if($NameOrig=~s/\A(SSD|NVMe) //i) { return guessDriveVendor($NameOrig); } return; } sub guessSerialVendor($) { my $Serial = $_[0]; if(not $Serial) { return; } if($Serial=~/\A([A-Z]+)\-/) { if(defined $SerialVendor{$1}) { return $SerialVendor{$1}; } } elsif($Serial=~/\A([A-Z]{3})/) { if(defined $SerialVendor{$1}) { return $SerialVendor{$1}; } } return; } sub guessFirmwareVendor($) { my $Firmware = $_[0]; if(not $Firmware) { return; } if(defined $FirmwareVendor{$Firmware}) { return $FirmwareVendor{$Firmware}; } if($Firmware=~/\A(\w{4})/) { if(defined $FirmwareVendor{$1}) { return $FirmwareVendor{$1}; } } return; } sub guessDeviceVendor($) { my $Device = $_[0]; if($Device=~s/(\A|\s)($ALL_DRIVE_VENDORS|$ALL_VENDORS|$ALL_CDROM_VENDORS)([\s_\-\[]|\Z)//i) { return $2; } return; } sub computeInch($) { my $Size = $_[0]; my ($W, $H) = (); if($Size=~/(\A|\s)(\d+)x(\d+)mm(\s|\Z)/) { ($W, $H) = ($2, $3); } elsif($Size=~/(\A|\s)([\d\.]+)x([\d\.]+)cm(\s|\Z)/) { ($W, $H) = (10*$2, 10*$3); } if($W and $H) { return sqrt($W*$W + $H*$H)/25.4; } return; } sub computeDensity($$) { my ($Resolution, $Inches) = @_; if($Inches and $Resolution=~/(\d+)x(\d+)/) { my ($W, $H) = ($1, $2); return sprintf("%.1f", sqrt($W*$W + $H*$H)/$Inches); } return; } sub computeRatio($) { my $Size = $_[0]; my %Ratio = ( "1.1" => "11/10", "1.2" => "6/5", "1.25" => "5/4", "1.26" => "5/4", "1.27" => "5/4", "1.28" => "5/4", "1.3" => "4/3", "1.4" => "4/3", "1.5" => "3/2", "1.6" => "16/10", "1.7" => "16/9", "1.8" => "16/9", "1.9" => "16/9", "2.3" => "21/9", "2.4" => "21/9", "3.5" => "32/9", "3.6" => "32/9" ); if($Size=~/(\d+)x(\d+)/) { my $ResP = $1/$2; my $Res = sprintf("%.2f", $ResP); my $ResP1 = sprintf("%.1f", $ResP); if(defined $Ratio{$Res}) { $Res = $Ratio{$Res}; } elsif(defined $Ratio{$ResP1}) { $Res = $Ratio{$ResP1}; } return $Res; } return; } sub computeArea($) { my $Size = $_[0]; if($Size=~/(\d+)x(\d+)/) { return sprintf("%.0f", $1*$2/(25.4*25.4)); } return; } sub getXRes($) { if($_[0]=~/\A(\d+)/) { return $1; } return; } sub duplVendor($$) { my ($Vendor, $Device) = @_; if($Vendor) { # do not duplicate vendor name if(not $Device=~s/\A\Q$Vendor\E([\s\-\_\[\.]+|\Z)//gi and not $Device=~s/\s+\Q$Vendor\E\s+/ /gi and not $Device=~s/\s+\Q$Vendor\E\Z//gi) { if(my $ShortVendor = nameID($Vendor)) { if($ShortVendor ne $Vendor) { $Device=~s/\A\Q$ShortVendor\E[\s\-\_\[\.]+//gi; $Device=~s/\s+\Q$ShortVendor\E\s+/ /gi; $Device=~s/\s+\Q$ShortVendor\E\Z//gi; } } } } return $Device; } sub roundToNearest($) { my $Num = $_[0]; my $Delta = $Num - int($Num); if($Delta*10>5) { return int($Num)+1; } return int($Num); } sub cleanValues($) { my $Hash = $_[0]; foreach my $Key (keys(%{$Hash})) { if(my $Val = $Hash->{$Key}) { if(emptyVal($Val)) { delete($Hash->{$Key}); } } } } sub emptyVal($) { my $Val = $_[0]; $Val=~s/\A\s+//; $Val=~s/\s+\Z//; if($Val=~/\A[\[\(]*(not specified|not available|out of spec|not defined|No Device Manufacturer|No Device Part Number|invalid|error|unkn|unknown|undefined|unknow|uknown|empty|n\/a|none|default string|vendor|device|unknown vendor|default|MB serial number|PCA serial|customer|model|_|unde|null|no string|reserved|Unknown \(0\)|\?|unknown unknown|generic|[\.\}\*\_]+)[\)\]]*\Z/i or $Val=~/(\A|\b|\d)(to be filled|unclassified device|not defined|bad index|does not exist|unkn|uknown|default)(\b|\Z)/i) { return 1; } return 0; } sub devSuffix($) { my $Device = $_[0]; my $Suffix = $Device->{"Device"}; if($Device->{"Type"} eq "cpu") { if($Device->{"Vendor"} eq "Intel") { # short suffix my @Parts = (); if($Device->{"Device"}=~/(\A| )CPU /) { if($Device->{"Device"}=~/\A(.+?)\s+CPU/) { push(@Parts, $1); } if($Device->{"Device"}=~/(\A| )CPU\s+(.+?)\s*\@/) { push(@Parts, $2); } } elsif($Device->{"Device"}=~/ processor /) { if($Device->{"Device"}=~/\A(.+?)\s+processor/i) { push(@Parts, $1); } } elsif($Device->{"Device"}=~/\A(686-class)\Z/) { push(@Parts, $1); } $Suffix = join("-", @Parts); } elsif($Device->{"Vendor"} eq "AMD") { $Suffix=~s/X2 Dual Core Processor/X2/; } elsif($Device->{"Vendor"} eq "ARM") { if($Device->{"Device"}=~/(.+)\s+Processor/) { $Suffix = $1; } } } elsif($Device->{"Type"} eq "memory") { if(my $FF = $Device->{"FF"}) { $Suffix .= "-".$FF; } } if($Device->{"Type"} eq "memory" or $Device->{"Type"} eq "disk" or $Device->{"Type"} eq "battery") { if(my $Ser = $Device->{"Serial"}) { $Suffix .= "-serial-".$Ser; } } return $Suffix; } sub fmtID($) { my $ID = $_[0]; $ID=~s/[\W]+\Z//g; $ID=~s/[\W\_]+/-/g; $ID=~s/\A[\-]+//g; $ID=~s/[\-]+\Z//g; return $ID; } sub nameID(@) { my $Name = shift(@_); my $Type = undef; if(@_) { $Type = shift(@_); } if(not $Type or $Type ne "memory") { $Name=~s/\s*\([^()]*\)//g; $Name=~s/\s*\[[^\[\]]*\]//g; } while ($Name=~s/(\s*\,\s*|\s+)(Inc|Ltda|Ltd|Co |Co|GmbH|Corp|Tech\.|Pte|LLC|Sdn|Bhd|BV|AG|RSS|PLC|s\.r\.l\.|srl|S\.P\.A|B\.V|S\.A|s r\. o|s\.r\.o|z\.s\.p\.o|Ind|e\.V|a\.s|Co\.Ltd|Int\'l|Intl|I\.T\.G|IND\.CO\.|zrt\.|S\.A\. de C\.V\.|GmbH \& Co\. KG|S\.L\.)(\.|\.*\Z)//gi) {} $Name=~s/,?\s+[a-z]{2,4}\.//gi; $Name=~s/,(.+)\Z//gi; $Name=~s/(_S\.p\.A\.)\Z//gi; while ($Name=~s/\s+(Corporation|Computer|Computers|International|Electric|Company|Electronics|Electronic|Elektronik|Technologies|Technology|Technolog)\Z//ig) {} $Name=~s/[\.\,]/ /g; $Name=~s/\s*\Z//g; $Name=~s/\A\s*//g; return $Name; } sub fixVendorModel($$) { my ($V, $M) = @_; $V=~s/\s+\Z//g; $V=~s/\AMotherboard by\s+//gi; if($M eq "ABIT") { return ($M, $V); } if(not $V) { if($M=~s/\A(Bananapi|BQ|Google Inc\.|Google|Khadas|LGE|MEDION|Motorola|Nokia|OrangePi|Purism|Qualcomm Technologies, Inc\.|Rockchip|Samsung|Shenzhen Amediatech Technology Co\., Ltd|SolidRun|Tanix|Xiaomi)(\s+|\Z)//i) { $V = $1; } elsif($M=~/\A(TravelMate)/) { $V = "Acer"; } elsif($M=~/\A(LapBook)/) { $V = "Chuwi"; } elsif($M=~/\A(Spring Peak)/) { $V = "Gigabyte Technology"; } elsif($M=~/\A(EZbook)/) { $V = "Jumper"; } elsif($M=~/\A(ODROIDC)/) { $V = "Hardkernel"; } elsif($M=~/\A(Helios64)/) { $V = "Kobol"; } elsif($M=~/\A(PineTab)/) { $V = "Pine Microsystems"; } elsif($M=~/\A(Raspberry Pi)/) { $V = "Raspberry Pi Foundation"; } elsif($M=~/\A(Satellite)/) { $V = "Toshiba"; } elsif($M=~/\A(ZBOX\-)/) { $V = "ZOTAC"; } } $M = duplVendor($V, $M); return ($V, $M); } sub fixModel($$$) { my ($Vendor, $Model, $Version) = @_; if(not $Model) { if($Version and $Version=~/\ALenovo (.+)/) { $Model = $1; } else { return undef; } } $Model=~s/\A\-//; $Model=~s/\A-?\[(.+)\]\-?\Z/$1/; # IBM $Model=~s/\A\Q$Vendor\E\s+//i; $Model=~s/\s+Board\Z//i; $Model=~s/\AMotherboard\s+//gi; $Model=~s/\A'//; $Model=~s/['\s\.]+\Z//; $Model=~s/'n'/ and /; if($Model eq $Vendor) { return ""; } if($Vendor eq "Hewlett-Packard") { $Model=~s/\AHP\s+//gi; $Model=~s/\s+Notebook PC\s*\Z//gi; $Model=~s/PAVILION/Pavilion/gi; $Model=~s/Envy/ENVY/gi; } elsif(uc($Vendor) eq "TOSHIBA") { $Model=~s/SATELLITE/Satellite/g; } elsif($Vendor=~/Fujitsu/) { $Model=~s/Amilo/AMILO/g; $Model=~s/LifeBook/LIFEBOOK/g; $Model=~s/Stylistic/STYLISTIC/g; } elsif($Vendor=~/\ADell(\s|\Z)/i) { $Model=~s/\A(MM061|MXC061|MP061|ME051)\Z/Inspiron $1/g; $Model=~s/\A(MXC062)\Z/XPS $1/g; $Model=~s/\ADell System //g; # Dell System Vostro 3450 by Dell Inc. $Model=~s/\ADell //g; # Dell 500 by Dell Inc. } elsif($Vendor eq "Micro-Star International") { $Model=~s/\AMSI\s+//gi; $Model=~s/\ANotebook\s+//gi; } elsif(uc($Vendor) eq "LENOVO") { if($Model=~/\A\s*INVALID\s*\Z/) { $Model = ""; } if($Version=~/\A\s*INVALID\s*\Z/) { $Version = ""; } if($Version=~/[A-Z]/i) { $Version=~s/\ALenovo-?\s*//i; if($Version and $Version!~/Rev \d/i) { while($Model=~s/\A\Q$Version\E\s+//i) {} if($Model!~/\Q$Version\E/i) { $Model = $Version." ".$Model; } } } $Model=~s/Ideapad/IdeaPad/gi; $Model=~s/ideacentre/IdeaCentre/gi; $Model=~s/\AProduct\s+Lenovo\s+//i; $Model=~s/\AProduct\s+//i; $Model=~s/\ALenovo\s+//i; } elsif($Version=~/ThinkPad/i and $Model!~/ThinkPad/i) { $Model = $Version." ".$Model; } return $Model; } sub listDir($) { my $Dir = $_[0]; if(not $Dir) { return (); } opendir(my $DH, $Dir); if(not $DH) { return (); } my @Contents = grep { $_ ne "." && $_ ne ".." } readdir($DH); closedir($DH); @Contents = sort @Contents; return @Contents; } sub probeSys() { if(checkCmd("uname")) { $Sys{"Arch"} = runCmd("uname -m"); $Sys{"Kernel"} = runCmd("uname -r"); } else { require POSIX; $Sys{"Arch"} = (POSIX::uname())[4]; $Sys{"Kernel"} = (POSIX::uname())[2]; } my ($Distr, $DistrVersion, $Rel) = probeDistr(); setDistr($Distr, $DistrVersion, $Rel, undef); if(not $Sys{"System"}) { printMsg("ERROR", "failed to detect Linux/BSD distribution"); if($Opt{"Snap"}) { warnSnapInterfaces(); exitStatus(1); } } if($Sys{"Arch"}=~/unknown/i) { require Config; $Sys{"Arch"} = $Config::Config{"archname"}; $Sys{"Arch"}=~s/\-linux.*//; } if(isBSD()) { if($Sys{"Arch"} eq "x86_64") { $Sys{"Arch"} = "amd64"; } } if($Opt{"PC_Name"}) { $Sys{"Name"} = $Opt{"PC_Name"}; } $Sys{"Probe_ver"} = $TOOL_VERSION; $Sys{"DE"} = $ENV{"XDG_CURRENT_DESKTOP"}; if(not $Sys{"DE"}) { $Sys{"DE"} = $ENV{"DESKTOP_SESSION"}; } if(my $KDE_Ver = $ENV{"KDE_SESSION_VERSION"} and $Sys{"DE"} eq "KDE") { $Sys{"DE"} .= $KDE_Ver; } if(not $Sys{"Display_manager"}) { my $DmFile = "/etc/X11/default-display-manager"; if(-f $DmFile) { if(readFile($DmFile)=~/bin\/(.+)/) { $Sys{"Display_manager"} = $1; } } } if(not $Sys{"Display_manager"}) { my $DmFile = "/etc/systemd/system/display-manager.service"; if(-f $DmFile) { if(readFile($DmFile)=~/ExecStart=([^\s]+)/) { $Sys{"Display_manager"} = basename($1); } } } if(not $Sys{"Display_manager"}) { my $DmFile = "/etc/sysconfig/displaymanager"; if(-f $DmFile) { if(readFile($DmFile)=~/DISPLAYMANAGER="(.+)"/) { $Sys{"Display_manager"} = $1; } } } my $DeFile = "/etc/sysconfig/desktop"; if(-f $DeFile) { my $DeContent = readFile($DeFile); if(not $Sys{"DE"}) { if($DeContent=~/DESKTOP="(.+)"/) { $Sys{"DE"} = $1; } } if(not $Sys{"Display_manager"}) { if($DeContent=~/DISPLAYMANAGER="(.+)"/) { $Sys{"Display_manager"} = $1; } } } foreach my $DM (@ALL_DISPLAY_MANAGERS) { if($DM eq "slim") { $DM .= ".lock"; } if(-e "/run/$DM" or -e "/run/$DM.pid") { $DM=~s/\..+//g; $Sys{"Display_manager"} = $DM; last; } } $Sys{"Display_manager"} = fixDisplayManager($Sys{"Display_manager"}); if($Sys{"DE"}) { $Sys{"Current_desktop"} = $Sys{"DE"}; } elsif(isBSD()) { my $WMs = runCmd("ps x | grep wm | grep -v grep"); if($WMs=~/\s(\w+wm)/) { $Sys{"Current_wm"} = $1; } if(runCmd("ps x | grep start-hello | grep -v grep")) { $Sys{"DE"} = "helloDesktop"; $Sys{"Current_desktop"} = $Sys{"DE"}; } } $Sys{"Display_server"} = ucfirst($ENV{"XDG_SESSION_TYPE"}); if(defined $ENV{"WAYLAND_DISPLAY"}) { $Sys{"Display_server"} = "Wayland"; } $Sys{"Lang"} = $ENV{"LANG"}; foreach (keys(%Sys)) { chomp($Sys{$_}); } } sub fixDisplayManager($) { my $DM = uc($_[0]); if(my $Fixed = $DisplayManager_Fix{$DM}) { return $Fixed; } return $DM; } sub probeDmi() { if(not enabledLog("dmi_id")) { return; } listProbe("logs", "dmi_id"); my $Dmi = ""; foreach my $File ("sys_vendor", "product_name", "product_version", "chassis_type", "board_vendor", "board_name", "board_version", "board_serial", "bios_vendor", "bios_version", "bios_date") { my $Value = readFile("/sys/class/dmi/id/".$File); if(not $Value) { next; } $Value=~s/\s+\Z//g; $Value = fmtVal($Value); if($File eq "sys_vendor") { if(not emptyProduct($Value)) { $Sys{"Vendor"} = $Value; } } elsif($File eq "product_name") { if(not emptyProduct($Value)) { $Sys{"Model"} = $Value; } } elsif($File eq "product_version") { if(not emptyProduct($Value)) { $Sys{"Version"} = $Value; } } elsif($File eq "chassis_type") { if(my $CType = getChassisType($ChassisType{$Value})) { $Sys{"Type"} = $CType; } } elsif($File eq "board_serial") { $Value = clientHash($Value); } if($Value ne "" and $Value=~/[A-Z0-9]/i) { $Dmi .= $File.": ".$Value."\n"; } } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/dmi_id", $Dmi); } ($Sys{"Vendor"}, $Sys{"Model"}) = fixVendorModel($Sys{"Vendor"}, $Sys{"Model"}); $Sys{"Model"} = fixModel($Sys{"Vendor"}, $Sys{"Model"}, $Sys{"Version"}); } sub emptyProduct($) { my $Val = $_[0]; if(not $Val or $Val=~/\b(System manufacturer|System Product|Board Vendor|Board Manufacturer|Mainboard|System Manufacter|stem manufacturer|System Manufact|SYSTEM_MANUFACTURER|Name|Version|to be filled|empty|Not Specified|Default[ _]string|board version|Unknow|n\/a|Not)\b/i or $Val=~/\A([_0O\-\.\s]+|[X]+|NA|N\/A|\-O|1234567890|0123456789|[\.\,]+|Board|\$|\$\(PROJECT_SKU_NAME\)|SYSTEM_PRODUCT_NAME|Unknown Product)\Z/i or emptyVal($Val)) { return 1; } if(nonASCII($Val)) { return 1; } return 0; } sub getChassisType($) { my $CType = lc($_[0]); $CType=~s/ chassis//i; if($CType!~/unknown|other/) { return $CType; } return; } sub fixProduct() { foreach my $Attr ("Vendor", "Version", "Model") { if(emptyProduct($Sys{$Attr})) { $Sys{$Attr} = ""; } } } sub fixFFByCPU($) { my $CPU = $_[0]; if($Sys{"Type"}!~/$DESKTOP_TYPE|$SERVER_TYPE/) { if($CPU=~/Celeron CPU E\d+|Pentium (CPU G\d+|D CPU|Dual-Core CPU E\d+) |Core 2 CPU \d+ |Core 2 Duo CPU E\d+|Core i\d CPU \d+ |Core i\d-\d+ CPU|CPU Q(9400|8200)|Athlon 64 X2 Dual Core Processor \d+|Athlon X4 \d+|Athlon 64 Processor \d+\+|Phenom II X[24] B?\d+|FX-\d+ Six-Core|A10\-\d+K|Xeon CPU (\d+|[EXW]\d{4}|(E5|D)-\d{4}) |Core i7-\d+ CPU|FX-\d+ Eight-Core|Atom CPU C3508|Ryzen 5 1600|PPC970FX/ and $CPU!~/Mobile/) { $Sys{"Type"} = "desktop"; } } if($Sys{"Type"}!~/$SERVER_TYPE/) { if($CPU=~/Opteron X3216|Xeon Silver|Xeon Gold|Xeon Platinum|POWER/) { $Sys{"Type"} = "server"; } } if($Sys{"Type"}!~/$MOBILE_TYPE/) { if($CPU=~/Athlon Neo X2 .* L3|Core i3 CPU M 380/) { $Sys{"Type"} = "notebook"; } } if(not $Sys{"Type"} or $Sys{"Type"} eq "desktop") { if($Sys{"Arch"}=~/aarch64/) { $Sys{"Type"} = "system on chip"; } } } sub fixFFByCDRom($) { my $CDRom = $_[0]; if($Sys{"Type"}!~/$DESKTOP_TYPE|$SERVER_TYPE/) { if($CDRom=~/(DVR-118L|DDU1615|SH-222AB|DVR-111D|GSA-H10N|CRX230EE|iHAS122|DVR-112D|GH22LP20|AD-7200A|TS-H553A|AD-7173A|DVDRAM_GSA-H60N|GH24NSB0|SH-222BB|SOHR-5238S|ND-3540A)/) { $Sys{"Type"} = "desktop"; } } } sub fixFFByBoard($) { my $Board = $_[0]; if($Sys{"Type"}!~/$DESKTOP_TYPE|$SERVER_TYPE/) { if($Board=~/\b(D510MO|GA-K8NMF-9|DG965RY|DG33BU|D946GZIS|N3150ND3V|D865GSA|DP55WG|H61MXT1|D875PBZ|F2A55|Z68XP-UD3|Z77A-GD65|M4A79T|775Dual-880Pro|P4Dual-915GL|P4i65GV|D5400XS|D201GLY|MicroServer|IPPSB-DB|MS-AA53|C2016-BSWI-D2|N3160TN|D915PBL|EIRD-SAM|D865PERL|D410PT|D525MW|D945GCNL|BSWI-D2|B202|D865GBF|G1-CPU-IMP|Aptio CRB|A1SRi|D865GVHZ|IC17X|N3050ND3H|Bettong CRB|E3C246D2I|Pine Trail - M CRB|Ultra 24)\b/) { $Sys{"Type"} = "desktop"; } } if($Sys{"Type"}!~/$SERVER_TYPE/) { if($Board=~/X10DRT-P|X10DRW-i|X10SDV-TP8F|X10DRH-iT|CS24-SC|K1SPE-IN001/) { $Sys{"Type"} = "server"; } } if($Sys{"Type"}!~/$MOBILE_TYPE/) { if($Board=~/\b(W7430|Poyang|PSMBOU|Lhotse-II|Nettiling|EI Capitan|JV11-ML|M7x0S Bottom|M720SR|26446AG|S5610|SANTA ROSA CRB|PowerBook\d+|VivoBook|VPCF12C5E)\b/) { $Sys{"Type"} = "notebook"; } if($Board=~/\b(SurfTab)\b/) { $Sys{"Type"} = "tablet"; } } if($Sys{"Type"} ne "all in one") { if($Board=~/(AFLMB4-945GSE|EZ1600)/) { $Sys{"Type"} = "all in one"; } } } sub fixFFByModel($$) { my ($V, $M) = @_; if($Sys{"Type"}!~/$MOBILE_TYPE/) { # can't distinguish all-in-ones vs notebooks (very similar hardware: same cdroms, mobile graphics cards, etc.) # so need to check by exact model name if($M=~/(AO531h|Aspire (7720|5670|\d+Z)|EasyNote|Extensa \d+|MacBook|RoverBook|A410-K\.BE47P1|0PJTXT|R490-KR6WK)/ or ($V=~/Alienware/i and $M=~/m15/) or ($V=~/Clevo/i and $M=~/M740TU|D40EV|M720R/) or ($V=~/IBM/i and $M=~/26474MG/) or ($V=~/Intel/i and $M=~/Corbett Park CRB/) or ($V=~/Fujitsu/i and $M=~/ESPRIMO Mobile/) or ($V=~/NOTEBOOK/) or ($V=~/Samsung/i and $M=~/R50\/R51/) or ($V=~/Toshiba/i and $M=~/Satellite/) or ($V=~/TPVAOC/i and $M=~/AA183M/) or ($V=~/NCS/i and $M=~/ONE1/)) { $Sys{"Type"} = "notebook"; } } if($Sys{"Type"}!~/$DESKTOP_TYPE|$SERVER_TYPE/) { if($M=~/MacPro|D865GLC|ESPRIMO P|Aspire easyStore|X11SSL-F|TERRA_PC|VXC Class/) { $Sys{"Type"} = "desktop"; } } if($Sys{"Type"}!~/firewall/) { # expansion if($M=~/Firewall/ or $V=~/Silver Peak Systems|Sophos/) { $Sys{"Type"} = "firewall"; } } if($Sys{"Type"}!~/$SERVER_TYPE/) { if($M=~/X10DRG-O\+-CPU|ML10Gen|Super Server|H12SSW-NT|X11SCE-F/ or ($V=~/Neousys/i and $M=~/Nuvo/)) { $Sys{"Type"} = "server"; } } if($Sys{"Type"}=~/$MOBILE_TYPE/ and $Sys{"Type"} ne "convertible") { if($M=~/convertible/i) { $Sys{"Type"} = "convertible"; } } if($Sys{"Type"} ne "stick pc") { if($V=~/MEEGOPAD/i) { $Sys{"Type"} = "stick pc"; } if($M=~/IdeaCentre Stick/i) { $Sys{"Type"} = "stick pc"; } } if($Sys{"Type"} ne "nettop") { if($M=~/MS-B120|IdeaCentre Q150/i) { $Sys{"Type"} = "nettop"; } } if($Sys{"Type"} ne "mini pc" and $Sys{"Type"} ne "stick pc") { if(($V=~/Beelink/i and $M=~/\ASII/) or ($V=~/Compulab/i and $M=~/\A(Intense|fitlet|Airtop)/) or ($V=~/Flytech/i and $M=~/C56/) or ($V=~/Intel/i and $M=~/\ANUC\d/) or ($V=~/Kontron/i and $M=~/SMX945/) or ($V=~/Orbsmart/i and $M=~/\AAW/) or ($V=~/Radiant/i and $M=~/P845/) or ($V=~/Supermicro/i and $M=~/X11SSE-F|A1SAi/) or ($V=~/THD/i and $M=~/RX2/) or ($V=~/ZOTAC/i and $M=~/\AZBOX/) or $M=~/TV Box/ or $M=~/\AZBOX\-/ or $M=~/Macmini|ESPRIMO Q510|MMLP5AP-SI|Mini PC|TL-WR842N|Thin Client|Thin Mini|VMac mini|Aptio CRB|Propc Nano|XS35V5|M6JR120|D425KT/) { $Sys{"Type"} = "mini pc"; } } if($Sys{"Type"} ne "all in one") { if($M=~/( AiO PC|AFLMB-9652)/ or $M=~/\A(MS-6657|EZ1601)\Z/ or $V eq "AIO" or ($V=~/Apple/i and $M=~/\AiMac/) or ($V=~/Lenovo/i and $M=~/\A(S310|IdeaCentre B|ThinkCentre M90z) /) or ($V=~/Hewlett/i and $M=~/ Aio\Z/i) or ($V=~/MiTAC/i and $M=~/\AAIO /)) { $Sys{"Type"} = "all in one"; } } if($Sys{"Type"} ne "tablet") { if($M=~/(Hi10 .+ tablet|Visconte4U|TERRA_PAD)/i or ($V=~/ONDA/i and $M=~/Tablet|V919/i) or ($V=~/Microsoft/i and $M=~/Surface/i) or ($V=~/Hampoo/i and $M=~/\A(E4D6|D4D6|I1D6|P02BD6)/i) or ($V=~/Acer/i and $M=~/ICONIA Tab/i) or ($V=~/TMAX/i and $M=~/TM/i) or ($V=~/Wacom/i and $M=~/Citiq/i)) { $Sys{"Type"} = "tablet"; } } } sub fixFFByMonitor($) { my $Mon = $_[0]; if($Sys{"Type"} ne "all in one") { if($Mon=~/(AIO PC)/) { $Sys{"Type"} = "all in one"; } } if($Sys{"Type"}!~/$MOBILE_TYPE/) { if($Mon=~/LGD02E9|SEC3445|LPLA500|CMO1680|LGD018B|APP9C20/) { $Sys{"Type"} = "notebook"; } } if($Sys{"Type"}!~/$DESKTOP_TYPE/) { if($Mon=~/VA1913w-2|NS-39D310NA19|TD2421/) { $Sys{"Type"} = "desktop"; } } } sub fixFFByGPU($) { my $GPU = $_[0]; if($Sys{"Type"}!~/$DESKTOP_TYPE|$SERVER_TYPE/) { if($GPU=~/\A((NV|G)\d+ \[GeForce|RV\d+ \[Radeon |GeForce4 MX|RV635 PRO|Radeon HD 3870)/) { $Sys{"Type"} = "desktop"; } } } sub fixFFByTouchpad($) { my $Id = $_[0]; if($Sys{"Type"}!~/$MOBILE_TYPE|phone/) { if($Id=~/ps\/2/ and $HW{$Id}{"Device"}!~/Im.*PS\/2/) { $Sys{"Type"} = "notebook"; } } } sub fixFFByDisk($) { my $Disk = $_[0]; if($Sys{"Type"}!~/$DESKTOP_TYPE|$SERVER_TYPE/) { if($Disk=~/HD321KJ|ST3500413AS|ST2000DM001|WD205BA|WD20EZRZ|HD103UJ|WD30EFRX/) { $Sys{"Type"} = "desktop"; } } } sub fixChassis() { my (%Bios, %Board) = (); foreach my $L (split(/\n/, readFile($FixProbe_Logs."/dmi_id"))) { if($L=~/\A(\w+?):\s+(.+?)\Z/) { my ($File, $Value) = ($1, $2); $Value = fmtVal($Value); if($File eq "chassis_type") { if(my $CType = getChassisType($ChassisType{$Value})) { $Sys{"Type"} = $CType; } } elsif($File eq "sys_vendor") { if(not emptyProduct($Value)) { $Sys{"Vendor"} = $Value; } } elsif($File eq "product_name") { if(not emptyProduct($Value)) { $Sys{"Model"} = $Value; } } elsif($File eq "product_version") { if(not emptyProduct($Value)) { $Sys{"Version"} = $Value; } } elsif($File eq "bios_vendor") { $Bios{"Vendor"} = fmtVal($Value); } elsif($File eq "bios_version") { $Bios{"Version"} = $Value; } elsif($File eq "bios_date") { if(not emptyProduct($Value)) { $Bios{"Release Date"} = $Value; } } elsif($File eq "board_vendor") { $Board{"Vendor"} = fmtVal($Value); } elsif($File eq "board_serial") { $Board{"Serial"} = fmtVal($Value); } elsif($File eq "board_name") { $Board{"Device"} = fmtVal($Value); } elsif($File eq "board_version") { $Board{"Version"} = $Value; } } } ($Sys{"Vendor"}, $Sys{"Model"}) = fixVendorModel($Sys{"Vendor"}, $Sys{"Model"}); $Sys{"Model"} = fixModel($Sys{"Vendor"}, $Sys{"Model"}, $Sys{"Version"}); if(not $Bios_ID) { $Bios_ID = registerBIOS(\%Bios); } if(not $Board_ID) { $Board_ID = registerBoard(\%Board); } if(not $Sys{"Type"} or grep {$Sys{"Type"} eq $_} ("soc", "system on chip", "notebook", "hand held")) { if($Sys{"Kernel"}=~/\-(sunxi|sunxi64|raspi2)\Z/i or $Sys{"Vendor"}=~/raspberry/i) { $Sys{"Type"} = "system on chip"; } if($Sys{"Kernel"}=~/\-sunxi/) { $Sys{"Vendor"} = "sunxi"; } elsif($Sys{"Kernel"}=~/\-(tegra)\Z/i) { $Sys{"Type"} = "system on chip"; $Sys{"Vendor"} = "NVIDIA"; $Sys{"Model"} = "Tegra"; } elsif($Sys{"Kernel"}=~/\-(rockchip-.*)\Z/i) { $Sys{"Type"} = "system on chip"; $Sys{"Vendor"} = "Rockchip"; } elsif($Sys{"Kernel"}=~/_(byt\-g9ff829d)\Z/i) { $Sys{"Type"} = "tablet"; $Sys{"Vendor"} = "Lenovo"; $Sys{"Model"} = "YOGA"; $Sys{"System"} = "android"; } elsif($Sys{"Kernel"}=~/PhoenixOS/i) { $Sys{"System"} = "phoenixos"; } elsif($Sys{"Kernel"}=~/-Microsoft\Z/i) { $Sys{"Type"} = "desktop"; $Sys{"Vendor"} = "Microsoft"; $Sys{"Model"} = "Windows Subsystem for Linux"; } } if(not $Sys{"Model"} and not $Sys{"Vendor"}) { if($Sys{"Kernel"}=~/\-(gf5d7b8b)\Z/i) { $Sys{"Type"} = "tablet"; $Sys{"Vendor"} = "Google"; $Sys{"Model"} = "Nexus 7"; $Sys{"System"} = "android"; } elsif($Sys{"Kernel"}=~/\-(LuisKERNEL|Dark-Ages)\-|\-perf\+|SM-N9500|lineageos|FKernel-v|lineage|g8ca5a01/i) { $Sys{"Type"} = "smartphone"; $Sys{"System"} = "android"; } elsif($Sys{"Kernel"}=~/\-qcom\-msm8916/i) { $Sys{"Type"} = "smartphone"; } } } sub ipAddr2ifConfig($) { my $IPaddr = $_[0]; my $IFConfig = ""; foreach my $Line (split(/\n/, $IPaddr)) { if($Line=~s/\A\d+:\s+//) { $IFConfig .= "\n".$Line."\n"; } else { $IFConfig .= $Line."\n"; } } return $IFConfig; } sub probeHWaddr() { my $IFConfig = undef; if($Opt{"FixProbe"}) { $IFConfig = fixHWaddr(); } else { my $ByIPaddr = 0; if(checkCmd("ifconfig")) { listProbe("logs", "ifconfig"); $IFConfig = runCmd("ifconfig -a 2>&1"); $IFConfig = hideIPs($IFConfig); $IFConfig = encryptMACs($IFConfig); $IFConfig=~s/(inet6 |inet |netmask |broadcast )[^\s]+/$1\XXX/g; $IFConfig=~s/(ssid )(.+?)( channel)/$1...$3/g; if(isBSD()) { $IFConfig=~s/(nwid|join|authname|wgpubkey|wgpeer) .+/$1 .../g; $IFConfig=~s/(groups|description|groups): .+/$1: .../g; } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/ifconfig", $IFConfig); } } elsif(checkCmd("ip")) { listProbe("logs", "ip_addr"); if(my $IPaddr = runCmd("ip addr 2>&1")) { $IPaddr = hideIPs($IPaddr); $IPaddr = encryptMACs($IPaddr); $IPaddr=~s/(inet6 |inet |brd )[^\s]+/$1\XXX/g; $IFConfig = ipAddr2ifConfig($IPaddr); $ByIPaddr = 1; if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/ip_addr", $IPaddr); } } } elsif(checkModule("IO/Socket.pm") and checkModule("IO/Interface.pm")) { require IO::Socket; require IO::Interface; my $Socket = IO::Socket::INET->new(Proto => "udp"); my @Ifs = (); my %Addrs = (); my $Macs = ""; foreach my $If ($Socket->if_list) { if(my $Mac = $Socket->if_hwaddr($If)) { $Mac = lc($Mac); $Mac=~s/:/-/g; $Mac = lc(clientHash(lc($Mac))); push(@Ifs, $If); # save order $Addrs{$If} = $Mac; $Macs .= "$If:$Mac\n"; } } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/macs", $Macs); } $Sys{"HWaddr"} = selectHWAddr(\@Ifs, \%Addrs); } else { printMsg("ERROR", "can't find 'ifconfig' or 'ip'"); exitStatus(1); } if($IFConfig) { if(isBSD()) { $IFConfig=~s/(\n\w)/\n$1/g; } $Sys{"HWaddr"} = detectHWaddr($IFConfig, $ByIPaddr); if($Opt{"HWLogs"} and enabledLog("ethtool_p")) { my $EthtoolP = ""; foreach my $E (sort keys(%PermanentAddr)) { $EthtoolP .= $E."=>".$PermanentAddr{$E}."\n"; } if($EthtoolP) { writeLog($LOG_DIR."/ethtool_p", $EthtoolP); } } } if(not $Sys{"HWaddr"}) { printMsg("ERROR", "failed to detect hwid"); if($Opt{"Snap"}) { warnSnapInterfaces(); } exitStatus(1); } } if($IFConfig) { foreach my $I (split(/\n\n/, $IFConfig)) { if($I=~/\A([^:\s]+):?\s/) { my $F = $1; if(($I=~/packets\s*:?\s*(\d+)/ and $1) or ($I=~/valid_lft\s+(\d+)/ and $1)) { $UsedNetworkDev{$F} = 1; } if(isBSD()) { if($I=~/status: (associated|active)/) { $UsedNetworkDev{$F} = 1; } } } } } } sub fixHWaddr() { my $IFConfig = readFile($FixProbe_Logs."/ifconfig"); my $ByIPaddr = 0; if(isBSD()) { $IFConfig=~s/(\n\w)/\n$1/g; } if(not $IFConfig) { if(my $IPaddr = readFile($FixProbe_Logs."/ip_addr")) { $IFConfig = ipAddr2ifConfig($IPaddr); $ByIPaddr = 1; } } if($IFConfig) { # fix HWaddr my $EthtoolP = readFile($FixProbe_Logs."/ethtool_p"); if($EthtoolP) { foreach my $E (split(/\n/, $EthtoolP)) { if($E=~/(.+)\=\>(.+)/) { $PermanentAddr{$1} = $2; } } } my $UAddr = $Sys{"HWaddr"}; $UAddr=~s/\-/:/g; if($EthtoolP or $IFConfig=~/\Q$UAddr\E/i or grep { uc($Sys{"HWaddr"}) eq $_ } @WrongAddr) { if(my $NewAddr = detectHWaddr($IFConfig, $ByIPaddr)) { $Sys{"HWaddr"} = $NewAddr; } } } return $IFConfig; } sub warnSnapInterfaces() { print STDERR "\nERROR: Make sure required Snap interfaces are connected:\n\n"; print STDERR " for i in hardware-observe system-observe block-devices log-observe upower-observe physical-memory-observe network-observe raw-usb mount-observe opengl;do sudo snap connect hw-probe:\$i :\$i; done\n"; # auto-connected: # # hardware-observe # mount-observe # network-observe # system-observe # upower-observe # log-observe # opengl } sub countStr($$) { my ($Str, $Target) = @_; my $Count = 0; while($Str=~s/$Target//) { $Count += 1; } return $Count; } sub detectHWaddr(@) { my $IFConfig = shift(@_); my $ByIPaddr = 0; if(@_) { $ByIPaddr = shift(@_); } my @Devs = (); my %Addrs = (); my %Blocks = (); foreach my $Block (split(/[\n]\s*[\n]+/, $IFConfig)) { my $Addr = undef; if($Block=~/\A(docker|vboxnet|vmnet|tun\d)/) { next; } if($Block=~/permaddr\s+([^\s]+)/) { $Addr = lc($1); } elsif($Block=~/ether\s+([^\s]+)/) { # new $Addr = lc($1); } elsif($Block=~/HWaddr\s+([^\s]+)/) { # old $Addr = lc($1); } elsif($Block=~/lladdr\s+([^\s]+)/) { # OpenBSD $Addr = lc($1); } elsif($Block=~/address:\s+([^\s]+)/) { # NetBSD $Addr = lc($1); } if(not $Addr) { next; } if(index($Addr, ":")!=-1) { # Support for old probes $Addr=~s/:/-/g; } my $NetDev = undef; if($Block=~/\A([^:]+?):?\s/) { $NetDev = $1; } else { next; } push(@Devs, $NetDev); # save order $Addrs{$NetDev} = $Addr; $Blocks{$NetDev} = $Block; } return selectHWAddr(\@Devs, \%Addrs, $ByIPaddr, \%Blocks); } sub getIF($$) { my ($Name, $Part) = @_; if($Name=~/\A([a-z]+)(\d+)/i) { if($Part eq "name") { return $1; } elsif($Part eq "num") { return int($2); } } return undef; } sub sortNaturally(@) { return sort {getIF($a, "name") cmp getIF($b, "name")} sort {getIF($a, "num") <=> getIF($b, "num")} @_; } sub selectHWAddr(@) { my $Devs = shift(@_); my $Addrs = shift(@_); my $ByIPaddr = 0; if(@_) { $ByIPaddr = shift(@_); } my $Blocks = {}; if(@_) { $Blocks = shift(@_); } # TODO: sort all i-faces on next re-gen of the DB if($ByIPaddr) { @{$Devs} = sortNaturally(@{$Devs}); } my (@Eth, @Wlan, @Other, @Wrong, @Virtual, @Extra) = (); my %MacDev = (); foreach my $NetDev (@{$Devs}) { my $Addr = $Addrs->{$NetDev}; $MacDev{$Addr} = $NetDev; if(not $Opt{"FixProbe"}) { if(my $RealMac = getRealHWaddr($NetDev)) { $PermanentAddr{$NetDev} = clientHash($RealMac); } } if(defined $PermanentAddr{$NetDev}) { $Addr = lc($PermanentAddr{$NetDev}); $Addr=~s/:/-/g; # support for old probes } if(grep { uc($Addr) eq $_ or clientHash($Addr) eq $_ } @WrongAddr) { push(@Wrong, $Addr); next; } if(defined $ExtraConnection{$NetDev}) { # external network devices push(@Extra, $Addr); } elsif($NetDev=~/\Aenp\d+s\d+.*u\d+\Z/i) { # enp0s20f0u3, enp0s29u1u5, enp0s20u1, etc. push(@Other, $Addr); } elsif(index($Addr, "-")!=-1 and (countStr($Addr, "00")>=5 or countStr($Addr, "88")>=5 or countStr($Addr, "ff")>=5)) { # 00-dd-00-00-00-00, 88-88-88-88-87-88, ... # Support for old probes push(@Other, $Addr); } elsif(isBSD() and $Blocks->{$NetDev}=~/media:.*Wireless|NetWiFi/) { $WLanInterface{$NetDev} = 1; push(@Wlan, $Addr); } elsif(isBSD() and $Blocks->{$NetDev}=~/media:.*Ethernet/) { $EthernetInterface{$NetDev} = 1; push(@Eth, $Addr); } elsif($NetDev=~/\Ae/) { $EthernetInterface{$NetDev} = 1; push(@Eth, $Addr); } elsif($NetDev=~/\Aw/) { $WLanInterface{$NetDev} = 1; push(@Wlan, $Addr); } elsif($NetDev=~/\Avir/) { push(@Virtual, $Addr); } else { push(@Other, $Addr); } } my $Sel = undef; if(@Eth) { $Sel = $Eth[0]; } elsif(@Wlan) { $Sel = $Wlan[0]; } elsif(@Other) { $Sel = $Other[0]; } elsif(@Extra) { @Extra = sort {$MacDev{$b}=~/\Aw/ cmp $MacDev{$a}=~/\Aw/} @Extra; $Sel = $Extra[0]; } elsif(@Wrong) { $Sel = $Wrong[0]; } elsif(@Virtual) { $Sel = $Virtual[0]; } if(not $Sel) { return clientHash("DEFAULT"); } return $Sel; } sub getRealHWaddr($) { my $Dev = $_[0]; if(checkCmd("ethtool")) { my $Info = runCmd("ethtool -P $Dev 2>/dev/null"); if($Info=~/(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)/) { my $Mac = lc($1); $Mac=~s/:/-/g; if($Mac ne "00-00-00-00-00-00" and $Mac ne "ff-ff-ff-ff-ff-ff") { return $Mac; } } } return; } sub readFileHex($) { my $Path = $_[0]; local $/ = undef; open(FILE, "<", $Path); binmode FILE; my $Data = ; close FILE; return unpack('H*', $Data); } sub readFile($) { my $Path = $_[0]; open(FILE, "<", $Path); local $/ = undef; my $Content = ; close(FILE); return $Content; } sub readLine($) { my $Path = $_[0]; open(FILE, "<", $Path); my $Line = ; close(FILE); return $Line; } sub fixDistr($$$$) { my ($Distr, $DistrVersion, $Rel, $Build) = @_; if(not $Distr) { if(-f "$FixProbe_Logs/issue") { my $Issue = readLine("$FixProbe_Logs/issue"); if($Issue=~/ROSA Enterprise Linux Server release ([\d\.]+)/i) { $Distr = "rels"; $DistrVersion = $1; } } } if(not $Distr) { if(-f "$FixProbe_Logs/rpms") { my $RpmsLine = readLine("$FixProbe_Logs/rpms"); if($RpmsLine=~/\.([a-z]\w+)\.\w+\Z/i) { if(defined $DistSuffix{$1} and $DistSuffix{$1}=~/\A(.+?)\-(\d.*)\Z/) { $Distr = $1; $DistrVersion = $2; } } if(not $Distr) { my $Rpms = readFile("$FixProbe_Logs/rpms"); foreach my $Pkg (sort keys(%DistPackage)) { if($Rpms=~/\Q$Pkg\E/) { if($DistPackage{$Pkg}=~/\A(.+?)\-(\d.*)\Z/) { $Distr = $1; $DistrVersion = $2; } last; } } } } elsif(-f "$FixProbe_Logs/debs") { my $Debs = readFile("$FixProbe_Logs/debs"); if(index($Debs, "termux-")!=-1) { $Distr = "android"; $DistrVersion = undef; $Rel = undef; $Sys{"Type"} = "smartphone"; } } } # Support for MX if($Distr=~/\A(debian|ubuntu)/) { my $Debs = readFile("$FixProbe_Logs/debs"); if($Debs=~/(mx-system|ddm-mx|q4os-desktop|kubuntu-desktop|xubuntu-desktop|lubuntu-desktop|ubuntu-budgie-desktop|ubuntu-mate-desktop|ubuntudde-desktop|ubuntustudio-desktop|ubuntukylin-desktop) ([\d\.]+)/) { $Distr = $1; my $PkgVersion = $2; if($Distr=~/(mx|q4os)/) { $Distr = $1; $DistrVersion = $PkgVersion; $Rel = undef; $DistrVersion=~s/\A(\d+)\..+/$1/; } elsif($Distr=~/(kubuntu|xubuntu|lubuntu|ubuntu-budgie|ubuntu-mate|ubuntudde|ubuntustudio|ubuntukylin)/) { $Distr = $1; } } } if(not $Distr or $Distr=~/freedesktop/) { if($Sys{"Kernel"}=~/\drosa\b/) { $Distr = "rosa"; if($Sys{"Kernel"}=~/\A3\.0\./) { $DistrVersion = "2012lts"; } elsif($Sys{"Kernel"}=~/\A3\.(8|10)\./) { $DistrVersion = "2012.1"; } elsif($Sys{"Kernel"}=~/\A3\.(14|17|18|19)\./) { $DistrVersion = "2014.1"; } elsif($Sys{"Kernel"}=~/\A4\./) { $DistrVersion = "2014.1"; } elsif($Sys{"Kernel"}=~/\A5\./) { $DistrVersion = "2016.1"; } else { printMsg("ERROR", "failed to fix 'system' attribute (kernel is '".$Sys{"Kernel"}."')"); } } } if(not $Rel) { if($Distr eq "rosa") { if($DistrVersion eq "2012.1") { if($Sys{"Kernel"}=~/\A3\.10\.(3\d|4\d)\-/) { $Rel = "rosafresh-r3"; } elsif($Sys{"Kernel"}=~/\A3\.10\.19\-/) { $Rel = "rosafresh-r2"; } elsif($Sys{"Kernel"}=~/\A3\.8\.12\-/) { $Rel = "rosafresh-r1"; } } } } if($Distr eq "debian" and (not $DistrVersion or $DistrVersion!~/\A(\d|Testing|Unstable|Sid)/i)) { if($Sys{"Kernel"}=~/\A5.1/) { $DistrVersion = "11"; } elsif($Sys{"Kernel"}=~/\A(4\.19|4\.20|5\.[023456789])/) { $DistrVersion = "10"; } elsif($Sys{"Kernel"}=~/\A(4\.9|4\.1[012345678])/) { $DistrVersion = "9"; } elsif($Sys{"Kernel"}=~/\A3\.16/) { $DistrVersion = "8"; } elsif($Sys{"Kernel"}=~/\A3\.2/) { $DistrVersion = "7"; } } if($Distr eq "gentoo" and not $DistrVersion) { if($Sys{"Kernel"}=~/\A5\.(1[01234]|[56789])/) { $DistrVersion = "2.7"; } elsif($Sys{"Kernel"}=~/\A(5\.[01234]|4\.1[89]|4\.20)/) { $DistrVersion = "2.6"; } elsif($Sys{"Kernel"}=~/\A(4\.14)/) { $DistrVersion = "2.4.1"; } elsif($Sys{"Kernel"}=~/\A4\.[589]/) { $DistrVersion = "2.3"; } elsif($Sys{"Kernel"}=~/\A4\.4/) { $DistrVersion = "2.2"; } } if(not $Distr or $Distr=~/freedesktop/) { if($Sys{"Kernel"}=~/\.fc(\d\d)\./) { $Distr = "fedora"; $DistrVersion = $1; } elsif($Sys{"Kernel"}=~/\.el(\d+)[_\d]*(\.|\Z)/) { $Distr = "centos"; $DistrVersion = $1; } elsif($Sys{"Kernel"}=~/\d-generic\Z/) { $Distr = "ubuntu"; } elsif($Sys{"Kernel"}=~/-arch[12]-/) { $Distr = "arch"; } elsif($Sys{"Kernel"}=~/\-ck\d\Z/) { $Distr = "manualinux"; $DistrVersion = undef; } elsif($Sys{"Kernel"}=~/\-(gentoo)\-/) { $Distr = $1; $DistrVersion = undef; } } elsif($Sys{"Kernel"}=~/-siduction-/) { $Distr = "siduction"; } if(isBSD($Distr)) { if(my $Pkgs = readFile("$FixProbe_Logs/pkglist")) { # if($Pkgs=~/($KNOWN_BSD_ALL) /i) { # $Distr = lc($1); # } if($Pkgs=~/ghostbsd-pkg-conf (\d[\.\d]+)/i) { $Distr = "ghostbsd"; if(not $DistrVersion or $DistrVersion eq $Sys{"Freebsd_version"}) { $DistrVersion = $1; } } elsif($Pkgs=~/GhostBSD_PKG os\/kernel (\d[\.\d]+)/i) { $Distr = "ghostbsd"; if(not $DistrVersion or $DistrVersion eq $Sys{"Freebsd_version"}) { $DistrVersion = $1; } } elsif($Pkgs=~/TING opnsense/i) { $Distr = "ting"; } elsif($Pkgs=~/\/opnsense(|\-devel) (\d[\.\d]*\d)/i) { $Distr = "opnsense"; $DistrVersion = $2; } elsif(my @AllVers = ($Pkgs=~m/helloSystem\s+(.+)/gi)) { foreach my $ReleaseString (@AllVers) { $Distr = "hellosystem"; my $ReleaseString = $1; if($ReleaseString=~/(\d[\d\.]*)_(.+)/) { $DistrVersion = $1; $Build = $2; } else { $DistrVersion = $ReleaseString; } } } } if(readFile("$FixProbe_Logs/df")=~/ \/($KNOWN_BSD_ALL)\n/i) { $Distr = lc($1); } } setDistr($Distr, $DistrVersion, $Rel, $Build); } sub setDistr($$$$) { my ($Distr, $DistrVersion, $Rel, $Build) = @_; if($DistrVersion) { $Distr = $Distr."-".$DistrVersion; } if($Distr) { $Sys{"System"} = $Distr; } if($DistrVersion or $DistrVersion eq "0") { $Sys{"System_version"} = $DistrVersion; } if($Rel) { $Sys{"Systemrel"} = $Rel; } if($Build) { $Sys{"Systembuild"} = $Build; } } sub probeDistr() { my ($Name, $Release, $Descr) = (); my $FreeBSDVer = ""; my $OPNsenseVer = ""; my $OSname = ""; if($Opt{"FixProbe"}) { $FreeBSDVer = readFile($FixProbe_Logs."/freebsd-version"); $OPNsenseVer = readFile($FixProbe_Logs."/opnsense-version"); $OSname = readFile($FixProbe_Logs."/osname"); } else { if(isBSD($^O)) { if(checkCmd("freebsd-version")) { listProbe("logs", "freebsd-version"); $FreeBSDVer = runCmd("freebsd-version"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/freebsd-version", $FreeBSDVer); } } if(checkCmd("opnsense-version")) { listProbe("logs", "opnsense-version"); $OPNsenseVer = runCmd("opnsense-version"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/opnsense-version", $OPNsenseVer); } } $OSname = $^O; writeLog($LOG_DIR."/osname", $OSname); } } if($OSname) { $Name = $OSname; } if($FreeBSDVer) { $Release = $FreeBSDVer; $Sys{"Freebsd_version"} = $FreeBSDVer; } if(isBSD($Name)) { if(not $Release) { $Release = $Sys{"Kernel"}; } if($Release=~/(.+)-RELEASE-(.+)/) { $Release = $1."-".$2; } elsif($Release=~/(.+)-RELEASE\Z/) { $Release = $1; } if(not $Opt{"FixProbe"}) { if(my $OS_Release = readFile("/etc/os-release")) { # For future (e.g. on GhostBSD) listProbe("logs", "os-release"); writeLog($LOG_DIR."/os-release", $OS_Release); } } if($OSname=~/freebsd/) { if(not $Sys{"Freebsd_version"}) { $Sys{"Freebsd_version"} = $Release; } # FuryBSD my $OptLocal = ""; if($Opt{"FixProbe"}) { $OptLocal = readFile($FixProbe_Logs."/opt-local-bin"); } else { $OptLocal = join("\n", listDir("/opt/local/bin")); if($OptLocal) { writeLog($LOG_DIR."/opt-local-bin", $OptLocal); } } if($OptLocal=~/($KNOWN_BSD_ALL)/i) { $Name = lc($1); } # GhostBSD my $GhostBSDConf = ""; if($Opt{"FixProbe"}) { $GhostBSDConf = readFile($FixProbe_Logs."/GhostBSD.conf"); } else { if(-e "/etc/pkg/GhostBSD.conf") { $GhostBSDConf = "..."; } if($GhostBSDConf) { writeLog($LOG_DIR."/GhostBSD.conf", $GhostBSDConf); } } if($GhostBSDConf) { $Name = "ghostbsd"; } my $GhostBSDRc = ""; if($Opt{"FixProbe"}) { $GhostBSDRc = readFile($FixProbe_Logs."/rc.conf.ghostbsd"); } else { if(-e "/etc/rc.conf.ghostbsd") { $GhostBSDRc = "..."; } if($GhostBSDRc) { writeLog($LOG_DIR."/rc.conf.ghostbsd", $GhostBSDRc); } } if($GhostBSDRc) { $Name = "ghostbsd"; } my $GhostBSDVer = ""; if($Opt{"FixProbe"}) { $GhostBSDVer = readFile($FixProbe_Logs."/ghostbsd-version"); if(not $GhostBSDVer) { $GhostBSDVer = readFile($FixProbe_Logs."/ports_ver"); } } elsif($Name eq "ghostbsd") { if(checkCmd("ghostbsd-version")) { $GhostBSDVer = runCmd("ghostbsd-version"); writeLog($LOG_DIR."/ghostbsd-version", $GhostBSDVer); } elsif(checkCmd("pkg")) { $GhostBSDVer = runCmd("pkg rquery \'\%v\' ports"); chomp($GhostBSDVer); writeLog($LOG_DIR."/ghostbsd-version", $GhostBSDVer); } } if($GhostBSDVer) { $Release = $GhostBSDVer; } # OPNsense my $OPNsenseConf = ""; if($Opt{"FixProbe"}) { $OPNsenseConf = readFile($FixProbe_Logs."/OPNsense.conf"); } else { if(-e "/usr/local/etc/pkg/repos/OPNsense.conf") { $OPNsenseConf = "..."; } if($OPNsenseConf) { writeLog($LOG_DIR."/OPNsense.conf", $OPNsenseConf); } } if($OPNsenseConf) { $Name = "opnsense"; } if($OPNsenseVer=~/opnsense\s+(\d[\d\.]+)/i) { $Name = "opnsense"; $Release = $1; } # NomadBSD my $RootVersion = ""; if($Opt{"FixProbe"}) { $RootVersion = readFile($FixProbe_Logs."/VERSION"); } else { $RootVersion = readFile("/VERSION"); if($RootVersion) { writeLog($LOG_DIR."/VERSION", $RootVersion); } } if($RootVersion) { $Name = "nomadbsd"; chomp($RootVersion); $Release = $RootVersion; } # ClonOS my $EtcIssue = ""; if($Opt{"FixProbe"}) { $EtcIssue = readFile($FixProbe_Logs."/issue"); } else { $EtcIssue = readFile("/etc/issue"); $EtcIssue = hideIPs($EtcIssue); if($EtcIssue) { writeLog($LOG_DIR."/issue", $EtcIssue); } } if($EtcIssue=~/(ClonOS) ([^\s]+)/) { $Name = lc($1); $Release = $2; } # helloSystem my $StartHello = ""; if($Opt{"FixProbe"}) { $StartHello = readFile($FixProbe_Logs."/start-hello"); } else { $StartHello = checkCmd("start-hello"); if($StartHello) { writeLog($LOG_DIR."/start-hello", $StartHello); } } if($StartHello) { $Name = "hellosystem"; } } if(defined $Sys{"Freebsd_version"}) { $Sys{"Freebsd_release"} = $Sys{"Freebsd_version"}; $Sys{"Freebsd_release"}=~s/-.+\Z//; } if($OSname=~/netbsd/) { # OS108 my $SlimTheme = ""; if($Opt{"FixProbe"}) { $SlimTheme = readFile($FixProbe_Logs."/slim.theme"); } else { my $SlimFile = "/usr/pkg/share/slim/themes/default/slim.theme"; if(-e $SlimFile) { $SlimTheme = runCmd("head $SlimFile -n 1"); } if($SlimTheme) { writeLog($LOG_DIR."/slim.theme", $SlimTheme); } } if($SlimTheme=~/OS108/) { $Name = "os108"; } } # TrueOS and others my $Uname = ""; if($Opt{"FixProbe"}) { $Uname = readFile($FixProbe_Logs."/uname"); } elsif(checkCmd("uname")) { $Uname = runCmd("uname -v"); $Uname = hideEmail($Uname); $Uname = hidePaths($Uname); if($Uname) { writeLog($LOG_DIR."/uname", $Uname); } } if($Uname=~/($KNOWN_BSD_ALL)/i) { $Name = lc($1); } if($Uname=~/\b(ting)-(\d[\d\.]*\d)/i) { $Name = lc($1); $Release = lc($2); } if($Uname=~/RELENG_(\d+)_(\d+)_(\d+)/i) { $Release = $1.".".$2.".".$3; } if($Name!~/dragonfly/) { # There is os-release on DragonFly if($Name and $Release) { return ($Name, $Release, "", ""); } return ($Name, "", "", ""); } } my $LSB_Rel = ""; if($Opt{"FixProbe"}) { $LSB_Rel = readFile($FixProbe_Logs."/lsb_release"); } elsif(not isBSD($Name) and not $Opt{"Docker"} and not $Opt{"Snap"} and not $Opt{"Flatpak"} and checkCmd("lsb_release")) { listProbe("logs", "lsb_release"); $LSB_Rel = runCmd("lsb_release -i -d -r -c 2>/dev/null"); if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/lsb_release", $LSB_Rel); } } my $OS_Rel = ""; if($Opt{"FixProbe"}) { $OS_Rel = readFile($FixProbe_Logs."/os-release"); } else { listProbe("logs", "os-release"); $OS_Rel = readFile("/etc/os-release"); if($Opt{"Snap"}) { # Snap strict confinement my $OSRelHostFs = "/var/lib/snapd/hostfs/etc/os-release"; if(-e $OSRelHostFs) { $OS_Rel = readFile($OSRelHostFs); } } elsif($Opt{"Flatpak"}) { foreach my $OSRelHost ("/run/host/etc/os-release", "/run/host/usr/lib/os-release", "/var/run/host/etc/os-release", "/var/run/host/usr/lib/os-release") { if(-e $OSRelHost) { $OS_Rel = readFile($OSRelHost); last; } } } if($Opt{"HWLogs"}) { writeLog($LOG_DIR."/os-release", $OS_Rel); } } my $Sys_Rel = ""; if($Opt{"FixProbe"}) { $Sys_Rel = readFile($FixProbe_Logs."/system-release"); } else { listProbe("logs", "system-release"); $Sys_Rel = readFile("/etc/system-release"); if($Opt{"HWLogs"} and $Sys_Rel) { writeLog($LOG_DIR."/system-release", $Sys_Rel); } } my $LSB_Rel_F = ""; if($Opt{"FixProbe"}) { $LSB_Rel_F = readFile($FixProbe_Logs."/lsb-release"); } else { listProbe("logs", "lsb-release"); $LSB_Rel_F = readFile("/etc/lsb-release"); if($Opt{"HWLogs"} and $LSB_Rel_F) { writeLog($LOG_DIR."/lsb-release", $LSB_Rel_F); } } if($LSB_Rel) { # Desktop if($LSB_Rel=~/ID:\s*(.*)/) { $Name = $1; } if(lc($Name) eq "n/a") { $Name = ""; } if($LSB_Rel=~/Release:\s*(.*)/) { $Release = lc($1); $Release=~s/\A\Q$Name\E\-//gi; } if($Release eq "n/a") { $Release = ""; } if($Release and $Name) { $Release=~s/\A$Name[\s\-]+//i; } if($LSB_Rel=~/Description:\s*(.*)/) { $Descr = $1; } if($Name=~/\ARedHatEnterprise/i) { $Name = "rhel"; } elsif($Name=~/\A(ROSAEnterpriseServer|ROSACobalt)/i) { return ("rels", $Release, "", ""); } elsif($Name=~/\AROSAEnterpriseDesktop/i) { return ("red", $Release, "", ""); } elsif($Name=~/\ARosa\.DX/i) { if($Descr=~/(Chrome|Nickel|Cobalt)/i) { return ("rosa-dx-".lc($1), $Release, "", ""); } } elsif($Descr=~/\AROSA SX/i) { if($Descr=~/(CHROME|NICKEL|COBALT)/i) { return ("rosa-sx-".lc($1), $Release, "", ""); } } elsif($Descr=~/\AROSA (Chrome|Nickel|Cobalt) ([\d\.]+)/i) { return ("rosa-".lc($1), lc($2), "", ""); } elsif($Descr=~/\AROSA (Chrome|Nickel|Cobalt)\Z/i) { return ("rosa-".lc($1), $Release, "", ""); } elsif($Name=~/\AROSA/i) { my $Rel = ""; if($Descr=~/ R([\d\-\.]+)/i) { $Rel = "rosafresh-r".$1; } elsif($Descr=~/ Enterprise Desktop X([\d\-\.]+)/i) { $Rel = "red-x".$1; } elsif($OS_Rel=~/Fresh R(\d+) /) { $Rel = "rosafresh-r".$1; } return ("rosa", $Release, $Rel, ""); } elsif($Name=~/\AOpenMandriva/i) { return ("openmandriva", $Release, "", ""); } elsif($Name=~/\AopenSUSE Tumbleweed/i and $Release=~/\A\d\d\d\d\d\d\d\d\Z/) { return ("opensuse", $Release, "", ""); } elsif($Name eq "Pop") { return ("pop!_os", $Release, "", ""); } elsif(lc($Name) eq "neon") { return ("kde-neon", $Release, "", ""); } elsif($Descr=~/\A(Devuan|ECP VeiL|KDE neon|LMDE|Maui|openSUSE Leap|Parrot|Pop\!_OS|RED OS|BigLinux)/i) { $Name = $1; } elsif($Descr=~/\A(antiX|elementary OS)[-\s]([\d\.]+)/i) { $Name = $1; $Release = $2; } elsif($Descr=~/\A(SUSE Linux Enterprise Desktop)/i) { $Name = "sled"; } elsif($Descr=~/\A(SUSE Linux Enterprise Server)/i) { $Name = "sles"; } elsif($Name=~/\ACentOSStream/i) { $Name = "centos"; $Release = "stream"; } } if($LSB_Rel_F) { if($LSB_Rel_F=~/DISTRIB_ID[:=][ \t]*(.*)/) { $Name = $1; $Name=~s/\A"(.+)"\Z/$1/; $Name=~s/\s+\Z/$1/g; } if($LSB_Rel_F=~/DISTRIB_RELEASE[:=][ \t]*(.*)/) { $Release = lc($1); $Release=~s/\A"(.+)"\Z/$1/; $Release=~s/\A\Q$Name\E[\-\s]+//gi; } if($LSB_Rel_F=~/DISTRIB_DESCRIPTION[:=][ \t]*(.*)/) { $Descr = $1; } if($Descr=~/Easy Buster/) { $Name = "EasyOS"; } elsif($Descr=~/(LMDE|CryptoDATA|KDE neon|PuppyRus-A|BigLinux|Bluestar Linux)/) { $Name = $1; } elsif($Descr=~/(Linux Lite) ([\d\.]+)/) { $Name = $1; $Release = $2; } } if(grep { $Release eq $_ } ("amd64", "x86_64")) { $Release = undef; } if((not $Name or not $Release or $Name=~/arcolinux/i) and $OS_Rel) { if($OS_Rel=~/\bID=[ \t]*[\"\']*([^"'\n]+)/) { $Name = $1; $Name=~s/\s+\Z//; } elsif($OS_Rel=~/\bID_LIKE=[ \t]*[\"\']*([^"'\n]+)/) { $Name = $1; $Name=~s/\s+\Z//; } if($OS_Rel=~/\bNAME=[ \t]*[\"\']*([^"'\n]+)/) { my $RealName = $1; if($RealName=~/(Peppermint|Pop\!_OS|KDE neon|Acronis Cyber Infrastructure|Virtuozzo Infrastructure)/) { $Name = $1; } } if($OS_Rel=~/\bPRETTY_NAME=[ \t]*[\"\']*([^"'\n]+)/) { my $PrettyName = $1; if($PrettyName=~/(CryptoDATA|Debian|Docker Desktop|Devuan|ECP VeiL|GNOME OS|Itd Os|KDE Neon|LMDE|MakuluLinux|Makululinux|MocaccinoOS|OpenVZ|Parrot|pearOS|Pop\!_OS|Porteus|SkiffOS|Sn3rpOs|SuperX|Virtuozzo Hybrid Infrastructure|Windowsfx|XCP-ng)/) { $Name = $1; } elsif($PrettyName=~/(Linux Lite) ([\d\.]+)/) { $Name = $1; $Release = $2; } } if($OS_Rel=~/\bVERSION_ID=[ \t]*[\"\']*([^"'\n]+)/ and $Name ne "Linux Lite") { $Release = lc($1); $Release=~s/\A\Q$Name\E[_\- ]//i; if($Release eq "i") { $Release = undef; } } if($Name=~/Acronis|Ultimate|Virtuozzo/i) { if($OS_Rel=~/\bVERSION=[ \t]*[\"\']*([^"'\n]+)/) { $Release = lc($1); } } if($Release eq "n/a") { $Release = ""; } } if($Name=~/\A(CentOS|ClearOS|RHEL|Debian|MX)/i) { $Release=~s/\A(\d+)\..+/$1/; } #elsif($Name=~/\A(Endless)/i) { # $Release=~s/\A(\d+\.\d+)\..+/$1/; #} if((not $Name or not $Release) and $Sys_Rel) { if($Sys_Rel=~/\A(.+?)\s+release\s+([\d\.]+)/ or $Sys_Rel=~/\A(.+?)\s+([\d\.]+)/) { $Name = $1; $Release = lc($2); } } if($Name=~/funtoo/) { $Release=~s/\A(intel64-skylake-|generic_64-)//; } elsif($Name eq "blackpantheros") { $Name = "blackpanther-os"; } elsif($Name eq "elementary OS") { $Name = "elementary"; } elsif($Name=~/kali/) { $Release=~s/\Akali-//; } $Name = shortOS($Name); $Name = lc($Name); if($Name and $Release) { return ($Name, $Release, "", ""); } return ($Name, "", "", ""); } sub devID(@) { my @ID = grep { $_ } @_; return lc(join("-", @ID)); } sub fNum($) { my $N = $_[0]; if(length($N)==1) { $N = "0".$N; } return $N; } sub devSort($$) { return ($_[0]=~/\A(pci|usb)/ cmp $_[1]=~/\A(pci|usb)/); } sub writeDevsDump() { foreach my $ID (keys(%HW)) { $HW{$ID}{"Bus"} = getDeviceBus($ID); if((my $Count = getDeviceCount($ID))>1) { $HW{$ID}{"Count"} = $Count; } if(not $HW{$ID}{"Status"}) { $HW{$ID}{"Status"} = "detected"; } } my $HWDump = JSON::XS->new->pretty->indent->space_after->canonical->encode(\%HW); if($Opt{"FixProbe"}) { writeFile($Opt{"FixProbe"}."/devices.json", $HWDump); if(-e $Opt{"FixProbe"}."/devices") { unlink($Opt{"FixProbe"}."/devices"); } } else { writeFile($DATA_DIR."/devices.json", $HWDump); } } sub writeDevs() { my $HWData = ""; foreach my $ID (sort {devSort($b, $a)} sort keys(%HW)) { foreach (keys(%{$HW{$ID}})) { $HW{$ID}{$_}=~s/;/ /g; } my @D = (); push(@D, $ID); push(@D, $HW{$ID}{"Class"}); if(not $HW{$ID}{"Status"}) { $HW{$ID}{"Status"} = "detected"; } push(@D, $HW{$ID}{"Status"}); # test result push(@D, $HW{$ID}{"Type"}); push(@D, $HW{$ID}{"Driver"}); push(@D, $HW{$ID}{"Vendor"}); push(@D, $HW{$ID}{"Device"}); if($HW{$ID}{"SVendor"} or $HW{$ID}{"SDevice"}) { push(@D, $HW{$ID}{"SVendor"}); if(defined $HW{$ID}{"SDevice"} and $HW{$ID}{"SDevice"} ne "Device") { push(@D, $HW{$ID}{"SDevice"}); } } my $HWLine = join(";", @D)."\n"; $HWData .= $HWLine; if((my $Count = getDeviceCount($ID))>1) { foreach (2 .. $Count) { $HWData .= $HWLine; } } } if($Opt{"FixProbe"}) { writeFile($Opt{"FixProbe"}."/devices", $HWData); if(-e $Opt{"FixProbe"}."/devices.json") { unlink($Opt{"FixProbe"}."/devices.json"); } } else { writeFile($DATA_DIR."/devices", $HWData); } } sub writeHost() { my $Host = ""; foreach my $K (sort keys(%Sys)) { if($K eq "Name" or $K eq "Version") { next; } if($Sys{$K} ne "") { $Host .= lc($K).":".$Sys{$K}."\n"; } } if($Sys{"Name"}) { $Host .= "id:".$Sys{"Name"}."\n"; } # Host Info if($Opt{"FixProbe"}) { writeFile($Opt{"FixProbe"}."/host", $Host); } else { writeFile($DATA_DIR."/host", $Host); } } sub nonASCII($) { return $_[0]=~/[^\x00-\x7f]/; } sub readHost($) { my $Path = $_[0]; my $Content = readFile($Path."/host"); my %Map = ( "id"=>"Name", "hwaddr"=>"HWaddr", "de"=>"DE", "nics"=>"NICs" ); foreach my $Line (split(/\n/, $Content)) { if($Line=~/\A(\w+)\:(.*)\Z/) { my ($K, $V) = ($1, $2); if(defined $Map{$K}) { $K = $Map{$K}; } else { $K = ucfirst($K); } $Sys{$K} = $V; } } if(-s $FixProbe_Logs."/dmi_id" or -s $FixProbe_Logs."/dmidecode" or ($Sys{"Arch"}=~/arm|aarch/i and -s $FixProbe_Logs."/dmesg") or -s $FixProbe_Logs."/sysctl") { foreach ("Vendor", "Model", "Subvendor", "Submodel", "Type") { delete($Sys{$_}); } } $Sys{"NICs"} = 0; $Sys{"Monitors"} = 0; $Sys{"Sockets"} = undef; $Sys{"Cores"} = undef; $Sys{"Threads"} = undef; $Sys{"Op_modes"} = undef; $Sys{"Ram_used"} = undef; $Sys{"Ram_total"} = undef; $Sys{"Filesystem"} = undef; $Sys{"System"} = undef; $Sys{"Systemrel"} = undef; $Sys{"Microarch"} = undef; } sub getUser() { foreach my $Var ("SUDO_USER", "USERNAME", "USER") { if(defined $ENV{$Var} and $ENV{$Var} ne "root") { return $ENV{$Var}; } } return; } sub writeLogs() { print "Reading logs ... "; if($Opt{"ListProbes"}) { print "\n"; } # level=minimal if(enabledLog("bsdhwmon") and checkCmd("bsdhwmon")) { listProbe("logs", "bsdhwmon"); my $Bsdhwmon = runCmd("bsdhwmon 2>/dev/null"); if($Bsdhwmon=~/Your motherboard does not/) { $Bsdhwmon = ""; } writeLog($LOG_DIR."/bsdhwmon", $Bsdhwmon); } if($Admin) { if(not $Opt{"Docker"} and enabledLog("dmesg.1") and checkCmd("journalctl")) { listProbe("logs", "dmesg.1"); my $Dmesg_Old = runCmd("journalctl -a -k -b -1 -o short-monotonic 2>/dev/null | grep -v systemd"); $Dmesg_Old=~s/\]\s+.*?\s+kernel:/]/g; $Dmesg_Old = hideDmesg($Dmesg_Old); writeLog($LOG_DIR."/dmesg.1", $Dmesg_Old); } } if(enabledLog("xorg.log.1")) { listProbe("logs", "xorg.log.1"); my $XLog_Old = readFile("/var/log/Xorg.0.log.old"); if(my $SUser = getUser()) { # Old Xorg log in XWayland (Ubuntu 18.04) if(my $XLog_Old_U = readFile("/home/".$SUser."/.local/share/xorg/Xorg.0.log.old")) { $XLog_Old = $XLog_Old_U; } } else { # Live if(my $XLog_Old_U = readFile("/home/ubuntu/.local/share/xorg/Xorg.0.log.old")) { $XLog_Old = $XLog_Old_U; } } $XLog_Old = hideTags($XLog_Old, "Serial#"); $XLog_Old = hidePaths($XLog_Old); $XLog_Old = encryptUUIDs($XLog_Old); if(my $HostName = $ENV{"HOSTNAME"}) { $XLog_Old=~s/ \Q$HostName\E / NODE /g; } $XLog_Old = hideHost($XLog_Old); $XLog_Old = hideByRegexp($XLog_Old, qr/\s?([\w\s]+\’s)/); writeLog($LOG_DIR."/xorg.log.1", $XLog_Old); } if(enabledLog("mcelog") and checkCmd("mcelog")) { listProbe("logs", "mcelog"); my $Mcelog = runCmd("mcelog --client 2>&1"); if($Mcelog=~/No such file or directory/) { $Mcelog = ""; } writeLog($LOG_DIR."/mcelog", $Mcelog); } if(enabledLog("xorg.conf")) { listProbe("logs", "xorg.conf"); my $XorgConf = readFile("/etc/X11/xorg.conf"); if(not $XorgConf) { $XorgConf = readFile("/usr/share/X11/xorg.conf"); } if(not $XorgConf and isBSD()) { $XorgConf = readFile("/usr/local/etc/X11/xorg.conf"); } if(not $Opt{"Docker"} or $XorgConf) { writeLog($LOG_DIR."/xorg.conf", $XorgConf); } } if(enabledLog("grub") and -e "/etc/default/grub") { listProbe("logs", "grub"); my $Grub = readFile("/etc/default/grub"); $Grub = hidePaths($Grub); writeLog($LOG_DIR."/grub", $Grub); } if(not $Opt{"Docker"}) { if(enabledLog("grub.cfg") and -f "/boot/grub2/grub.cfg") { listProbe("logs", "grub.cfg"); my $GrubCfg = readFile("/boot/grub2/grub.cfg"); $GrubCfg = hidePaths($GrubCfg); $GrubCfg = encryptUUIDs($GrubCfg); $GrubCfg=~s/.*password.+/###/g; writeLog($LOG_DIR."/grub.cfg", $GrubCfg); } } if(checkCmd("xrandr")) { if(enabledLog("xrandr")) { listProbe("logs", "xrandr"); my $XRandr = runCmd("xrandr --verbose 2>&1"); $XRandr = clearLog_X11($XRandr); if(not $XRandr and defined $ENV{"XDG_SESSION_TYPE"}) { printMsg("WARNING", "X11-related logs are not collected (try to run 'sudo -E hw-probe ...')"); } writeLog($LOG_DIR."/xrandr", $XRandr); } if(enabledLog("xrandr_providers")) { listProbe("logs", "xrandr_providers"); my $XRandrProviders = runCmd("xrandr --listproviders 2>&1"); writeLog($LOG_DIR."/xrandr_providers", clearLog_X11($XRandrProviders)); } } if(enabledLog("glxinfo") and checkCmd("glxinfo")) { listProbe("logs", "glxinfo"); my $Glxinfo = runCmd("glxinfo 2>&1"); $Glxinfo = clearLog_X11($Glxinfo); $Glxinfo=~s/(GLX Visuals)(.|\n)+?\Z/$1\n...\n/g; writeLog($LOG_DIR."/glxinfo", $Glxinfo); } if(enabledLog("biosdecode") and checkCmd("biosdecode")) { listProbe("logs", "biosdecode"); my $BiosDecode = ""; if($Admin) { $BiosDecode = runCmd("biosdecode 2>/dev/null"); if(length($BiosDecode)<20) { $BiosDecode = ""; } } writeLog($LOG_DIR."/biosdecode", $BiosDecode); } # level=default if(not $Opt{"AppImage"} and enabledLog("cpupower") and checkCmd("cpupower")) { # TODO: Why doesn't work in AppImage? listProbe("logs", "cpupower"); my $CPUpower = ""; $CPUpower .= "frequency-info\n--------------\n"; $CPUpower .= runCmd("cpupower frequency-info 2>&1"); $CPUpower .= "\n"; $CPUpower .= "idle-info\n---------\n"; $CPUpower .= runCmd("cpupower idle-info 2>&1"); if($CPUpower=~/cpupower not found/) { $CPUpower = undef; } if($CPUpower) { writeLog($LOG_DIR."/cpupower", $CPUpower); } } if(enabledLog("dkms_status") and checkCmd("dkms")) { listProbe("logs", "dkms_status"); my $DkmsStatus = ""; if($Admin) { $DkmsStatus = runCmd("dkms status 2>&1"); } writeLog($LOG_DIR."/dkms_status", $DkmsStatus); } if(enabledLog("xdpyinfo") and checkCmd("xdpyinfo")) { listProbe("logs", "xdpyinfo"); if(my $Xdpyinfo = runCmd("xdpyinfo 2>&1")) { $Xdpyinfo=~s/(visual:(.|\n)+?)\Z/...\n/g; writeLog($LOG_DIR."/xdpyinfo", clearLog_X11($Xdpyinfo)); } } if(enabledLog("rpms") and checkCmd("rpm")) { listProbe("logs", "rpms"); my $Rpms = runCmd("rpm -qa 2>/dev/null | sort"); if($Rpms) { writeLog($LOG_DIR."/rpms", $Rpms); } } if(enabledLog("dpkg") and checkCmd("dpkg")) { listProbe("logs", "debs"); my $Dpkgs = runCmd("dpkg -l 2>/dev/null | awk '/^[hi]i/{print \$2,\$3,\$4}'"); if($Dpkgs) { writeLog($LOG_DIR."/debs", $Dpkgs); } } if(enabledLog("apk") and $Sys{"System"}=~/alpine/i and checkCmd("apk")) { listProbe("logs", "apk"); my $Apk = runCmd("apk info 2>/dev/null"); if($Apk) { writeLog($LOG_DIR."/apk", $Apk); } } if(enabledLog("pkglist")) { if(checkCmd("pacman")) { # Arch / Manjaro listProbe("logs", "pkglist"); my $Pkglist = runCmd("pacman -Q 2>/dev/null"); if($Pkglist) { writeLog($LOG_DIR."/pkglist", $Pkglist); } } if($Sys{"System"}=~/solus/i and checkCmd("eopkg")) { listProbe("logs", "pkglist"); my $Pkglist = runCmd("eopkg list-installed -l 2>/dev/null | grep Name:"); if($Pkglist) { $Pkglist=~s/Name\: //g; $Pkglist=~s/, version: / /g; $Pkglist=~s/, release: / r/g; writeLog($LOG_DIR."/pkglist", $Pkglist); } } if($Sys{"System"}=~/clear-linux/i and checkCmd("swupd")) { listProbe("logs", "pkglist"); my $BundleList = runCmd("swupd bundle-list"); if($BundleList) { writeLog($LOG_DIR."/bundle-list", $BundleList); } } if($Sys{"System"}=~/slackware/i and -d "/var/log/packages") { listProbe("logs", "pkglist"); my $LogPkgs = `ls -1 /var/log/packages | sort`; if($LogPkgs) { writeLog($LOG_DIR."/pkglist", $LogPkgs); } } if($Sys{"System"}=~/gentoo/i and -d "/var/db/pkg") { listProbe("logs", "pkglist"); my $DbPkgs = `ls /var/db/pkg/*`; if($DbPkgs) { writeLog($LOG_DIR."/pkglist", $DbPkgs); } } if(isOpenBSD() and checkCmd("pkg_info")) { listProbe("logs", "pkg_info"); my $PkgInfo = runCmd("pkg_info -qP"); if($PkgInfo) { writeLog($LOG_DIR."/pkglist", $PkgInfo); } } elsif(isNetBSD() and checkCmd("pkgin")) { listProbe("logs", "pkgin"); my $PkgList = runCmd("pkgin list | sort"); $PkgList=~s/\s+.+?\n/\n/g; if($PkgList) { writeLog($LOG_DIR."/pkglist", $PkgList); } } elsif($Sys{"System"}=~/midnightbsd/ and checkCmd("mport")) { listProbe("logs", "mport"); my $Pkginfo = runCmd("mport list"); $Pkginfo=~s/\s+.+?\n/\n/g; if($Pkginfo) { writeLog($LOG_DIR."/pkglist", $Pkginfo); } } elsif(defined $Sys{"Freebsd_release"} and $Sys{"Freebsd_release"} < 10.0) { listProbe("logs", "pkg_info"); my $PkgInfo = runCmd("pkg_info"); $PkgInfo=~s/\s+.+?\n/\n/g; if($PkgInfo) { writeLog($LOG_DIR."/pkglist", $PkgInfo); } } elsif(isBSD() and checkCmd("pkg")) { # any modern FreeBSD-based system listProbe("logs", "pkg"); my $PkgQuery = runCmd("pkg query --all '\%R \%o \%v' | sort"); if($PkgQuery) { writeLog($LOG_DIR."/pkglist", $PkgQuery); } } } if(not $Opt{"Docker"}) { if(enabledLog("rfkill") and checkCmd("rfkill")) { listProbe("logs", "rfkill"); my $Rfkill = runCmd("rfkill list 2>&1"); if($Opt{"Snap"} and $Rfkill=~/Permission denied|Bad file descriptor/) { $Rfkill = ""; } writeLog($LOG_DIR."/rfkill", $Rfkill); } } if(enabledLog("iw_list") and checkCmd("iw")) { listProbe("logs", "iw_list"); my $IwList = runCmd("iw list 2>&1"); if($Opt{"Snap"} and $IwList=~/Permission denied/) { $IwList = ""; } if($IwList) { writeLog($LOG_DIR."/iw_list", $IwList); } } if(enabledLog("iwconfig") and checkCmd("iwconfig")) { listProbe("logs", "iwconfig"); my $IwConfig = runCmd("iwconfig 2>&1"); $IwConfig = hideMACs($IwConfig); $IwConfig = hideTags($IwConfig, "ESSID"); writeLog($LOG_DIR."/iwconfig", $IwConfig); } if(enabledLog("nm-tool") and checkCmd("nm-tool")) { listProbe("logs", "nm-tool"); my $NmTool = runCmd("nm-tool 2>&1"); if($NmTool) { writeLog($LOG_DIR."/nm-tool", $NmTool); } } if(enabledLog("nmcli") and checkCmd("nmcli")) { listProbe("logs", "nmcli"); my $NmCli = runCmd("nmcli c 2>&1"); $NmCli=~s/.+\s+([^\s]+\s+[^\s]+\s+[^\s]+\s*\n)/XXX $1/g; $NmCli=~s/\AXXX /NAME/g; $NmCli = encryptUUIDs($NmCli); if($NmCli) { writeLog($LOG_DIR."/nmcli", $NmCli); } } if($Admin and enabledLog("fdisk") and checkCmd("fdisk") and not isBSD()) { listProbe("logs", "fdisk"); my $Fdisk = runCmd("fdisk -l 2>&1"); if($Opt{"Snap"} and $Fdisk=~/Permission denied/) { $Fdisk = ""; } $Fdisk = hidePaths($Fdisk); $Fdisk = hideTags($Fdisk, "Disk identifier"); if($Fdisk) { writeLog($LOG_DIR."/fdisk", $Fdisk); } } if(enabledLog("inxi") and my $InxiCmd = checkCmd("inxi")) { listProbe("logs", "inxi"); my $Inxi = undef; if(readLine($InxiCmd)=~/perl/) { # The new Perl inxi $Inxi = runCmd("inxi -Fxxxzmd --no-host 2>&1"); } else { # Old inxi $Inxi = runCmd("inxi -Fxzd -c 0 -! 31 2>&1"); } $Inxi=~s/\s+\w+\:\s*//g; writeLog($LOG_DIR."/inxi", $Inxi); } my $I2cdetect = ""; if(enabledLog("i2cdetect") and checkCmd("i2cdetect")) { listProbe("logs", "i2cdetect"); $I2cdetect = runCmd("i2cdetect -l 2>&1"); writeLog($LOG_DIR."/i2cdetect", $I2cdetect); } if($Admin and (enabledLog("ddcutil") or enabledLog("ddc")) and $Sys{"Type"}!~/$MOBILE_TYPE/ and $Sys{"Model"}!~/VirtualBox|QEMU|VMWare|Virtual Machine|Parallels Virtual/) { my $DDCUtilCmd = undef; if($Opt{"Snap"} or $Opt{"AppImage"} or $Opt{"Flatpak"}) { $DDCUtilCmd = findCmd("ddcutil"); } elsif(checkCmd("ddcutil")) { $DDCUtilCmd = "ddcutil"; } if($DDCUtilCmd) { listProbe("logs", "ddcutil"); my $DDCUtil = ""; my @Range = (0 .. 31); #if($I2cdetect) #{ # @Range = (); # foreach my $L (split(/\n/, $I2cdetect)) # { # if($L=~/i2c-(\d+).+(NVIDIA|nvkm|i915|Radeon|AMDGPU|DPD)/) # { # push(@Range, $1); # } # } #} foreach my $N (@Range) { my $DDCCmd = "$DDCUtilCmd probe --bus $N"; # if($Opt{"AppImage"} or $Opt{"Docker"}) { # $DDCCmd .= " --f1"; # } my $DDCProbe = runCmd($DDCCmd." --sleep-multiplier 0.5 | grep -v 'DDC Null Response'"); if($DDCProbe=~/Maximum retries exceeded/) { $DDCProbe = runCmd($DDCCmd); } if($DDCProbe) { if($DDCProbe!~/No monitor detected|communication failed/) { $DDCUtil .= "# ddcutil probe --bus $N\n"; $DDCUtil .= $DDCProbe."\n"; } } } if($Opt{"HWLogs"} and $DDCUtil) { $DDCUtil = encryptSerials($DDCUtil, "sn"); $DDCUtil=~s/(binary serial number ).+?(\n)/$1...$2/g; writeLog($LOG_DIR."/ddcutil", $DDCUtil); } } } if(-e "/sys/firmware/efi") # defined $KernMod{"efivarfs"} { # installed in EFI mode if(enabledLog("efivar") and checkCmd("efivar")) { listProbe("logs", "efivar"); my $Efivar = runCmd("efivar -l 2>&1"); if($Efivar=~/error listing variables/i) { $Efivar = ""; } writeLog($LOG_DIR."/efivar", $Efivar); } if($Admin and $Sys{"Arch"}=~/x86_64|amd64/) { if(enabledLog("efibootmgr") and checkCmd("efibootmgr")) { listProbe("logs", "efibootmgr"); my $Efibootmgr = runCmd("efibootmgr -v 2>&1"); if($Opt{"Snap"} and $Efibootmgr=~/Permission denied/) { $Efibootmgr = ""; } $Efibootmgr = encryptUUIDs($Efibootmgr); $Efibootmgr = hideByRegexp($Efibootmgr, qr/MAC\((.+?)\)/); $Efibootmgr = hideByRegexp($Efibootmgr, qr/0x([a-f\d]{8})/); $Efibootmgr = hideByRegexp($Efibootmgr, qr/U\.U\.I\.D\.=([a-fA-F\d\.]{17}-[a-fA-F\d\.]{9}-[a-fA-F\d\.]{9}-[a-fA-F\d\.]{9}-[a-fA-F\d\.]{25})/); writeLog($LOG_DIR."/efibootmgr", $Efibootmgr); } } if(enabledLog("boot_efi") and -d "/boot/efi" and not $Opt{"Snap"}) { listProbe("logs", "boot_efi"); my $BootEfi = runCmd("find /boot/efi 2>/dev/null | sort"); writeLog($LOG_DIR."/boot_efi", $BootEfi); } } my $Switch = "/sys/kernel/debug/vgaswitcheroo/switch"; if(enabledLog("vgaswitcheroo") and -e $Switch) { listProbe("logs", "vgaswitcheroo"); my $SInfo = readFile($Switch); writeLog($LOG_DIR."/vgaswitcheroo", $SInfo); } if(enabledLog("input_devices")) { listProbe("logs", "input_devices"); my $InputDevices = readFile("/proc/bus/input/devices"); if($InputDevices) { writeLog($LOG_DIR."/input_devices", $InputDevices); } } if(enabledLog("iostat") and checkCmd("iostat")) { listProbe("logs", "iostat"); my $Iostat = runCmd("iostat 2>&1"); $Iostat=~s/\(.+\)/(...)/; writeLog($LOG_DIR."/iostat", $Iostat); } if(enabledLog("acpi") and checkCmd("acpi")) { listProbe("logs", "acpi"); my $Acpi = runCmd("acpi -V 2>/dev/null"); writeLog($LOG_DIR."/acpi", $Acpi); } if(defined $KernMod{"fglrx"} and $KernMod{"fglrx"}!=0) { if(enabledLog("fglrxinfo") and checkCmd("fglrxinfo")) { listProbe("logs", "fglrxinfo"); my $Fglrxinfo = runCmd("fglrxinfo -t 2>&1"); writeLog($LOG_DIR."/fglrxinfo", $Fglrxinfo); } if(enabledLog("amdconfig") and checkCmd("amdconfig")) { listProbe("logs", "amdconfig"); my $AMDconfig = runCmd("amdconfig --list-adapters 2>&1"); writeLog($LOG_DIR."/amdconfig", $AMDconfig); } } elsif(defined $KernMod{"nvidia"} and $KernMod{"nvidia"}!=0) { if(enabledLog("nvidia-smi")) { foreach ("64", "") { my $NvidiaSmi_Path = "/usr/lib".$_."/nvidia/bin/nvidia-smi"; if(-e $NvidiaSmi_Path) { listProbe("logs", "nvidia-smi"); my $NvidiaSmi = runCmd("$NvidiaSmi_Path -q 2>&1"); writeLog($LOG_DIR."/nvidia-smi", $NvidiaSmi); last; } } } } if(enabledLog("vulkaninfo") and checkCmd("vulkaninfo")) { listProbe("logs", "vulkaninfo"); my $Vulkaninfo = runCmd("vulkaninfo 2>&1"); if($Vulkaninfo!~/Cannot create/i) { writeLog($LOG_DIR."/vulkaninfo", $Vulkaninfo); } } if(enabledLog("vdpauinfo") and checkCmd("vdpauinfo")) { listProbe("logs", "vdpauinfo"); my $Vdpauinfo = runCmd("vdpauinfo 2>&1"); if($Vdpauinfo=~/Failed to open/i) { $Vdpauinfo = undef; } if($Vdpauinfo) { writeLog($LOG_DIR."/vdpauinfo", clearLog_X11($Vdpauinfo)); } } if(enabledLog("vainfo") and checkCmd("vainfo")) { listProbe("logs", "vainfo"); my $Vainfo = ""; my $DriDir = "/dev/dri"; foreach my $DriDev (listDir($DriDir)) { if($DriDev!~/render/) { next; } my $VaInfoCmd = "vainfo --display drm --device $DriDir/$DriDev"; my $VaInfoRes = qx($VaInfoCmd 2>&1); if($VaInfoRes=~/failed with error/i) { next; } $Vainfo .= "# $VaInfoCmd\n"; $Vainfo .= "$VaInfoRes\n"; } if(not $Vainfo) { $Vainfo = runCmd("vainfo 2>&1"); if($Vainfo=~/failed with error/i) { $Vainfo = undef; } } if($Vainfo) { writeLog($LOG_DIR."/vainfo", clearLog_X11($Vainfo)); } } if(enabledLog("scsi")) { listProbe("logs", "scsi"); my $Scsi = readFile("/proc/scsi/scsi"); if($Scsi) { # list all devices in RAID writeLog($LOG_DIR."/scsi", $Scsi); } } if(enabledLog("ioports")) { listProbe("logs", "ioports"); my $IOports = readFile("/proc/ioports"); if($IOports) { writeLog($LOG_DIR."/ioports", $IOports); } } if(enabledLog("interrupts")) { listProbe("logs", "interrupts"); my $Interrupts = readFile("/proc/interrupts"); if($Interrupts) { writeLog($LOG_DIR."/interrupts", $Interrupts); } } my $Aplay = undef; if(enabledLog("aplay") and checkCmd("aplay")) { listProbe("logs", "aplay"); $Aplay = runCmd("aplay -l 2>&1"); if(length($Aplay)<80 and $Aplay=~/no soundcards found|not found/i) { $Aplay = ""; } writeLog($LOG_DIR."/aplay", $Aplay); } if(enabledLog("arecord") and checkCmd("arecord")) { listProbe("logs", "arecord"); my $Arecord = runCmd("arecord -l 2>&1"); if(length($Arecord)<80 and $Arecord=~/no soundcards found|not found/i) { $Arecord = ""; } writeLog($LOG_DIR."/arecord", $Arecord); } if(enabledLog("amixer") and checkCmd("amixer")) { listProbe("logs", "amixer"); if(not defined $Aplay) { $Aplay = runCmd("aplay -l"); } my %CardNums = (); while($Aplay=~/card\s+(\d+)/g) { $CardNums{$1} = 1; } my $Amixer = ""; foreach my $ACard (sort {int($a)<=>int($b)} keys(%CardNums)) { $Amixer .= runCmd("amixer -c$ACard info 2>&1"); $Amixer .= runCmd("amixer -c$ACard 2>&1"); $Amixer .= "\n"; } writeLog($LOG_DIR."/amixer", $Amixer); } if(enabledLog("alsactl") and checkCmd("alsactl")) { listProbe("logs", "alsactl"); system("alsactl store -f $TMP_DIR/alsactl 2>/dev/null"); if(-f "$TMP_DIR/alsactl") { move("$TMP_DIR/alsactl", $LOG_DIR."/alsactl"); } } if(enabledLog("systemd-analyze") and checkCmd("systemd-analyze")) { listProbe("logs", "systemd-analyze"); if(my $SystemdAnalyze = runCmd("systemd-analyze 2>/dev/null")) { $SystemdAnalyze .= "\n"; $SystemdAnalyze .= runCmd("systemd-analyze blame 2>/dev/null"); if($SystemdAnalyze) { $SystemdAnalyze = decorateSystemd($SystemdAnalyze); $SystemdAnalyze = hideDevDiskUUIDs($SystemdAnalyze); $SystemdAnalyze = hideByRegexp($SystemdAnalyze, qr/shaman\@(.+?)\.service/); writeLog($LOG_DIR."/systemd-analyze", $SystemdAnalyze); } } } if(enabledLog("gpu-manager.log") and -f "/var/log/gpu-manager.log") { # Ubuntu listProbe("logs", "gpu-manager.log"); if(my $GpuManager = readFile("/var/log/gpu-manager.log")) { writeLog($LOG_DIR."/gpu-manager.log", $GpuManager); } } if(not $Opt{"Docker"} and enabledLog("modprobe.d")) { listProbe("logs", "modprobe.d"); my @Modprobe = listDir("/etc/modprobe.d/"); my $Mprobe = ""; foreach my $Mp (@Modprobe) { if($Mp eq "00_modprobe.conf" or $Mp eq "01_mandriva.conf") { next; } $Mprobe .= $Mp."\n"; foreach (1 .. length($Mp)) { $Mprobe .= "-"; } $Mprobe .= "\n"; my $Content = readFile("/etc/modprobe.d/".$Mp); $Content=~s{http(s|)://[^ ]+}{}g; $Mprobe .= $Content; $Mprobe .= "\n\n"; } writeLog($LOG_DIR."/modprobe.d", $Mprobe); } if(enabledLog("xorg.conf")) { listProbe("logs", "xorg.conf.d"); my $XConfig = ""; my @XDirs = ("/etc/X11/xorg.conf.d", "/usr/share/X11/xorg.conf.d"); if(isBSD()) { @XDirs = ("/usr/local/etc/X11/xorg.conf.d/", @XDirs); } foreach my $XDir (@XDirs) { if(not -d $XDir) { next; } my @XorgConfD = listDir($XDir); foreach my $Xc (@XorgConfD) { if($Xc!~/\.conf\Z/) { next; } $XConfig .= $Xc."\n"; foreach (1 .. length($Xc)) { $XConfig .= "-"; } $XConfig .= "\n"; $XConfig .= readFile($XDir."/".$Xc); $XConfig .= "\n\n"; } } if(not $Opt{"Docker"} or $XConfig) { writeLog($LOG_DIR."/xorg.conf.d", $XConfig); } } if(enabledLog("rc.conf")) { listProbe("logs", "rc.conf"); my $RcConf = readFile("/etc/rc.conf"); $RcConf = hidePaths($RcConf); $RcConf = encryptUUIDs($RcConf); $RcConf = hideMACs($RcConf); $RcConf = hideIPs($RcConf); $RcConf=~s/((hostname|user|host|port|vm_list|autossh_rules|syslogd_flags)\s*=).+/$1.../g; $RcConf=~s/(openvpn)\w*\s*=.+/$1.../g; $RcConf=~s/[ ]*#.*//g; $RcConf=~s/[\n]{2,}/\n/g; writeLog($LOG_DIR."/rc.conf", $RcConf); } if(enabledLog("loader.conf")) { listProbe("logs", "loader.conf"); my $BootLoader = readFile("/boot/loader.conf"); $BootLoader = hidePaths($BootLoader); $BootLoader=~s/[ ]*#.*//g; $BootLoader=~s/[\n]{2,}/\n/g; writeLog($LOG_DIR."/loader.conf", $BootLoader); } if(enabledLog("gpart") and checkCmd("gpart")) { listProbe("logs", "gpart"); my $Gpart = runCmd("gpart show 2>/dev/null"); $Gpart = hidePaths($Gpart); writeLog($LOG_DIR."/gpart", $Gpart); } if(enabledLog("gpart_list") and checkCmd("gpart")) { listProbe("logs", "gpart_list"); my $GpartList = runCmd("gpart list -a 2>/dev/null"); $GpartList = hidePaths($GpartList); $GpartList = encryptUUIDs($GpartList); if($GpartList) { writeLog($LOG_DIR."/gpart_list", $GpartList); } } if(enabledLog("vmstat") and checkCmd("vmstat")) { listProbe("logs", "vmstat"); my $Vmstat = runCmd("vmstat 2>/dev/null"); writeLog($LOG_DIR."/vmstat", $Vmstat); } if(enabledLog("top_head") and checkCmd("top")) { listProbe("logs", "top_head"); my $TopHead = runCmd("top -b -d1 | head -n 4 2>/dev/null"); $TopHead=~s/(last pid:\s+)\d+/$1.../; $TopHead=~s/\s+[^\s]+\s+\d\d:\d\d:\d\d//; writeLog($LOG_DIR."/top_head", $TopHead); } if($Opt{"Scanners"}) { if(enabledLog("sane-find-scanner") and checkCmd("sane-find-scanner")) { listProbe("logs", "sane-find-scanner"); my $FindScanner = runCmd("sane-find-scanner -q 2>/dev/null"); writeLog($LOG_DIR."/sane-find-scanner", $FindScanner); } if(enabledLog("scanimage") and checkCmd("scanimage")) { listProbe("logs", "scanimage"); my $Scanimage = runCmd("scanimage -L 2>/dev/null | grep -v v4l"); if($Scanimage=~/No scanners were identified/i) { $Scanimage = ""; } writeLog($LOG_DIR."/scanimage", $Scanimage); } } if(enabledLog("drm_info") and checkCmd("drm_info")) { listProbe("logs", "drm_info"); my $DrmInfo = runCmd("drm_info 2>/dev/null"); writeLog($LOG_DIR."/drm_info", $DrmInfo); } # level=maximal if(enabledLog("firmware") and -d "/lib/firmware") { listProbe("logs", "firmware"); my $Firmware = undef; if(isBSD()) { $Firmware = runCmd("find /boot/firmware -type f | sort"); } else { $Firmware = runCmd("find /lib/firmware -type f | sort"); } $Firmware=~s{/lib/firmware/}{}g; writeLog($LOG_DIR."/firmware", $Firmware); } if(enabledLog("top") and checkCmd("top")) { listProbe("logs", "top"); my $TopInfo = runCmd("top -n 1 -b 2>&1"); if(my $SessUser = getUser()) { $TopInfo=~s/ \Q$SessUser\E / USER /g; } writeLog($LOG_DIR."/top", $TopInfo); } if(enabledLog("pstree") and checkCmd("pstree")) { listProbe("logs", "pstree"); my $Pstree = runCmd("pstree 2>&1"); writeLog($LOG_DIR."/pstree", $Pstree); } if(enabledLog("numactl") and checkCmd("numactl")) { listProbe("logs", "numactl"); my $Numactl = runCmd("numactl -H"); if($Numactl) { writeLog($LOG_DIR."/numactl", $Numactl); } } if(enabledLog("slabtop") and checkCmd("slabtop")) { listProbe("logs", "slabtop"); my $Slabtop = runCmd("slabtop -o"); writeLog($LOG_DIR."/slabtop", $Slabtop); } # scan for available WiFi networks if(enabledLog("iw_scan") and checkCmd("iw")) { listProbe("logs", "iw_scan"); my $IwScan = ""; if($Admin) { foreach my $I (sort keys(%WLanInterface)) { $IwScan .= $I."\n"; foreach (1 .. length($I)) { $IwScan .= "-"; } $IwScan .= "\n"; $IwScan .= runCmd("iw dev $I scan 2>&1"); $IwScan .= "\n"; } } $IwScan = hideTags($IwScan, "SSID|UUID|Serial Number"); $IwScan = hideMACs($IwScan); writeLog($LOG_DIR."/iw_scan", $IwScan); } # scan for available bluetooth connections if(enabledLog("hcitool_scan") and checkCmd("hcitool")) { listProbe("logs", "hcitool_scan"); my $HciScan = runCmd("hcitool scan --class 2>&1"); if($HciScan=~/No such device/i) { $HciScan = ""; } $HciScan = hideMACs($HciScan); if($HciScan) { writeLog($LOG_DIR."/hcitool_scan", $HciScan); } } if(enabledLog("route") and checkCmd("route")) { listProbe("logs", "route"); my $Route = runCmd("route 2>&1"); $Route = hideIPs($Route); writeLog($LOG_DIR."/route", $Route); } if(enabledLog("xvinfo") and checkCmd("xvinfo")) { listProbe("logs", "xvinfo"); my $XVInfo = runCmd("xvinfo 2>&1"); $XVInfo = encryptUUIDs($XVInfo); writeLog($LOG_DIR."/xvinfo", clearLog_X11($XVInfo)); } if(enabledLog("lsinitrd") and checkCmd("lsinitrd")) { listProbe("logs", "lsinitrd"); my $Lsinitrd = runCmd("lsinitrd 2>&1"); $Lsinitrd=~s/.*?(\w+\s+\d+\s+\d\d\d\d\s+)/$1/g; writeLog($LOG_DIR."/lsinitrd", $Lsinitrd); } if(enabledLog("update-alternatives") and checkCmd("update-alternatives")) { listProbe("logs", "update-alternatives"); my $Alternatives = runCmd("update-alternatives --list 2>/dev/null"); writeLog($LOG_DIR."/update-alternatives", $Alternatives); } if($Opt{"Printers"}) { if($Admin) { my $MAX_P_LEN = 1000; my $ELog = "/var/log/cups/error_log"; if(enabledLog("cups_error_log") and -e $ELog) { listProbe("logs", "cups_error_log"); my $CupsError = readFile($ELog); if(length($CupsError)>$MAX_P_LEN) { $CupsError = "...\n\n".substr($CupsError, -$MAX_P_LEN); } writeLog($LOG_DIR."/cups_error_log", $CupsError); } my $ALog = "/var/log/cups/access_log"; if(enabledLog("cups_access_log") and -e $ALog) { listProbe("logs", "cups_access_log"); my $CupsAccess = readFile($ALog); if(length($CupsAccess)>$MAX_P_LEN) { $CupsAccess = "...\n\n".substr($CupsAccess, -$MAX_P_LEN); } writeLog($LOG_DIR."/cups_access_log", $CupsAccess); } } } # Disabled as it can hang the system # my $SuperIO = ""; # if($Admin) { # $SuperIO = runCmd("superiotool -d 2>/dev/null"); # } # writeLog($LOG_DIR."/superiotool", $SuperIO); if($Opt{"DumpACPI"}) { listProbe("logs", "acpidump"); if(isBSD()) { my $AcpiDump_Decoded = ""; if($Admin and checkCmd("acpidump")) { $AcpiDump_Decoded = runCmd("acpidump -dt 2>/dev/null"); } writeLog($LOG_DIR."/acpidump_decoded", $AcpiDump_Decoded); } else { my $AcpiDump = ""; # To decode acpidump: # 1. acpixtract -a acpidump # 2. iasl -d ECDT.dat if($Admin) { if(checkCmd("acpidump")) { $AcpiDump = runCmd("acpidump 2>/dev/null"); } } writeLog($LOG_DIR."/acpidump", $AcpiDump); if($Opt{"DecodeACPI"}) { if(-s "$LOG_DIR/acpidump") { decodeACPI("$LOG_DIR/acpidump", "$LOG_DIR/acpidump_decoded"); } } } } print "Ok\n"; } sub checkCmd(@) { my $Cmd = shift(@_); my $Verify = undef; if(@_) { $Verify = shift(@_); } if(index($Cmd, "/")!=-1 and -x $Cmd) { # relative or absolute path return $Cmd; } my @Paths = split(/:/, $ENV{"PATH"}); if(isNetBSD()) { push(@Paths, "/usr/sbin", "/sbin", "/usr/pkg/sbin"); } if(not $Verify) { @Paths = sort {length($a)<=>length($b)} @Paths; } foreach my $Dir (@Paths) { $Dir=~s{/+\Z}{}g; if(-x "$Dir/$Cmd") { if($Verify) { if(not `$Dir/$Cmd --version 2>/dev/null`) { next; } } return "$Dir/$Cmd"; } } return; } sub findCmd($) { my $Cmd = $_[0]; if(my $Path = checkCmd($Cmd, 1)) { return $Path; } return $Cmd; } sub decodeACPI($$) { my ($Dump, $Output) = @_; $Dump = abs_path($Dump); if(not checkCmd("acpixtract") or not checkCmd("iasl")) { return 0; } my $TmpDir = $TMP_DIR."/acpi"; mkpath($TmpDir); chdir($TmpDir); # list data my $DSL = runCmd("acpixtract -l \"$Dump\" 2>&1"); $DSL .= "\n"; $DSL=~s{\Q$Dump\E}{acpidump}; # extract *.dat system("acpixtract -a \"$Dump\" >/dev/null 2>&1"); # decode *.dat my @Files = listDir("."); foreach my $File (@Files) { if($File=~/\A(.+)\.dat\Z/) { my $Name = $1; if($Name=~/dsdt/i) { # next; } runCmd("iasl -d \"$File\" 2>&1"); my $DslFile = $Name.".dsl"; if(-f $DslFile) { $DSL .= uc($Name)."\n"; foreach (1 .. length($Name)) { $DSL .= "-"; } $DSL .= "\n"; my $Data = readFile($DslFile); $Data=~s{\A\s*/\*.*?\*/\s*}{}sg; $DSL .= $Data; $DSL .= "\n"; $DSL .= "\n"; } unlink($File); unlink($DslFile); } } chdir($ORIG_DIR); writeFile($Output, $DSL); rmtree($TmpDir); return 1; } sub clearLog_X11($) { if(length($_[0])<$EMPTY_LOG_SIZE and $_[0]=~/No protocol specified|Can't open display|unable to open display|Unable to connect to|cannot connect to|couldn't open display/i) { return ""; } return $_[0]; } sub clearLog($) { my $Log = $_[0]; my $Sc = chr(27); $Log=~s/$Sc\[.*?m//g; $Log=~s/$Sc%G//g; return $Log; } sub showInfo() { my $ShowDir = $DATA_DIR; if($Opt{"Source"}) { if(-f $Opt{"Source"}) { if(isPkg($Opt{"Source"})) { my $Pkg = abs_path($Opt{"Source"}); chdir($TMP_DIR); system("tar", "-m", "-xf", $Pkg); chdir($ORIG_DIR); if($?) { printMsg("ERROR", "failed to extract package (".$?.")"); exitStatus(1); } if(my @Dirs = listDir($TMP_DIR)) { $ShowDir = $TMP_DIR."/".$Dirs[0]; } else { printMsg("ERROR", "failed to extract package"); exitStatus(1); } } else { printMsg("ERROR", "not a package"); exitStatus(1); } } elsif(-d $Opt{"Source"}) { $ShowDir = $Opt{"Source"}; } else { printMsg("ERROR", "can't access '".$Opt{"Source"}."'"); exitStatus(1); } } else { if(not -d $DATA_DIR) { printMsg("ERROR", "'".$DATA_DIR."' is not found, please make probe first"); exitStatus(1); } } my %Tbl; my %STbl; my $Devs = {}; if(-e $ShowDir."/devices") { foreach my $L (split(/\s*\n\s*/, readFile($ShowDir."/devices"))) { my @Info = split(/;/, $L); my %Dev = ( "ID" => $Info[0], "Class" => $Info[1], "Status" => $Info[2], "Type" => $Info[3], "Driver" => $Info[4], "Vendor" => $Info[5], "Device" => $Info[6], "SVendor" => $Info[7], "SDevice" => $Info[8] ); my $ID = $Dev{"ID"}; $Dev{"Bus"} = getDeviceBus($ID); if(not defined $Devs->{$ID}) { $Devs->{$ID} = \%Dev; } if(not defined $Devs->{$ID}{"Count"}) { $Devs->{$ID}{"Count"} = 0; } $Devs->{$ID}{"Count"} += 1; } } elsif(-e $ShowDir."/devices.json" and $USE_JSON_XS) { require Encode; $Devs = JSON::XS::decode_json(Encode::encode_utf8(readFile($ShowDir."/devices.json"))); } foreach my $ID (keys(%{$Devs})) { $Devs->{$ID}{"ID"} = $ID; if(not defined $TypeOrder{$Devs->{$ID}->{"Type"}}) { $TypeOrder{$Devs->{$ID}->{"Type"}} = "Z"; } if(not defined $BusOrder{$Devs->{$ID}->{"Bus"}}) { $TypeOrder{$Devs->{$ID}->{"Bus"}} = "Z"; } } my @AllCols = ("Bus", "ID", "Class", "Vendor", "Device", "Type", "Driver", "Status"); my @ShortCols = ("Bus", "ID", "Vendor", "Device", "Type"); if(isBSD($^O)) { @ShortCols = ("Bus", "Vendor", "Device", "Type"); } foreach my $ID (sort {$BusOrder{$Devs->{$a}{"Bus"}} cmp $BusOrder{$Devs->{$b}{"Bus"}}} sort {$TypeOrder{$Devs->{$a}{"Type"}} cmp $TypeOrder{$Devs->{$b}{"Type"}}} sort {$Devs->{$a}{"Bus"} cmp $Devs->{$b}{"Bus"}} sort {$Devs->{$a}{"Type"} cmp $Devs->{$b}{"Type"}} sort keys(%{$Devs})) { my $Dev = $Devs->{$ID}; foreach my $Attr (@AllCols) { if(not defined $Dev->{$Attr}) { $Dev->{$Attr} = undef; } } foreach my $Attr (keys(%{$Dev})) { if(not defined $Tbl{$Attr}) { $Tbl{$Attr} = []; } my $Val = $Dev->{$Attr}; if($Attr eq "ID") { if(index($Val, "-serial-")!=-1) { $Val=~s/\-serial\-(.+?)\Z//; } } if($Opt{"Compact"}) { if($Attr eq "ID") { $Val=~s/\A(\w+:)//g; $Val = shortStr($Val, 19); } elsif($Attr eq "Vendor") { $Val = shortStr($Val, 16); } elsif($Attr eq "Device") { $Val = shortStr($Val, 35); } elsif($Attr eq "Type") { $Val = shortStr($Val, 12); } elsif($Attr eq "Driver") { $Val = shortStr($Val, 10); } } push(@{$Tbl{$Attr}}, $Val); if($Dev->{"Count"}>1) { foreach (2 .. $Dev->{"Count"}) { push(@{$Tbl{$Attr}}, $Val); } } } } foreach my $L (split(/\s*\n\s*/, readFile($ShowDir."/host"))) { if($L=~/(\w+):(.*)/) { my ($Attr, $Val) = ($1, $2); if($Opt{"Compact"}) { if($Attr eq "id") { $Val = shortStr($Val, 25); } } $STbl{$Attr} = $Val; } } print "\n"; if($Opt{"Show"} or $Opt{"ShowHost"}) { print "Host Info\n"; print "=========\n\n"; foreach my $Attr ("system", "arch", "kernel", "vendor", "model", "year", "type", "hwaddr", "id") { if($STbl{$Attr}) { print ucfirst($Attr).": "; print " " x (length("kernel")-length($Attr)); print $STbl{$Attr}."\n"; } } print "\n\n"; } if($Opt{"ShowDevices"}) { my $Rows = $#{$Tbl{"ID"}}; my $DevsTitle = "Devices (".($Rows + 1).")"; print $DevsTitle."\n"; print "=" x (length($DevsTitle)); print "\n\n"; if(defined $Opt{"Verbose"}) { showTable(\%Tbl, $Rows, @AllCols); } else { showTable(\%Tbl, $Rows, @ShortCols); } print "\n"; } } sub getDeviceBus($) { if($_[0]=~/\A([^:]+)\:/) { my $Bus = uc($1); if($Bus=~/BAT|BIOS|BOARD|CPU|MEM|FLOPPY/) { $Bus = "SYS"; } return $Bus; } return undef; } sub shortStr($$) { my ($Str, $Len) = @_; if(length($Str)>$Len) { return substr($Str, 0, $Len-3)."..."; } return $Str; } sub showTable(@) { my ($Tbl, $Num, @Columns) = @_; my %Max; foreach my $Col (sort keys(%{$Tbl})) { if(not defined $Max{$Col}) { $Max{$Col} = 0; } foreach my $El (@{$Tbl->{$Col}}) { if(length($El) > $Max{$Col}) { $Max{$Col} = length($El); } } } my $Br = ""; my $Hd = ""; foreach my $Col (@Columns) { my $Hd_T = $Col; if(not $Hd) { $Hd_T = "| ".$Hd_T; } $Hd .= "| ".$Col; $Hd .= mulCh(" ", $Max{$Col} - length($Col) + 1); $Br .= "+"; $Br .= mulCh("-", $Max{$Col} + 2); } $Br .= "+"; $Hd .= "|"; print $Br."\n"; print $Hd."\n"; print $Br."\n"; foreach my $Row (0 .. $Num) { foreach my $Col (@Columns) { my $El = $Tbl->{$Col}[$Row]; print "| ".$El; print alignStr($El, $Max{$Col} + 1); } print "|\n"; } print $Br."\n"; } sub mulCh($$) { my $Str = ""; foreach (1 .. $_[1]) { $Str .= $_[0]; } return $Str; } sub alignStr($$) { my $Align = ""; foreach (1 .. ($_[1] - length($_[0]))) { $Align .= " "; } return $Align; } sub checkGraphics() { print "Check graphics ... "; my $Glxgears = getGears(); listProbe("tests", "glxgears"); my $Out_I = runCmd("vblank_mode=0 $Glxgears"); $Out_I=~s/(\d+ frames)/\n$1/; $Out_I=~s/GL_EXTENSIONS =.*?\n//; writeLog($TEST_DIR."/glxgears", clearLog_X11($Out_I)); my $Out_D = undef; if(grep {defined $WorkMod{$_}} @G_DRIVERS_INTEL and $Sys{"Type"}=~/$MOBILE_TYPE/) { # Hybrid graphics if(defined $KernMod{"nvidia"}) { # check NVidia Optimus with proprietary driver if(checkCmd("optirun")) { listProbe("tests", "glxgears (Nvidia)"); $Out_D = runCmd("optirun $Glxgears"); } } elsif(defined $KernMod{"nouveau"}) { # check NVidia Optimus with free driver listProbe("tests", "glxgears (Nouveau)"); system("xrandr --setprovideroffloadsink 1 0"); # nouveau Intel if($?) { printMsg("ERROR", "failed to run glxgears test on discrete card"); } else { $Out_D = runCmd("DRI_PRIME=1 vblank_mode=0 $Glxgears"); } } elsif(defined $KernMod{"radeon"} or defined $KernMod{"amdgpu"}) { # check Radeon Hybrid graphics with free driver listProbe("tests", "glxgears (Radeon)"); $Out_D = runCmd("DRI_PRIME=1 vblank_mode=0 $Glxgears"); } } if($Out_D) { $Out_D=~s/(\d+ frames)/\n$1/; $Out_D=~s/GL_EXTENSIONS =.*?\n//; writeLog($TEST_DIR."/glxgears_discrete", clearLog_X11($Out_D)); } checkGraphicsCardOutput($Out_I, $Out_D); print "Ok\n"; } sub checkGraphicsCardOutput($$) { my ($Int, $Discrete) = @_; my $Success = "frames in"; if(grep {defined $WorkMod{$_}} @G_DRIVERS_INTEL) { if(defined $WorkMod{"nvidia"}) { if($Discrete=~/$Success/) { setCardStatus("nvidia", "works"); } } elsif(defined $WorkMod{"nouveau"}) { if($Discrete=~/$Success/ and $Discrete=~/GL_VENDOR.+nouveau/i) { setCardStatus("nouveau", "works"); } } elsif(defined $WorkMod{"radeon"} or defined $WorkMod{"amdgpu"}) { if($Discrete=~/$Success/) { setCardStatus("radeon", "works"); } } if($Int=~/$Success/ and $Int=~/GL_VENDOR.+Intel/i) { foreach (@G_DRIVERS_INTEL) { setCardStatus($_, "works"); } } } elsif(defined $WorkMod{"nouveau"} or defined $WorkMod{"nvidia"}) { if($Int=~/$Success/) { setCardStatus("nouveau", "works"); } } elsif(defined $WorkMod{"radeon"} or defined $WorkMod{"amdgpu"} or defined $WorkMod{"fglrx"}) { if($Int=~/$Success/) { setCardStatus("radeon", "works"); } } } sub setCardStatus($$) { my ($Dr, $Status) = @_; my $V = $DriverVendor{$Dr}; if(defined $GraphicsCards{$V}) { foreach my $ID (sort keys(%{$GraphicsCards{$V}})) { if($GraphicsCards{$V}{$ID} eq $Dr or $Status eq "detected") { $HW{$ID}{"Status"} = $Status; if($Status eq "works") { setAttachedStatus($ID, $Status); } } } } } sub setCardStatusByVendor($$$) { my ($V, $Status, $Driver) = @_; if(defined $GraphicsCards{$V}) { foreach my $ID (sort keys(%{$GraphicsCards{$V}})) { $HW{$ID}{"Status"} = $Status; if($Status eq "works") { setAttachedStatus($ID, $Status); } if($Driver and $HW{$ID}{"Driver"}=~/vgapci/) { $HW{$ID}{"Driver"} = $Driver; } } } } sub checkHW() { # TODO: test operability, set status to "works", "malfunc" or "failed" if($Opt{"CheckGraphics"} and checkCmd("glxgears")) { if(defined $ENV{"WAYLAND_DISPLAY"} or $ENV{"XDG_SESSION_TYPE"} eq "wayland" or defined $ENV{"DISPLAY"}) { checkGraphics(); } } if($Opt{"CheckMemory"} and checkCmd("memtester")) { print "Check memory ... "; my $Memtester = runCmd("memtester 8 1"); $Memtester=~s/\A(.|\n)*(Loop)/$2/g; while($Memtester=~s/[^\cH]\cH//g) {} writeLog($TEST_DIR."/memtester", $Memtester); print "Ok\n"; } if($Opt{"CheckHdd"}) { my $CheckHddCmd = undef; if(isBSD()) { if(enabledLog("diskinfo") and checkCmd("diskinfo")) { $CheckHddCmd = "diskinfo -c"; } } elsif(checkCmd("hdparm")) { $CheckHddCmd = "hdparm -t"; } if($CheckHddCmd) { print "Check HDDs ... "; my $HDD_Read = ""; my $HDD_Num = 0; foreach my $Dr (sort keys(%HDD)) { my $DrFile = basename($Dr); my $Title = ""; if(my $DevId = $HDD{$Dr}) { my $HddInfo = $HW{$DevId}; $Title = $HddInfo->{"Vendor"}." ".$HddInfo->{"Device"}; } elsif(defined $HDD_Info{$DrFile}) { $Title = $HDD_Info{$DrFile}{"Title"}; } my $Cmd = $CheckHddCmd." ".$Dr; my $Out = runCmd($Cmd); $Out=~s/\A\n\Q$Dr\E\:?\n//; $Out=~s/.+#.+\n//g; $HDD_Read .= "Drive $Title\n"; $HDD_Read .= "$Cmd\n"; $HDD_Read .= $Out."\n"; if(defined $Opt{"LimitCheckHdd"} and $HDD_Num++>=$Opt{"LimitCheckHdd"}) { last; } } if($HDD_Read) { writeLog($TEST_DIR."/hdd_read", $HDD_Read); } print "Ok\n"; } } my $Md5 = "md5sum"; if(isBSD()) { $Md5 = "md5"; } if($Opt{"CheckCpu"} and checkCmd("dd") and checkCmd($Md5)) { if(my @CPUs = grep { /\Acpu:/ } keys(%HW)) { print "Check CPU ... "; my $CPU_Info = $HW{$CPUs[0]}; runCmd("dd if=/dev/zero bs=1M count=512 2>$TMP_DIR/cpu_perf | $Md5"); my $CPUPerf = $CPU_Info->{"Vendor"}." ".$CPU_Info->{"Device"}."\n"; $CPUPerf .= "dd if=/dev/zero bs=1M count=512 | $Md5\n"; $CPUPerf .= readFile("$TMP_DIR/cpu_perf"); writeLog($TEST_DIR."/cpu_perf", $CPUPerf); print "Ok\n"; if($CPUPerf=~/copied,.+, (.+?)\Z/) { $HW{$CPUs[0]}{"Rate"} = $1; } } } } sub getGears() { return "glxgears -info 2>/dev/null & sleep 17 ; killall glxgears 2>/dev/null"; } sub listProbe($$) { if($Opt{"ListProbes"}) { print $_[0]."/".$_[1]."\n"; } } my %EnabledLog = ( "minimal" => [ "acpidump", "acpidump_decoded", "arcconf", "biosdecode", "cpuinfo", "dev", "df", "dmesg", "dmesg.1", "dmidecode", "dmi_id", "edid", "edid-decode", "ethtool_p", "glxinfo", "grub", "hciconfig", "hdparm", "hwinfo", "ifconfig", "ip_addr", "lsb_release", "lsb-release", "lsblk", "lscpu", "lsmod", "lspci", "lspci_all", "lsusb", "mcelog", "megacli", "megactl", "mmcli", "opensc-tool", "os-release", "power_supply", "sensors", "smartctl", "smartctl_megaraid", "system-release", "upower", "usb-devices", "xorg.log", "xorg.log.1", "xrandr", "xrandr_providers" ], "default" => [ "acpi", "amdconfig", "amixer", "apk", "aplay", "arecord", "boot.log", "boot_efi", "cpuid", "cpupower", "dkms_status", "dpkg", "drm_info", "efibootmgr", "efivar", "fdisk", "fglrxinfo", "getprop", "gpu-manager.log", "grub.cfg", "hp-probe", "i2cdetect", "input_devices", "interrupts", "inxi", "ioports", "iostat", "iw_list", "iwconfig", "lspnp", "modprobe.d", "nm-tool", "nmcli", "nvidia-smi", "pkglist", "rfkill", "rpms", "sane-find-scanner", "scanimage", "scsi", "smart-log", "systemd-analyze", "uptime", "vainfo", "vdpauinfo", "vgaswitcheroo", "vulkaninfo", "xdpyinfo", "xinput", "xorg.conf" ], "maximal" => [ "alsactl", "cups_access_log", "cups_error_log", "ddcutil", "ddc", "findmnt", "firmware", "fstab", "hcitool_scan", "hddtemp", "iw_scan", "modinfo", "mount", "neofetch", "numactl", "route", "slabtop", "systemctl", "udev-db", "update-alternatives", "xvinfo" ], "optional" => [ "avahi", "lsinitrd", "pstree", "top" ] ); my %EnabledLog_BSD = ( "minimal" => [ "apm", "arcconf", "atactl", "biosdecode", "curl", "dev", "devinfo", "df", "dmesg", "dmidecode", "fdisk", "geom", "glxinfo", "gpart", "gpart_list", "hwstat", "ifconfig", "kldstat", "locale", "lscpu", "mcelog", "megacli", "mfiutil", "modstat", "pciconf", "pcictl", "pcictl_n", "pcidump", "pkglist", "shasum", "smartctl", "smartctl_megaraid", "sndstat", "sysctl", "usbconfig", "usbctl", "usbdevs", "xorg.log", "xrandr" ], "default" => [ "acpidump", "acpidump_decoded", "amixer", "aplay", "arecord", "camcontrol", "config", "cpuid", "diskinfo", "disklabel", "drm_info", "efibootmgr", "efivar", "iostat", "kldstat_v", "lsblk", "lspci", "lspci_all", "lsusb", "neofetch", "ofwdump", "sane-find-scanner", "scanimage", "smart-log", "top_head", "uptime", "vmstat", "x86info", "xinput", "xorg.conf", "xorg.log.1", "xrandr_providers" ], "maximal" => [ "alsactl", "firmware", "fstab", "loader.conf", "mount", "rc.conf", "sysinfo" ], "optional" => [] ); sub completeEnabledLogs() { foreach my $LL ("minimal", "default") { foreach my $L (@{$EnabledLog{$LL}}) { push(@{$EnabledLog{"maximal"}}, $L); } } foreach my $L (@{$EnabledLog{"minimal"}}) { push(@{$EnabledLog{"default"}}, $L); } } sub enabledLog($) { my $Name = $_[0]; if(defined $Opt{"Disable"}) { if(grep { $_ eq $Name } split(/,/, $Opt{"Disable"})) { return 0; } } if(defined $Opt{"Enable"}) { if(grep { $_ eq $Name } split(/,/, $Opt{"Enable"})) { return 1; } } if(grep { $_ eq $Name } @{$EnabledLog{$Opt{"LogLevel"}}}) { return 1; } if(defined $Sys{"System"} and $Sys{"System"}=~/ROSA/i) { if($Opt{"LogLevel"} eq "default") { if($Name eq "fstab") { return 1; } } } return 0; } sub getMaxLogSize($) { my $Log = $_[0]; my $MaxSize = 2*$MAX_LOG_SIZE; if(grep {$Log eq $_} @LARGE_LOGS) { $MaxSize = $MAX_LOG_SIZE; } if($Log eq "boot.log") { $MaxSize = $MAX_LOG_SIZE/8; } return $MaxSize; } sub writeLog($$) { my ($Path, $Content) = @_; my $Log = basename($Path); if(not grep {$Log eq $_} @ProtectedLogs) { my $MaxSize = getMaxLogSize($Log); if(length($Content)>$MaxSize) { if($Log eq "boot.log") { # Save end of log $Content = substr($Content, -$MaxSize+4); $Content=~s/\A.*?\n//; $Content = "...\n".$Content; } else { $Content = substr($Content, 0, $MaxSize-3)."..."; } } } writeFile($Path, $Content); } sub appendFile($$) { my ($Path, $Content) = @_; if(my $Dir = dirname($Path)) { mkpath($Dir); } open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n"); print FILE $Content; close(FILE); } sub writeFile($$) { my ($Path, $Content) = @_; return if(not $Path); if(my $Dir = dirname($Path)) { mkpath($Dir); } open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n"); print FILE $Content; close(FILE); } sub readPciIds_A($$) { my ($Path, $Info) = @_; readPciIds($Path, $Info); if(-e "$Path.add") { readPciIds("$Path.add", $Info); } } sub readUsbIds_A($$) { my ($Path, $Info) = @_; readUsbIds($Path, $Info); if(-e "$Path.add") { readUsbIds("$Path.add", $Info); } } sub readPciIds($$) { my $List = readFile($_[0]); my $Info = $_[1]; my ($V, $D, $SV, $SD, $C, $SC, $SSC) = (); foreach (split(/\n/, $List)) { if(/\A(\t*)([a-f\d]{4}) /) { my $L = length($1); if($L==0) { $V = $2; if(/[a-f\d]{4}\s+(.*?)\Z/) { $Info->{"V"}{$V} = $1; } } elsif($L==1) { $D = $2; if(/\t[a-f\d]{4}\s+(.*?)\Z/) { $Info->{"I"}{$V}{$D} = $1; } } elsif($L==2) { if(/\t([a-f\d]{4}) ([a-f\d]{4})\s+(.*?)\Z/) { $SV = $1; $SD = $2; $Info->{"D"}{$V}{$D}{$SV}{$SD} = $3; } } } elsif(/\AC ([a-f\d]{2}) (.+)/) { $C = $1; $Info->{"C"}{$C} = $2; $Info->{"C"}{$C."00"} = $2; } elsif(/\A(\t+)([a-f\d]{2}) (.+)/) { my $L = length($1); if($L==1) { $SC = $2; $Info->{"C"}{$C.$SC} = $3; } elsif($L==2) { $SSC = $2; $Info->{"C"}{$C.$SC.$SSC} = $3; } } } } sub readUsbIds($$) { my $List = readFile($_[0]); my $Info = $_[1]; my ($V, $D) = (); foreach (split(/\n/, $List)) { if(/\A(\t*)([a-f\d]{4}) /) { my $L = length($1); if($L==0) { $V = $2; if(/[a-f\d]{4}\s+(.*?)\Z/) { $UsbVendor{$V} = $1; } } elsif($L==1) { $D = $2; if(/\t[a-f\d]{4}\s+(.*?)\Z/) { $Info->{$V}{$D} = $1; } } } } } sub readSdioIds_Sys() { readSdioIds("/usr/share/hwdata/sdio.ids", \%SdioInfo, \%SdioVendor); } sub readSdioIds($$$) { my ($Path, $Info, $Vnds) = @_; if(not -e $Path) { return; } my $List = readFile($Path); my ($V, $D); foreach (split(/\n/, $List)) { if(/\A(\t*)(\w{4}) /) { my $L = length($1); if($L==0) { $V = $2; if(/\A\w{4}\s+(.*?)\Z/) { $Vnds->{$V} = $1; } } elsif($L==1) { $D = $2; if(/\t\w{4}\s+(.*?)\Z/) { $Info->{$V}{$D} = $1; } } } } } sub downloadProbe($$) { my ($ID, $Dir) = @_; my $Page = downloadFileContent("$URL/index.php?probe=$ID"); if(index($Page, "ERROR(3):")!=-1) { return -1; } if(index($Page, "ERROR(1):")!=-1) { printMsg("ERROR", "You are not allowed temporarily to download probes"); rmtree($Dir."/logs"); exitStatus(1); } if(not $Page) { printMsg("ERROR", "Internet connection is required"); exitStatus(1); } print "Importing probe $ID\n"; my %LogDir = ("log"=>$Dir."/logs", "test"=>$Dir."/tests"); mkpath($LogDir{"log"}); mkpath($LogDir{"test"}); my $NPage = ""; foreach my $Line (split(/\n/, $Page)) { if($Line=~/(href|src)=['"]([^"']+?)['"]/) { my $Url = $2; if($Url=~/((css|js|images)\/[^?]+)/) { my ($SPath, $Subj) = ($1, $2); my $Content = downloadFileContent($URL."/".$Url); writeFile($Dir."/".$SPath, $Content); if($Subj eq "css") { while($Content=~s{url\(['"]([^'"]+)['"]\)}{}) { my $FPath = dirname($SPath)."/".$1; mkpath($Dir."/".dirname($FPath)); downloadFile($URL."/".$FPath, $Dir."/".$FPath); } } } elsif($Url=~/(log|test)\=([^&?]+)/) { my ($LogType, $LogName) = ($1, $2); my $LogPath = $LogDir{$LogType}."/".$LogName.".html"; my $Log = downloadFileContent($URL."/".$Url); if(index($Log, "ERROR(1):")!=-1) { printMsg("ERROR", "You are not allowed temporarily to download probes"); rmtree($Dir."/logs"); exitStatus(1); } $Log = preparePage($Log); $Log=~s{(['"])(css|js|images)/}{$1../$2/}g; $Log=~s{index.php\?probe=$ID}{../index.html}; writeFile($LogPath, $Log); my $LogD = basename($LogDir{$LogType}); $Line=~s/\Q$Url\E/$LogD\/$LogName.html/; } elsif($Url eq "index.php?probe=$ID") { $Line=~s/\Q$Url\E/index.html/; } elsif($Url=~/\A#/) { # Do nothing } else { $Line=~s/\Q$Url\E/$URL\/$Url/g; } } $NPage .= $Line."\n"; } $NPage=~s&\Q\E(.|\n)+\Q\E\n&This probe is available online by this URL in the Hardware Database.

&; writeFile($Dir."/index.html", preparePage($NPage)); return 0; } sub preparePage($) { my $Content = $_[0]; $Content=~s&\Q\E(.|\n)+?\Q\E\n&&; $Content=~s&\Q\E(.|\n)+?\Q\E\n&&; $Content=~s&\Q\E(.|\n)+?\Q\E\n&&; $Content=~s&\Q\E(.|\n)+?\Q\E\n&


\n
\n&; return $Content; } sub downloadFileContent($) { my $Url = $_[0]; $Url=~s/&/&/g; if(checkCmd("curl")) { my $Cmd = getCurlCmd($Url); return `$Cmd`; } else { return getRequest($Url, "NoSSL"); } } sub downloadFile($$) { my ($Url, $Output) = @_; $Url=~s/&/&/g; if(checkCmd("curl")) { my $Cmd = getCurlCmd($Url)." --output \"$Output\""; return `$Cmd`; } else { writeFile($Output, getRequest($Url, "NoSSL")); } } sub getCurlCmd($) { my $Url = $_[0]; my $Cmd = "curl -s -L \"$Url\""; $Cmd .= " --ipv4 --compressed"; $Cmd .= " --connect-timeout 5"; $Cmd .= " --retry 1"; $Cmd .= " -A \"Mozilla/5.0 (X11; Linux x86_64; rv:50.0) Gecko/20100101 Firefox/50.123\""; return $Cmd; } sub importProbes($) { my $Dir = $_[0]; if($Opt{"Snap"}) { $Dir = $ENV{"SNAP_USER_COMMON"}."/".$Dir; } elsif($Opt{"Flatpak"}) { $Dir = $ENV{"XDG_DATA_HOME"}."/".$Dir; } if(not -d $Dir) { mkpath($Dir); if(not $Opt{"Group"}) { setPublic($Dir); } } my ($Imported, $OneProbe) = (undef, undef); my $IndexInfo = eval ( readFile($Dir."/index.info") ) || {}; if(my $Inv = $Opt{"Group"}) { my $TopPage = downloadFileContent("$URL/index.php?view=computers&inventory=".$Inv); my @Computers = ($TopPage=~/Computer ([a-f\d]+) /g); foreach my $C (@Computers) { print "Computer $C\n"; my $ComputerPage = downloadFileContent("$URL/index.php?computer=".$C."&inventory=".$Inv); my @ComputerProbes = ($ComputerPage=~/ Probe ([a-f\d]+) /g); my $MaxElems = 2; if($#ComputerProbes>$MaxElems-1) { splice(@ComputerProbes, $MaxElems); } foreach my $P (@ComputerProbes) { if(defined $IndexInfo->{"SkipProbes"}{$P}) { next; } my $To = $Dir."/".$P; if(not -e $To or not -e "$To/logs") { if(downloadProbe($P, $To)!=-1) { my %Prop = (); $Prop{"hwaddr"} = uc($C); if($ComputerPage=~/Probe $P (.+?) -->/) { foreach (split(";", $1)) { if(/\A(\w+?):'(.+)'\Z/) { $Prop{$1} = $2; } } } writeFile($To."/probe.info", Data::Dumper::Dumper(\%Prop)); $Imported = $P; } else { $IndexInfo->{"SkipProbes"}{$P} = 1; } } } } } else { my @Paths = (); if(-d $PROBE_DIR) { foreach my $P (listDir($PROBE_DIR)) { push(@Paths, $PROBE_DIR."/".$P); } } my $OldProbes = getOldProbeDir(); if($OldProbes and -d $OldProbes) { # ROSA: changed probe place in 1.3 foreach my $P (listDir($OldProbes)) { push(@Paths, $OldProbes."/".$P); } } foreach my $D (@Paths) { my $P = basename($D); if($P eq "LATEST" or not -d $D or not listDir($D)) { next; } if(defined $IndexInfo->{"SkipProbes"}{$P}) { next; } my $To = $Dir."/".$P; if(not -e $To or not -e "$To/logs") { if(downloadProbe($P, $To)!=-1) { my $TmpDir = $TMP_DIR."/hw.info"; system("tar -xf $D/* -C $TMP_DIR"); my %Prop = (); foreach my $Line (split(/\n/, readFile($TmpDir."/host"))) { if($Line=~/(\w+):(.*)/) { $Prop{$1} = $2; } } my @DStat = stat($TmpDir); $Prop{"date"} = $DStat[9]; # last modify time $Prop{"hwaddr"} = uc($Prop{"hwaddr"}); writeFile($To."/probe.info", Data::Dumper::Dumper(\%Prop)); $Imported = $P; setPublic($To, "-R"); rmtree($TmpDir); } else { $IndexInfo->{"SkipProbes"}{$P} = 1; } } } } writeFile($Dir."/index.info", Data::Dumper::Dumper($IndexInfo)); if(not $Opt{"Group"}) { setPublic($Dir."/index.info"); } if(not $Imported) { print "No probes to import\n"; } my %Indexed = (); foreach my $P (listDir($Dir)) { if(not -d "$Dir/$P") { next; } my $D = $Dir."/".$P; my $Prop = eval ( readFile($D."/probe.info") ) || {}; $Indexed{uc($Prop->{"hwaddr"})}{$P} = $Prop; $OneProbe = $P; } if(not $OneProbe) { return -1; } my $LIST = ""; foreach my $HWaddr (sort keys(%Indexed)) { my @Probes = sort {$Indexed{$HWaddr}{$b}->{"date"} cmp $Indexed{$HWaddr}{$a}->{"date"}} keys(%{$Indexed{$HWaddr}}); my $Hw = $Indexed{$HWaddr}{$Probes[0]}; my $Title = undef; if($Hw->{"vendor"} and $Hw->{"model"}) { $Title = join(" ", $Hw->{"vendor"}, $Hw->{"model"}); } elsif($Hw->{"type"}) { if($Hw->{"vendor"}) { $Title = $Hw->{"vendor"}." ".ucfirst($Hw->{"type"})." (".getShortHWid($Hw->{"hwaddr"}).")"; } else { $Title = ucfirst($Hw->{"type"})." (".getShortHWid($Hw->{"hwaddr"}).")"; } } else { if($Hw->{"vendor"}) { $Title = $Hw->{"vendor"}." Computer (".getShortHWid($Hw->{"hwaddr"}).")"; } else { $Title = "Computer (".getShortHWid($Hw->{"hwaddr"}).")"; } } $LIST .= "

$Title

\n"; $LIST .= "\n"; $LIST .= "\n"; $LIST .= ""; if(not $Opt{"Group"}) { $LIST .= ""; } $LIST .= "\n\n"; foreach my $P (@Probes) { my $System = $Indexed{$HWaddr}{$P}->{"system"}; my $SystemClass = $System; if($System=~s/\A(\w+)-/$1 /) { $SystemClass = $1; } $LIST .= "\n"; $LIST .= "\n"; $LIST .= "\n"; $LIST .= "\n"; $LIST .= "\n"; if(not $Opt{"Group"}) { $LIST .= "\n"; } $LIST .= "\n"; } $LIST .= "
ProbeArchSystemDateDesc
\n"; $LIST .= "$P\n"; $LIST .= "\n"; $LIST .= $Indexed{$HWaddr}{$P}->{"arch"}; $LIST .= "\n"; $LIST .= "  ".ucfirst($System); $LIST .= "\n"; $LIST .= getDateStamp($Indexed{$HWaddr}{$P}->{"date"}); $LIST .= "\n"; $LIST .= $Indexed{$HWaddr}{$P}->{"id"}; $LIST .= "
\n"; $LIST .= "
\n"; } my $Descr = "This is your collection of probes. See more probes and computers online in the Hardware Database."; my $INDEX = readFile($Dir."/".$OneProbe."/index.html"); $INDEX=~s{\Q\E(.|\n)+\Q\E\n}{

Probes Timeline

\n$Descr\n$LIST\n}; $INDEX=~s{(\Q\E)(.|\n)+(\Q\E)}{$1 Probes Timeline $3}; $INDEX=~s{(['"])(css|js|images)/}{$1$OneProbe/$2/}g; writeFile($Dir."/index.html", $INDEX); if(not $Opt{"Group"}) { setPublic($Dir."/index.html"); } print "Created index: $Dir/index.html\n"; } sub getShortHWid($) { my $HWid = $_[0]; if(length($HWid) eq $HASH_LEN_CLIENT) { $HWid = substr($HWid, 0, 5); } else { $HWid=~s/\A(\w+\-\w+).+\-(\w+)\Z/$1...$2/; } return $HWid; } sub getDateStamp($) { my $Date = localtime($_[0]); if($Date=~/\w+\s+(\w+\s+\d+)\s+\d+:\d+:\d+\s+(\d+)/) { return "$1, $2"; } return $Date; } sub getTimeStamp($) { my $Date = localtime($_[0]); if($Date=~/\w+\s+\w+\s+\d+\s+(\d+:\d+):\d+\s+\d+/) { return $1; } return $Date; } sub getYear($) { my $Date = localtime($_[0]); if($Date=~/ (\d+)\Z/) { return $1; } return undef; } sub setPublic(@) { my $Path = shift(@_); my $R = undef; if(@_) { $R = shift(@_); } if(not checkCmd("chmod")) { return; } my @Chmod = ("chmod", "777"); if($R) { push(@Chmod, $R); } push(@Chmod, $Path); system(@Chmod); if(not $Opt{"Snap"} and not $Opt{"Flatpak"}) { if(my $SessUser = getUser()) { my @Chown = ("chown", $SessUser.":".$SessUser); if($R) { push(@Chown, $R); } push(@Chown, $Path); system(@Chown); } } } sub fixLsUsb($) { my $Content = $_[0]; my @Content_New = (); foreach my $Block (split(/\n\n/, $Content)) { if($Block=~/: ID (\w{4}):(\w{4})/) { my ($V, $D) = ($1, $2); if(defined $UsbVendor{$V}) { my $Vendor = $UsbVendor{$V}; if(defined $UsbInfo{$V}{$D}) { my $Product = $UsbInfo{$V}{$D}; $Block=~s{(:\s+ID\s+$V:$D)[ ]+\n}{$1 $Vendor $Product\n}; $Block=~s{(idVendor\s+0x$V)[ ]+\n}{$1 $Vendor\n}; $Block=~s{(idProduct\s+0x$D)[ ]+\n}{$1 $Product\n}; } } } push(@Content_New, $Block); } return join("\n\n", @Content_New); } sub fixLsPci_All($) { my $Content = $_[0]; my @Content_New = (); foreach my $Block (split(/\n\n/, $Content)) { if($Block=~/ Class \[([a-f\d]+)\]: Device \[(\w{4}):(\w{4})\]/) { my ($C, $V, $D) = ($1, $2, $3); if(defined $PciInfo{"V"}{$V}) { my $Vendor = $PciInfo{"V"}{$V}; if(defined $PciInfo{"I"}{$V}{$D}) { my $Product = $PciInfo{"I"}{$V}{$D}; $Block=~s{(\]:) Device (\[$V:$D\])}{$1 $Vendor $Product $2}; if($Block=~/Subsystem: Device \[(\w{4}):(\w{4})\]/) { my ($SV, $SD) = ($1, $2); if(my $SubVendor = $PciInfo{"V"}{$SV}) { my $Subsystem = "Device"; if(defined $PciInfo{"D"}{$V}{$D}{$SV}{$SD}) { $Subsystem = $PciInfo{"D"}{$V}{$D}{$SV}{$SD}; } elsif($V eq $SV and $D eq $SD) { $Subsystem = $Product; } $Block=~s{(Subsystem:) Device (\[$SV:$SD\])}{$1 $SubVendor $Subsystem $2}; } } } } if(defined $PciInfo{"C"}{$C}) { my $Class = $PciInfo{"C"}{$C}; $Block=~s{ Class (\[$C\]:)}{ $Class $1}; } } push(@Content_New, $Block); } return join("\n\n", @Content_New); } sub fixLsPci($) { my $Content = $_[0]; my @Content_New = (); my %Dev = (); foreach my $Block (split(/\n\n/, $Content)) { foreach my $Attr ("Class", "Vendor", "Device", "SVendor", "SDevice") { if($Block=~/$Attr:.*\[([a-f\d]{4})\]/) { $Dev{$Attr} = $1; } } my $C = $Dev{"Class"}; if(defined $PciInfo{"C"}{$C}) { my $Class = $PciInfo{"C"}{$C}; $Block=~s{(Class:\s+)Class(\s+\[$C\])}{$1$Class$2}; } my ($V, $D) = ($Dev{"Vendor"}, $Dev{"Device"}); if(defined $PciInfo{"V"}{$V}) { my $Vendor = $PciInfo{"V"}{$V}; $Block=~s{(Vendor:\s+)Vendor(\s+\[$V\])}{$1$Vendor$2}; if(defined $PciInfo{"I"}{$V}{$D}) { my $Product = $PciInfo{"I"}{$V}{$D}; $Block=~s{(Device:\s+)Device(\s+\[$D\])}{$1$Product$2}; my ($SV, $SD) = ($Dev{"SVendor"}, $Dev{"SDevice"}); if(my $SubVendor = $PciInfo{"V"}{$SV}) { $Block=~s{(SVendor:\s+)Unknown vendor(\s+\[$SV\])}{$1$SubVendor$2}; my $Subsystem = undef; if(defined $PciInfo{"D"}{$V}{$D}{$SV}{$SD}) { $Subsystem = $PciInfo{"D"}{$V}{$D}{$SV}{$SD}; } elsif($V eq $SV and $D eq $SD) { $Subsystem = $Product; } if($Subsystem) { $Block=~s{(SDevice:\s+)Device(\s+\[$SD\])}{$1$Subsystem$2}; } } } } push(@Content_New, $Block); } return join("\n\n", @Content_New); } sub fixLogs($) { my $Dir = $_[0]; if(-f "$Dir/hwinfo" and -s "$Dir/hwinfo" < 2*$EMPTY_LOG_SIZE) { # Support for HW Probe 1.4 if(readFile("$Dir/hwinfo")=~/unrecognized arguments|error while loading shared libraries/) { # hwinfo: error: unrecognized arguments: --all # hwinfo: error while loading shared libraries: libhd.so.21: cannot open shared object file: No such file or directory writeFile("$Dir/hwinfo", ""); } } foreach my $L ("iostat", "systemd-analyze", "systemctl", "disklabel") { # Support for HW Probe 1.3-1.4 # iostat: command not found if(-f "$Dir/$L" and -s "$Dir/$L" < 50) { unlink($Dir."/$L"); } } foreach my $L ("glxinfo", "xdpyinfo", "xinput", "vdpauinfo", "xrandr") { if(-e "$Dir/$L" and -s "$Dir/$L" < $EMPTY_LOG_SIZE) { if(not clearLog_X11(readFile("$Dir/$L"))) { writeFile("$Dir/$L", ""); } } } if(-f "$Dir/vulkaninfo") { # Support for HW Probe 1.3 if(readFile("$Dir/vulkaninfo")=~/Cannot create/i) { unlink("$Dir/vulkaninfo"); } } if(-f "$Dir/vainfo" and -s "$Dir/vainfo" < $EMPTY_LOG_SIZE) { # Support for HW Probe 1.4 # error: failed to initialize display if(readFile("$Dir/vainfo")=~/failed to initialize/) { writeFile("$Dir/vainfo", ""); } } if(-f "$Dir/cpupower" and -s "$Dir/cpupower" < $EMPTY_LOG_SIZE) { # Support for HW Probe 1.3 if(readFile("$Dir/cpupower")=~/cpupower not found/) { unlink("$Dir/cpupower"); } } if(-f "$Dir/rfkill" and -s "$Dir/rfkill") { # Support for HW Probe 1.4 # Can't open RFKILL control device: No such file or directory if(readFile("$Dir/rfkill")=~/No such file or directory|Bad file descriptor/) { writeFile("$Dir/rfkill", ""); } } foreach my $L ("aplay", "arecord") { if(-e "$Dir/$L" and -s "$Dir/$L" < 50) { if(readFile("$Dir/$L")=~/command not found/) { writeFile("$Dir/$L", ""); } } } foreach my $L ("lsusb", "usb-devices", "lspci", "lspci_all", "dmidecode", "dmesg", "megacli") { if(-f "$Dir/$L" and -s "$Dir/$L" < 2*$EMPTY_LOG_SIZE) { # Support for HW Probe 1.4 # sh: XXX: command not found # pcilib: Cannot open /proc/bus/pci # lspci: Cannot find any working access method. # lsusb: error while loading shared libraries: libusb-1.0.so.0: cannot open shared object file: No such file or directory # ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libarmmem.so' from /etc/ld.so.preload cannot be preloaded # /dev/mem: Permission denied # dmidecode: command not found # No SMBIOS nor DMI entry point found # dmesg: read kernel buffer failed: Operation not permitted writeFile("$Dir/$L", ""); } } foreach my $L ("pstree", "findmnt", "fdisk", "df") { # Support for HW Probe 1.4 if(-f "$Dir/$L" and -s "$Dir/$L" < $EMPTY_LOG_SIZE) { # sh: XXX: command not found # lsblk: Permission denied writeFile("$Dir/$L", ""); } } foreach my $L ("efibootmgr", "lsblk") { # Support for HW Probe 1.4 if(-f "$Dir/$L" and -s "$Dir/$L" < $EMPTY_LOG_SIZE/2) { writeFile("$Dir/$L", ""); } } foreach my $L ("lsusb", "usb-devices", "lspci", "lspci_all", "dmidecode", "hwinfo") { # Support for old probes if(not -e "$Dir/$L") { next; } my $Content = readFile("$Dir/$L"); if($L eq "lsusb") { if(index($Content, "Resource temporarily unavailable")!=-1) { $Content=~s/can't get device qualifier: Resource temporarily unavailable\n//g; $Content=~s/cannot read device status, Resource temporarily unavailable \(11\)\n//g; $Content=~s/cannot read port 1 status, Resource temporarily unavailable \(11\)\n//g; $Content=~s/can't get debug descriptor: Resource temporarily unavailable\n//g; $Content=~s/can't get hub descriptor, LIBUSB_ERROR_(IO|PIPE) \(Resource temporarily unavailable\)\n//g; writeFile("$Dir/$L", $Content); } if(index($Content, "some information will be missing")!=-1) { $Content=~s/Couldn't open device, some information will be missing\n//g; $Content=~s/Couldn't get configuration descriptor 0, some information will be missing\n//g; writeFile("$Dir/$L", $Content); } if($Opt{"UsbIDs"}) { if(index($Content, "HW_PROBE_USB_")!=-1 or $Content=~/: ID [a-f\d]{4}:[a-f\d]{4} \n/) { $Content=~s{lsusb: cannot open "/tmp/HW_PROBE_USB_", Permission denied\n\n}{}g; if($Opt{"UsbIDs"}) { $Content = fixLsUsb($Content); } writeFile("$Dir/$L", $Content); } } } elsif($L eq "lspci" or $L eq "lspci_all") { if(index($Content, "lspci: Unable to load libkmod resources: error")!=-1) { $Content=~s/lspci: Unable to load libkmod resources: error -\d+\n//g; writeFile("$Dir/$L", $Content); } if(index($Content, "pcilib: sysfs_read_vpd: read failed: Input/output error")!=-1) { $Content=~s/pcilib: sysfs_read_vpd: read failed: Input\/output error\n//g; writeFile("$Dir/$L", $Content); } if($Opt{"PciIDs"}) { if($L eq "lspci" and index($Content, "Class:\tClass [")!=-1) { writeFile("$Dir/$L", fixLsPci($Content)); } if($L eq "lspci_all" and index($Content, "]: Device [")!=-1) { writeFile("$Dir/$L", fixLsPci_All($Content)); } } } elsif($L eq "dmidecode") { if(index($Content, "Table is unreachable, sorry")!=-1) { $Content=~s{/dev/mem: Bad address\nTable is unreachable, sorry.\n}{}g; $Content=~s{/dev/mem: lseek: Value too large for defined data type\nTable is unreachable, sorry.\n}{}g; writeFile("$Dir/$L", $Content); } } elsif($L eq "hwinfo") { if(index($Content, "sh: /dev/null: Permission denied")!=-1) { $Content=~s{sh: /dev/null: Permission denied\n}{}g; writeFile("$Dir/$L", $Content); } } if(index($Content, "ERROR: ld.so:")!=-1) { # ERROR: ld.so: object '/usr/lib/arm-linux-gnueabihf/libarmmem.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored. # ERROR: ld.so: object 'libesets_pac.so' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored. $Content=~s/ERROR: ld\.so:.+?: ignored\.\n//g; writeFile("$Dir/$L", $Content); } } if(-e "$Dir/inxi") { # Support for HW Probe 1.4 if(readFile("$Dir/inxi")=~/Unsupported option|Use of uninitialized value/) { unlink("$Dir/inxi"); } } if(-e "$Dir/storcli") { # Support for HW Probe 1.4 if(index(readFile("$Dir/storcli"), "unexpected TOKEN_SLASH")!=-1) { writeFile("$Dir/storcli", ""); } } foreach my $L (@LARGE_LOGS) { if(-s "$FixProbe_Logs/$L" > getMaxLogSize($L)) { if(my $Content = readFile("$FixProbe_Logs/$L")) { writeLog("$FixProbe_Logs/$L", $Content); } } } if(-e "$Dir/modinfo") { # Support for HW Probe 1.4 if(my $Content = readFile("$Dir/modinfo")) { if(index($Content, "signature: ")!=-1) { if($Content=~s/:*\n\s+[A-F\d]{2}\:.+//g) { writeFile("$Dir/modinfo", $Content); } } } } if($Sys{"Probe_ver"} eq "1.4" or not $Sys{"Probe_ver"}) { # HW Probe <= 1.4 if(-e "$FixProbe_Logs/boot.log" and my $Content = readFile("$FixProbe_Logs/boot.log")) { writeLog("$FixProbe_Logs/boot.log", clearLog($Content)); } if(-e "$FixProbe_Logs/rpms" and my $Content = readFile("$FixProbe_Logs/rpms")) { my @Rpms = sort { "\L$a" cmp "\L$b" } split(/\n/, $Content); writeLog("$FixProbe_Logs/rpms", join("\n", @Rpms)); } if(-f "$Dir/mcelog") { if(readFile("$Dir/mcelog")=~/No such file or directory/) { writeFile("$Dir/mcelog", ""); } } } } sub createIDsLink($) { my $Type = $_[0]; my $Type_U = uc($Type); my $Link = "/tmp/HW_PROBE_".$Type_U."_"; if($Opt{"Flatpak"}) { $Link = "/var/tmp/P_".$Type_U; } if(-e $Link) { return undef; } if($Opt{"Snap"}) { if(my $SNAP_Dir = $ENV{"SNAP"}) { symlink("$SNAP_Dir/usr/share/$Type.ids", $Link); return $Link; } } elsif($Opt{"Flatpak"}) { symlink("/app/share/$Type.ids", $Link); return $Link; } return undef; } sub makeProbe() { probeSys(); probeDmi(); probeHWaddr(); probeHW(); if(keys(%ExtraConnection)) { fixHWaddr(); } if($Opt{"Logs"}) { writeLogs(); } if($Opt{"Check"}) { checkHW(); } if($USE_JSON_XS) { writeDevsDump(); } else { writeDevs(); } writeHost(); } sub fixByPkgs($) { my $Subj = $_[0]; if(isBSD()) { push(@DE_Package, ["awesome", "Awesome"]); push(@DE_Package, ["blackbox", "Blackbox"]); push(@DE_Package, ["evilwm", "evilwm"]); push(@DE_Package, ["fluxbox", "Fluxbox"]); push(@DE_Package, ["fvwm2", "fvwm2"]); push(@DE_Package, ["i3", "i3"]); push(@DE_Package, ["icewm", "IceWM"]); push(@DE_Package, ["jwm", "JWM"]); push(@DE_Package, ["menumaker", "MenuMaker"]); push(@DE_Package, ["openbox", "Openbox"]); push(@DE_Package, ["pekwm", "PekWM"]); push(@DE_Package, ["ratpoison", "Ratpoison"]); push(@DE_Package, ["sawfish", "Sawfish"]); push(@DE_Package, ["spectrwm", "spectrwm"]); push(@DE_Package, ["windowmaker", "Window Maker"]); push(@DE_Package, ["wm2", "wm2"]); push(@DE_Package, ["xmonad", "xmonad"]); } foreach my $PkgsFile ("rpms", "debs", "pkglist") { my $PkgsPath = "$FixProbe_Logs/$PkgsFile"; if(-e $PkgsPath) { my $Pkgs = readFile($PkgsPath); my @CheckPkgs = (); if($Subj eq "DE") { @CheckPkgs = @DE_Package; } elsif($Subj eq "DisplayServer") { @CheckPkgs = @DisplayServer_Package; } elsif($Subj eq "DisplayManager") { @CheckPkgs = @DisplayManager_Package; } foreach my $CPkg (@CheckPkgs) { my $P = $CPkg->[0]; if(index($Pkgs, $P)==-1) { next; } if($Pkgs=~/(\A|\s)\Q$P\E\b/) { return $CPkg->[1]; } if(isBSD()) { if($Pkgs=~/ .+\/\Q$P\E\b/) { return $CPkg->[1]; } } } } } return undef; } sub initDataDir($) { my $Dir = $_[0]; return ($Dir, $Dir."/logs", $Dir."/tests"); } sub isBSD(@_) { my $OS = undef; if(@_) { $OS = shift(@_); } elsif(not $Opt{"FixProbe"}) { if($^O=~/bsd|dragonfly/) { return 1; } } else { $OS = $Sys{"System"}; } return ($OS=~/bsd|dragonfly|\bting\b/ or $OS=~/$KNOWN_BSD_ALL/); } sub isNetBSD(@_) { my $OS = $Sys{"System"}; if(@_) { $OS = shift(@_); } return $OS=~/netbsd|os108/; } sub isOpenBSD(@_) { my $OS = $Sys{"System"}; if(@_) { $OS = shift(@_); } return $OS=~/openbsd|fuguita|libertybsd/; } sub scenario() { if($Opt{"Help"}) { print $HelpMessage; exitStatus(0); } if($Opt{"DumpVersion"}) { print $TOOL_VERSION."\n"; exitStatus(0); } if($Opt{"ShowVersion"}) { print $ShortUsage; exitStatus(0); } if(checkModule("Digest/SHA.pm")) { $USE_DIGEST = 1; require Digest::SHA; } elsif(not $Opt{"FixProbe"}) { if(checkCmd("sha512sum")) { $USE_DIGEST_ALT = "sha512sum"; } elsif(checkCmd("sha512")) { $USE_DIGEST_ALT = "sha512"; } elsif(checkCmd("openssl") and runCmd("openssl version")!~/0\.9\.[1-7]/) { $USE_DIGEST_ALT = "openssl dgst -sha512"; } elsif(checkCmd("shasum") and runCmd("shasum --version 2>/dev/null")) { $USE_DIGEST_ALT = "shasum -a 512"; } else { printMsg("ERROR", "can't find any utility to compute SHA512"); exitStatus(1); } } if($Opt{"ImportProbes"} or $Opt{"IdentifyDrive"} or $Opt{"IdentifyMonitor"}) { if($Opt{"AppImage"}) { printMsg("ERROR", "this function is not supported by AppImage"); exitStatus(1); } else { if(checkModule("Data/Dumper.pm")) { $USE_DUMPER = 1; require Data::Dumper; $Data::Dumper::Sortkeys = 1; } } } if(checkModule("JSON/XS.pm")) { $USE_JSON_XS = 1; require JSON::XS; } if(my $IA = checkModule("LHW/IntelligentAnalysis.pm", 1)) { $USE_IA = 1; require $IA; } if($Opt{"DecodeACPI"}) { $Opt{"DumpACPI"} = 1; } if(not $Opt{"Compact"}) { $Opt{"Compact"} = 1; } if($Opt{"Show"}) { $Opt{"ShowDevices"} = 1; } if($Opt{"Maximal"}) { $Opt{"LogLevel"} = "maximal"; } if($Opt{"Minimal"}) { $Opt{"LogLevel"} = "minimal"; } if($Opt{"LogLevel"}) { if($Opt{"LogLevel"}=~/\A(min|mini|minimum)\Z/i) { $Opt{"LogLevel"} = "minimal"; } elsif($Opt{"LogLevel"}=~/\A(max|maxi|maximum)\Z/i) { $Opt{"LogLevel"} = "maximal"; } if($Opt{"LogLevel"}!~/\A(minimal|default|maximal)\Z/i) { printMsg("ERROR", "unknown log level '".$Opt{"LogLevel"}."'"); exitStatus(1); } $Opt{"LogLevel"} = lc($Opt{"LogLevel"}); $Opt{"Logs"} = 1; } else { $Opt{"LogLevel"} = "default"; if(not $Opt{"All"} and not $Opt{"Logs"} and $Opt{"Probe"}) { $Opt{"Logs"} = 1; $Opt{"LogLevel"} = "minimal"; } } if(isBSD($^O)) { %EnabledLog = %EnabledLog_BSD; $URL = $URL_BSD; my @Exclude = (); if($^O=~/openbsd|dragonfly/ or isNetBSD($^O)) { push(@Exclude, "loader", "gpart", "gpart_list", "diskinfo", "camcontrol"); } if($^O=~/freebsd|dragonfly/) { push(@Exclude, "disklabel"); } if(@Exclude) { my $Ex = join("|", @Exclude); foreach my $K (keys(%EnabledLog)) { @{$EnabledLog{$K}} = grep {$_!~/$Ex/} @{$EnabledLog{$K}}; } } } completeEnabledLogs(); foreach my $LogStatus ("Enable", "Disable") { if(not defined $Opt{$LogStatus}) { next; } foreach my $L (split(/,/, $Opt{$LogStatus})) { if(not grep { $_ eq $L } @{$EnabledLog{"minimal"}} and not grep { $_ eq $L } @{$EnabledLog{"default"}} and not grep { $_ eq $L } @{$EnabledLog{"maximal"}} and not grep { $_ eq $L } @{$EnabledLog{"optional"}}) { printMsg("ERROR", "logging of \'$L\' cannot be enabled or disabled"); exitStatus(1); } } } if($Opt{"HWInfoPath"}) { if(not -f $Opt{"HWInfoPath"}) { printMsg("ERROR", "can't access file '".$Opt{"HWInfoPath"}."'"); exitStatus(1); } } if($Opt{"IdentifyDrive"} or $Opt{"IdentifyMonitor"}) { if(not $USE_DUMPER) { printMsg("ERROR", "requires perl-Data-Dumper module"); exitStatus(1); } } if($Opt{"IdentifyDrive"}) { if(not -f $Opt{"IdentifyDrive"}) { printMsg("ERROR", "can't access file '".$Opt{"IdentifyDrive"}."'"); exitStatus(1); } my $DriveDesc = readFile($Opt{"IdentifyDrive"}); my $DriveDev = "ID"; if($DriveDesc=~/\A(.+)\n/) { $DriveDev = $1; } detectDrive($DriveDesc, $DriveDev); print Data::Dumper::Dumper(\%HW); exitStatus(0); } if($Opt{"ShowDmesg"}) { if(not -f $Opt{"ShowDmesg"}) { printMsg("ERROR", "can't access file '".$Opt{"ShowDmesg"}."'"); exitStatus(1); } print hideDmesg(readFile($Opt{"ShowDmesg"}), 1); exitStatus(0); } if($Opt{"IdentifyMonitor"}) { if(not -f $Opt{"IdentifyMonitor"}) { printMsg("ERROR", "can't access file '".$Opt{"IdentifyMonitor"}."'"); exitStatus(1); } detectMonitor(readFile($Opt{"IdentifyMonitor"})); print Data::Dumper::Dumper(\%HW); exitStatus(0); } if($Opt{"DecodeACPI_From"} and $Opt{"DecodeACPI_To"}) { if(not -f $Opt{"DecodeACPI_From"}) { printMsg("ERROR", "can't access file '".$Opt{"DecodeACPI_From"}."'"); exitStatus(1); } decodeACPI($Opt{"DecodeACPI_From"}, $Opt{"DecodeACPI_To"}); exitStatus(0); } if($Opt{"InstallDeps"}) { $Opt{"All"} = 1; } if($Opt{"Save"}) { $Opt{"All"} = 1; } if($Opt{"Logs"}) { $Opt{"Probe"} = 1; } if($Opt{"All"}) { $Opt{"Probe"} = 1; $Opt{"Logs"} = 1; } if($Opt{"Check"}) { $Opt{"Probe"} = 1; $Opt{"Logs"} = 1; } if($Opt{"Probe"}) { $Opt{"HWLogs"} = 1; } if($Opt{"Probe"} or $Opt{"StartMonitoring"} or $Opt{"StopMonitoring"} or $Opt{"ShowLog"}) { if(not $Admin) { if($Opt{"Snap"}) { printMsg("WARNING", "run as root for better results ('sudo -E hw-probe ...' or with 'su')"); } elsif($Opt{"Flatpak"}) { printMsg("WARNING", "run as root for better results"); } else { printMsg("ERROR", "you should run as root ('sudo -E hw-probe ...' or with 'su')"); exitStatus(1); } } } if($Opt{"Probe"} and not $Opt{"FixProbe"}) { if(-d $DATA_DIR) { if(not -w $DATA_DIR) { printMsg("ERROR", "can't write to '".$DATA_DIR."', please run as root"); exitStatus(1); } rmtree($DATA_DIR); } } if($Opt{"ShowLog"}) { printMsg("INFO", readFile($PROBE_LOG)); } if($Opt{"FixProbe"}) { $Opt{"Probe"} = 0; $Opt{"HWLogs"} = 0; $Opt{"Logs"} = 0; } if($Opt{"Probe"} and ($Opt{"Upload"} or $Opt{"Save"})) { ($DATA_DIR, $LOG_DIR, $TEST_DIR) = initDataDir($TMP_PROBE); } if($Opt{"Check"}) { $Opt{"CheckGraphics"} = 1; $Opt{"CheckMemory"} = 1; $Opt{"CheckHdd"} = 1; $Opt{"CheckCpu"} = 1; } if($Opt{"CheckGraphics"} or $Opt{"CheckMemory"} or $Opt{"CheckHdd"} or $Opt{"CheckCpu"}) { $Opt{"Check"} = 1; $Opt{"Logs"} = 1; } if(my $PciIDs = $Opt{"PciIDs"}) { if(not -e $PciIDs) { printMsg("ERROR", "can't access '".$PciIDs."'"); exitStatus(1); } readPciIds_A($PciIDs, \%PciInfo); } if(my $UsbIDs = $Opt{"UsbIDs"}) { if(not -e $UsbIDs) { printMsg("ERROR", "can't access '".$UsbIDs."'"); exitStatus(1); } readUsbIds_A($UsbIDs, \%UsbInfo); } if(my $SdioIDs = $Opt{"SdioIDs"}) { if(not -e $SdioIDs) { printMsg("ERROR", "can't access '".$SdioIDs."'"); exitStatus(1); } readSdioIds($SdioIDs, \%SdioInfo, \%SdioVendor); if(-e "$SdioIDs.add") { readSdioIds("$SdioIDs.add", \%AddSdioInfo, \%AddSdioVendor); } } if($Opt{"PnpIDs"}) { if(not -e $Opt{"PnpIDs"}) { printMsg("ERROR", "can't access '".$Opt{"PnpIDs"}."'"); exitStatus(1); } } if($Opt{"FixProbe"}) { if(not -e $Opt{"FixProbe"}) { printMsg("ERROR", "can't access '".$Opt{"FixProbe"}."'"); exitStatus(1); } if(-f $Opt{"FixProbe"} and isPkg($Opt{"FixProbe"})) { # package my $PName = basename($Opt{"FixProbe"}); $FixProbe_Pkg = abs_path($Opt{"FixProbe"}); $Opt{"FixProbe"} = $FixProbe_Pkg; my $TmpDir = $TMP_DIR; if(-s $Opt{"FixProbe"} > 1048576) { $TmpDir = $TMP_LOCAL; mkpath($TmpDir); } copy($Opt{"FixProbe"}, $TmpDir."/".$PName); chdir($TmpDir); system("tar", "-m", "-xf", $PName); chdir($ORIG_DIR); $Opt{"FixProbe"} = $TmpDir."/hw.info"; } else { printMsg("ERROR", "unsupported probe format '".$Opt{"FixProbe"}."'"); exitStatus(1); } $Opt{"FixProbe"}=~s/[\/]+\Z//g; $FixProbe_Logs = $Opt{"FixProbe"}."/logs"; $FixProbe_Tests = $Opt{"FixProbe"}."/tests"; if(-d $Opt{"FixProbe"}) { if(not listDir($FixProbe_Logs)) { printMsg("ERROR", "can't find logs in '".$Opt{"FixProbe"}."'"); exitStatus(1); } } else { printMsg("ERROR", "can't access '".$Opt{"FixProbe"}."'"); exitStatus(1); } if(-f "$FixProbe_Logs/media_urls") { # support for old probes foreach my $File ("journalctl", "journalctl.1", "lib_modules", "ld.so.cache", "sys_module", "media_active", "media_urls", "lspcidrake", "lpstat", "lpinfo", "systemctl_status", "ps", "cups_access_log", "cups_error_log", "sane-find-scanner", "scanimage", "codec", "sys_class", "lsinitrd", "xmodmap", "avahi", "dmesg.old", "asound_modules", "syslog", "lib", "parted", "gdisk") { unlink($FixProbe_Logs."/".$File); } my $Udevadm = $FixProbe_Logs."/udevadm"; if(-f $Udevadm) { if(readFile($Udevadm)!~/sdio/i) { unlink($Udevadm); } } } if(my $RmLog = $Opt{"RmLog"}) { if(-f "$FixProbe_Logs/$RmLog" and not grep {$RmLog eq $_} @ProtectedLogs and not grep {$RmLog eq $_} @ProtectFromRm) { writeFile("$FixProbe_Logs/$RmLog", ""); } } if($Opt{"RmObsolete"}) { foreach my $L ("boot.log", "dmesg.1", "findmnt", "fstab", "grub.cfg", "mount", "pstree", "systemctl", "top", "xorg.log.1", "xorg.conf.d", "xorg.conf", "modprobe.d", "interrupts", "gl_conf-alternatives", "alsactl") # NOTE: systemctl is needed to detect Display_manager { if(-e "$FixProbe_Logs/$L") { unlink("$FixProbe_Logs/$L"); } } if(my $Xdpy = readFile("$FixProbe_Logs/xdpyinfo")) { if($Xdpy=~s/(visual:(.|\n)+?)\Z/...\n/g) { writeFile("$FixProbe_Logs/xdpyinfo", $Xdpy); } } if(my $Glx = readFile("$FixProbe_Logs/glxinfo")) { if($Glx=~s/(GLX Visuals)(.|\n)+?\Z/$1\n...\n/g) { writeFile("$FixProbe_Logs/glxinfo", $Glx); } } } if(my $TrLog = $Opt{"TruncateLog"}) { if(-f "$FixProbe_Logs/$TrLog" and not grep {$TrLog eq $_} @ProtectedLogs) { if(my $Content = readFile("$FixProbe_Logs/$TrLog")) { writeLog("$FixProbe_Logs/$TrLog", $Content); } } } $Opt{"Logs"} = 0; } if($Opt{"Save"}) { if(not -d $Opt{"Save"}) { printMsg("ERROR", "please create directory first"); exitStatus(1); } } if($Opt{"Upload"}) { if(not checkCmd("curl")) { if(not $Opt{"Snap"} and not $Opt{"Flatpak"}) { printMsg("WARNING", "'curl' package is not installed"); } } } if($Opt{"Probe"} or $Opt{"Check"}) { makeProbe(); if(not $Opt{"Upload"} and not $Opt{"Save"} and not $Opt{"Show"} and not $Opt{"ShowDevices"} and not $Opt{"ShowHost"} and not $Opt{"Docker"}) { print "Local probe path: $DATA_DIR\n"; } } elsif($Opt{"FixProbe"}) { readHost($Opt{"FixProbe"}); # instead of probeSys fixLogs($FixProbe_Logs); my ($Distr, $DistrVersion, $Rel, $Build) = probeDistr(); fixDistr($Distr, $DistrVersion, $Rel, $Build); if(isBSD()) { if($Sys{"Arch"} eq "x86_64") { $Sys{"Arch"} = "amd64"; } } fixProduct(); fixChassis(); probeHWaddr(); probeHW(); if($Sys{"System"} eq "debian") { fixDistr($Sys{"System"}, $Sys{"System_version"}, undef, undef); } if(not $Sys{"System"}) { $Sys{"System"} = "lfs"; } if(keys(%ExtraConnection)) { fixHWaddr(); } checkGraphicsCardOutput(readFile($FixProbe_Tests."/glxgears"), readFile($FixProbe_Tests."/glxgears_discrete")); if($Opt{"PC_Name"}) { $Sys{"Name"} = $Opt{"PC_Name"}; # fix PC name } # 1.6: added Current_desktop to identify probe of XDG_* # We identify early 1.6 pre-releases (version is not bumped yet) by presence of Uuid property in Sys if(not $Sys{"DE"} or (not $Sys{"Current_desktop"} and $Sys{"Probe_ver"} ne "1.5") or $Sys{"DE"} eq "KDE") { if(my $FixDE = fixByPkgs("DE")) { if($Sys{"DE"} ne "KDE" or $FixDE=~/KDE/) { $Sys{"DE"} = $FixDE; } } } if($Sys{"System"}=~/\Aubuntu(-\d|\Z)/) { if($Sys{"DE"}=~/KDE/) { $Sys{"System"}=~s/\Aubuntu/kubuntu/; } elsif($Sys{"DE"}=~/LXDE|LXQt/) { $Sys{"System"}=~s/\Aubuntu/lubuntu/; } elsif($Sys{"DE"}=~/XFCE/) { $Sys{"System"}=~s/\Aubuntu/xubuntu/; } elsif($Sys{"DE"}=~/MATE/) { $Sys{"System"}=~s/\Aubuntu/ubuntu-mate/; } elsif($Sys{"DE"}=~/Budgie/) { $Sys{"System"}=~s/\Aubuntu/ubuntu-budgie/; } elsif($Sys{"DE"}=~/Deepin/) { $Sys{"System"}=~s/\Aubuntu/ubuntudde/; } elsif($Sys{"DE"}=~/UKUI/) { $Sys{"System"}=~s/\Aubuntu/ubuntukylin/; } } if(not $Sys{"Display_server"}) { if(my $FixDisplayServer = fixByPkgs("DisplayServer")) { $Sys{"Display_server"} = $FixDisplayServer; } } if(not $Sys{"Display_manager"}) { if(my $FixDM = fixByPkgs("DisplayManager")) { $Sys{"Display_manager"} = fixDisplayManager($FixDM); } } if(isBSD()) { if($Sys{"System"}=~/hellosystem/i and (not $Sys{"DE"} or $Sys{"DE"}=~/openbox/i)) { $Sys{"DE"} = "helloDesktop"; } elsif($Sys{"Current_wm"}) { $Sys{"DE"} = $Sys{"Current_wm"}; } elsif($Sys{"Wm"}) { $Sys{"DE"} = $Sys{"Wm"}; } elsif(-s $FixProbe_Logs."/xorg.log") { if(isOpenBSD()) { $Sys{"DE"} = "fvwm"; } #else { # $Sys{"DE"} = "Unknown"; #} } } if($Opt{"DecodeACPI"}) { if(-s "$FixProbe_Logs/acpidump") { decodeACPI("$FixProbe_Logs/acpidump", "$FixProbe_Logs/acpidump_decoded"); } } if($USE_JSON_XS) { writeDevsDump(); } else { writeDevs(); } writeHost(); if($FixProbe_Pkg) { # package my $PName = basename($FixProbe_Pkg); chdir(dirname($Opt{"FixProbe"})); my $Compress = ""; if($PName=~/gz\Z/) { $Compress .= "tar -czf ".$PName." hw.info"; } else { # XZ if($Opt{"LowCompress"}) { # low CPU/RAM, high SPACE $Compress .= "XZ_OPT=-0 "; # high CPU, low RAM/SPACE # $Compress .= "XZ_OPT='--memlimit=15MiB' "; } elsif($Opt{"HighCompress"}) { # high CPU/RAM, low SPACE $Compress .= "XZ_OPT=-9 "; } else { # default is -9 } $Compress .= "tar -cJf ".$PName." hw.info"; } qx/$Compress/; if($?) { printMsg("ERROR", "can't create a package"); chdir($ORIG_DIR); exitStatus(1); } move($PName, $FixProbe_Pkg); if($!=~/Permission denied/) { printMsg("ERROR", "failed to access $FixProbe_Pkg"); } chdir($ORIG_DIR); rmtree($Opt{"FixProbe"}); # remove temp directory } } if($Admin and ($Opt{"Flatpak"} or $Opt{"OutputDir"})) { # Allow to mix root and non-root runs setPublic($PROBE_DIR, "-R"); } if($Opt{"Show"} or $Opt{"ShowDevices"} or $Opt{"ShowHost"}) { showInfo(); } if($Opt{"Upload"}) { uploadData(); cleanData(); } elsif($Opt{"Save"}) { saveProbe($Opt{"Save"}); cleanData(); } if($Opt{"GenerateGroup"}) { if(not $Opt{"Email"}) { printMsg("ERROR", "please specify -email option (your Email for notifications)"); exitStatus(1); } generateGroup(); } if($Opt{"Email"} and $Opt{"Email"}!~/\A[^\@]+\@[^\@]+\.\w{2,}\Z/) { printMsg("ERROR", "invalid Email address"); exitStatus(1); } if($Opt{"RemindGroup"}) { probeHWaddr(); if(not $Sys{"HWaddr"}) { printMsg("ERROR", "failed to detect hwid"); exitStatus(1); } remindGroup(); } if($Opt{"StartMonitoring"} or $Opt{"StopMonitoring"}) { if(not $Opt{"Group"}) { printMsg("ERROR", "please specify -i option (inventory id)"); exitStatus(1); } if(not $Admin and ($Opt{"Flatpak"} or $Opt{"Snap"})) { printMsg("WARNING", "not all hardware monitoring features are available when using Flatpak or Snap as a non-root user"); } if($Opt{"StartMonitoring"}) { $Opt{"Probe"} = 1; $Opt{"Logs"} = 1; $Opt{"HWLogs"} = 1; $Opt{"CheckGraphics"} = 1; $Opt{"CheckMemory"} = 1; $Opt{"CheckHdd"} = 1; $Opt{"CheckCpu"} = 1; makeProbe(); $Opt{"Monitoring"} = 1; uploadData(); } elsif($Opt{"StopMonitoring"}) { $Opt{"Probe"} = 1; probeHWaddr(); } setupMonitoring(); } if($Opt{"ImportProbes"}) { if(not $Admin and not $Opt{"Group"}) { printMsg("ERROR", "you should run as root (sudo or su)"); exitStatus(1); } if(not $USE_DUMPER) { printMsg("ERROR", "requires perl-Data-Dumper module"); exitStatus(1); } importProbes($Opt{"ImportProbes"}); } if($BY_DESKTOP) { # Wait for user to save the probe ID sleep(60); } exitStatus(0); } scenario(); hw-probe-1.6.2/periodic/000077500000000000000000000000001417672225000150475ustar00rootroot00000000000000hw-probe-1.6.2/periodic/hw-probe.service000066400000000000000000000004641417672225000201600ustar00rootroot00000000000000[Unit] Description=Probe hardware and upload result to Linux hardware database ConditionVirtualization=false After=local-fs.target [Service] Type=simple ExecStart=/usr/bin/hw-probe -all -upload IOSchedulingClass=idle Nice=19 IOSchedulingClass=2 IOSchedulingPriority=7 ProtectSystem=full StandardOutput=null hw-probe-1.6.2/periodic/hw-probe.timer000066400000000000000000000002301417672225000176270ustar00rootroot00000000000000[Unit] Description=Monthly hw-probe report [Timer] OnCalendar=monthly AccuracySec=12h Persistent=true OnBootSec=7min [Install] WantedBy=timers.target hw-probe-1.6.2/snap/000077500000000000000000000000001417672225000142125ustar00rootroot00000000000000hw-probe-1.6.2/snap/gui/000077500000000000000000000000001417672225000147765ustar00rootroot00000000000000hw-probe-1.6.2/snap/gui/hw-probe.desktop000066400000000000000000000003641417672225000201170ustar00rootroot00000000000000[Desktop Entry] Name=Hardware Probe Comment=Probe for hardware, check operability and find drivers Exec=hw-probe Icon=${SNAP}/usr/share/icons/hw-probe.png Type=Application StartupNotify=true Categories=System; Keywords=HW Probe;Hardware;Probe; hw-probe-1.6.2/snap/hw-probe.sh000066400000000000000000000001351417672225000162700ustar00rootroot00000000000000#!/bin/sh if [ $# -eq 0 ]; then hw-probe-snap -snap else hw-probe-snap -snap "$@" fi hw-probe-1.6.2/snap/snapcraft.yaml000066400000000000000000000347011417672225000170640ustar00rootroot00000000000000name: hw-probe version: 1.6-3 summary: Check operability of computer hardware and find drivers description: > A tool to probe for hardware, check operability and find drivers with the help of Linux Hardware Database. Probe — is a snapshot of your computer hardware state. The tool checks operability of devices by analysis of logs and returns a permanent url to view the probe of the computer: hw-probe -all -upload If some of your hardware devices does not work due to a missed driver then the tool will suggest a proper Linux kernel version according to the LKDDb or third-party drivers. Enable all interfaces in Permissions and run as root if you want to check health of all your hard drives. type: app base: core18 confinement: strict grade: stable plugs: dot-local-share-xorg-logs: interface: personal-files read: - $HOME/.local/share/xorg apps: hw-probe: extensions: [kde-neon] command: usr/bin/hw-probe plugs: [hardware-observe, system-observe, block-devices, log-observe, upower-observe, physical-memory-observe, network-observe, raw-usb, mount-observe, opengl, dot-local-share-xorg-logs] environment: PATH: $PATH:$SNAP/sbin:$SNAP/usr/sbin:$SNAP/usr/bin:$SNAP/usr/share/hw-probe-pyqt5-gui PERL5LIB: $SNAP/usr/share/perl5:$SNAP/usr/lib/x86_64-linux-gnu/perl-base:$SNAP/usr/lib/i386-linux-gnu/perl-base LD_LIBRARY_PATH: $SNAP/lib/x86_64-linux-gnu/:$SNAP/lib/i386-linux-gnu/:$SNAP/usr/lib64:$SNAP/usr/lib:$SNAP/usr/lib/x86_64-linux-gnu:$SNAP/usr/lib/i386-linux-gnu LC_ALL: C PYTHONPATH: $SNAP/usr/lib/python3/dist-packages parts: edid-decode: source: https://github.com/linuxhw/build-stuff/releases/download/1.4/edid-decode-20180622.tar.gz source-type: tar plugin: make override-build: | sed -i -e 's/ -g / -s /' Makefile make make install DESTDIR=$SNAPCRAFT_PART_INSTALL build-packages: - gcc - make prime: - usr/bin/edid-decode dmidecode: source: https://download-mirror.savannah.gnu.org/releases/dmidecode/dmidecode-3.3.tar.xz source-type: tar plugin: make override-build: | sed -i -e 's/ -O2/ -s -O2/' Makefile make make install prefix=/usr DESTDIR=$SNAPCRAFT_PART_INSTALL find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip build-packages: - gcc - make stage-packages: - on armhf: - dmidecode - on arm64: - dmidecode prime: - usr/sbin lm-sensors: source: https://github.com/lm-sensors/lm-sensors/archive/V3-6-0.tar.gz source-type: tar plugin: make override-build: | sed -i -e 's/ -g / -s /' Makefile make make install BUILD_STATIC_LIB=0 DEBUG=0 PREFIX=/usr DESTDIR=$SNAPCRAFT_PART_INSTALL find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip build-packages: - gcc - make prime: - usr/bin/sensors - etc/sensors3.conf - usr/lib/libsensors* libkmod: source: http://ftp.riken.jp/Linux/kernel.org/linux/utils/kernel/kmod/kmod-25.tar.xz source-type: tar plugin: make override-build: | ./configure --disable-debug --disable-python --disable-logging --disable-test-modules --disable-manpages --prefix=/usr sed -i -e 's/ -g / -s /' Makefile make make install DESTDIR=$SNAPCRAFT_PART_INSTALL find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip build-packages: - gcc - make prime: - usr/lib/libkmod.so* usbutils: source: https://mirrors.edge.kernel.org/pub/linux/utils/usb/usbutils/usbutils-007.tar.xz source-type: tar plugin: make override-build: | curl http://www.linux-usb.org/usb.ids > usb.ids sed -i -e 's/usbhid-dump//' Makefile.* configure ./configure --prefix=/usr sed -i -e 's/ -g / -s /' Makefile make make install DESTDIR=$SNAPCRAFT_PART_INSTALL find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip sed -i -e 's|/usr/share/usb.ids|/tmp/HW_PROBE_USB_|' $SNAPCRAFT_PART_INSTALL/usr/bin/lsusb build-packages: - gcc - make - curl - libusb-1.0-0-dev - libudev-dev prime: - usr/bin/lsusb - usr/bin/usb-devices - usr/share/usb.ids pciutils: source: https://github.com/pciutils/pciutils/archive/v3.6.2.tar.gz source-type: tar plugin: make override-build: | curl https://pci-ids.ucw.cz/v2.2/pci.ids > pci.ids make install PREFIX=/usr DESTDIR=$SNAPCRAFT_PART_INSTALL SHARED=no LIBKMOD=yes HWDB=no ZLIB=no DNS=no sed -i -e 's|/usr/share/pci.ids|/tmp/HW_PROBE_PCI_|' $SNAPCRAFT_PART_INSTALL/usr/sbin/lspci build-packages: - gcc - make - curl - libkmod-dev - pkg-config - libtool prime: - usr/sbin/lspci - usr/share/pci.ids acpica-unix: source: https://acpica.org/sites/acpica/files/acpica-unix-20210730.tar.gz source-type: tar plugin: make build-attributes: [no-patchelf] override-build: | make make install DESTDIR=$SNAPCRAFT_PART_INSTALL build-packages: - gcc - make - bison prime: - usr/bin/acpidump - usr/bin/iasl - usr/bin/acpixtract hdparm: source: https://github.com/linuxhw/build-stuff/releases/download/1.6/hdparm-9.62.tar.gz source-type: tar plugin: make override-build: | make make install DESTDIR=$SNAPCRAFT_PART_INSTALL build-packages: - gcc - make prime: - sbin/hdparm smartmontools: source: https://github.com/linuxhw/build-stuff/releases/download/1.5/smartmontools-7.2.tar.gz source-type: tar plugin: make override-build: | sh autogen.sh ./configure --with-nvme-devicescan --prefix=/ sed -i -e 's/ -g / -s /' Makefile make make install DESTDIR=$SNAPCRAFT_PART_INSTALL find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip build-packages: - gcc - make - automake prime: - sbin/smartctl libusb-1: source: https://github.com/libusb/libusb/archive/v1.0.22.tar.gz source-type: tar plugin: make override-build: | sh autogen.sh ./configure --disable-static --prefix=/usr sed -i -e 's/ -g / -s /' Makefile make make install DESTDIR=$SNAPCRAFT_PART_INSTALL find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip build-packages: - gcc - make - automake prime: - usr/lib/libusb*.so* util-linux: source: https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.37/util-linux-2.37.2.tar.xz source-type: tar plugin: make override-build: | ./configure --prefix=/usr sed -i -e 's/ -g / -s /' Makefile make dmesg mkdir -p $SNAPCRAFT_PART_INSTALL/usr/bin/ cp -f ./dmesg $SNAPCRAFT_PART_INSTALL/usr/bin/ find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip build-packages: - gcc - make - automake prime: - usr/bin/dmesg libx86emu: source: https://github.com/wfeldt/libx86emu/archive/3.2.tar.gz source-type: tar plugin: make override-build: | echo '3.2' > VERSION rm -f git2log sed -i -e 's/ -g / -s /' Makefile make make install DESTDIR=$SNAPCRAFT_PART_INSTALL find $SNAPCRAFT_PART_INSTALL -type f | perl -lne 'print if -B and -x' | xargs strip build-packages: - gcc - make hwinfo: after: [libx86emu] source: https://github.com/openSUSE/hwinfo/archive/21.76.tar.gz source-type: tar plugin: make override-build: | echo '21.76' > VERSION rm -f git2log sed -i -e 's/ -g / -s /' Makefile.common CFLAGS='-I'$SNAPCRAFT_STAGE'/usr/include' LDFLAGS='-L'$SNAPCRAFT_STAGE'/usr/lib64 -L'$SNAPCRAFT_STAGE'/usr/lib -lx86emu' make make install DESTDIR=$SNAPCRAFT_PART_INSTALL build-packages: - gcc - make - flex - uuid-dev prime: - usr/lib64/libhd* - usr/lib/libhd* - usr/share/hwinfo/* - usr/sbin/hwinfo perl-uri: source: https://cpan.metacpan.org/authors/id/E/ET/ETHER/URI-1.74.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-http-message: source: https://cpan.metacpan.org/authors/id/O/OA/OALDERS/HTTP-Message-6.18.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-net-http: source: https://cpan.metacpan.org/authors/id/O/OA/OALDERS/Net-HTTP-6.18.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-try-tiny: source: https://cpan.metacpan.org/authors/id/E/ET/ETHER/Try-Tiny-0.30.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-lwp-mediatypes: source: https://cpan.metacpan.org/authors/id/G/GA/GAAS/LWP-MediaTypes-6.02.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-http-date: source: https://cpan.metacpan.org/authors/id/G/GA/GAAS/HTTP-Date-6.02.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-timedate: source: https://cpan.metacpan.org/authors/id/G/GB/GBARR/TimeDate-2.30.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl libwww-perl: source: https://cpan.metacpan.org/authors/id/E/ET/ETHER/libwww-perl-6.35.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl prime: - usr/share/perl5/LWP - usr/share/perl5/LWP.pm perl-parent: source: https://cpan.metacpan.org/authors/id/C/CO/CORION/parent-0.237.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-data-dumper: source: https://cpan.metacpan.org/authors/id/S/SM/SMUELLER/Data-Dumper-2.161.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/usr/lib/*-linux-gnu*/perl/*/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl perl-time-local: source: https://cpan.metacpan.org/authors/id/D/DR/DROLSKY/Time-Local-1.28.tar.gz source-type: tar plugin: make override-build: | perl Makefile.PL make install DESTDIR=`pwd`/INST INSTALLSITELIB=/SITELIB mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ cp -fr ./INST/SITELIB/* $SNAPCRAFT_PART_INSTALL/usr/share/perl5/ build-packages: - make - perl hw-probe: source: https://github.com/linuxhw/build-stuff/releases/download/1.6/hw-probe-1.6-AI.tar.gz source-type: tar plugin: make override-build: | make install DESTDIR=$SNAPCRAFT_PART_INSTALL mv $SNAPCRAFT_PART_INSTALL/usr/bin/hw-probe $SNAPCRAFT_PART_INSTALL/usr/bin/hw-probe-snap chmod +x snap/hw-probe.sh cp -f snap/hw-probe.sh $SNAPCRAFT_PART_INSTALL/usr/bin/hw-probe mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/icons/ cp -f flatpak/icon-64x64.png $SNAPCRAFT_PART_INSTALL/usr/share/icons/hw-probe.png mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/perl5/File/ mv $SNAPCRAFT_PART_INSTALL/usr/share/perl/5.*.*/File/Copy.pm $SNAPCRAFT_PART_INSTALL/usr/share/perl5/File/ build-packages: - make - perl stage-packages: - perl-base - perl-modules prime: - usr/bin/hw-probe - usr/bin/hw-probe-snap - usr/lib/*-linux-gnu/perl-base - usr/bin/perl - usr/share/perl5/File/Copy.pm - usr/share/icons/hw-probe.png hw-probe-pyqt5-gui: source: https://github.com/linuxhw/build-stuff/releases/download/1.6/hw-probe-pyqt5-gui-1.1-AI.tar.gz source-type: tar plugin: make override-build: | mkdir -p $SNAPCRAFT_PART_INSTALL/usr/share/hw-probe-pyqt5-gui/ chmod +x Hardware\ Probe cp -fr Resources $SNAPCRAFT_PART_INSTALL/usr/share/hw-probe-pyqt5-gui/ cp -f Hardware\ Probe $SNAPCRAFT_PART_INSTALL/usr/share/hw-probe-pyqt5-gui/hw-probe-pyqt5-gui stage-packages: - python3-sip - python3-pyqt5 - xdg-utils prime: - usr/lib/python3/dist-packages - usr/share/hw-probe-pyqt5-gui - usr/bin/xdg-open - usr/bin/xdg-mime organize: etc/sensors3.conf: etc/sensors3.conf.bak