5

I am writing an application that works like Neofetch when a -w option is passed. It shows some of the the system information like memory, swap, cpu, battery usages, hostname, local ip, kernel version etc.

I am wondering how to get the "Host" like in Neofetch. For example:

                   -`                    sourav@archlinux-arm 
                  .o+`                   -------------------- 
                 `ooo/                   OS: Arch Linux armv7l 
                `+oooo:                  Host: Raspberry Pi 3 Model B Rev 1.2 
               `+oooooo:                 Kernel: 4.19.108-1-ARCH 
               -+oooooo+:                Uptime: 10 mins 
             `/:-:++oooo+:               Packages: 804 (pacman) 
            `/++++/+++++++:              Shell: bash 5.0.16 
           `/++++++++++++++:             Resolution: 1366x768 
          `/+++ooooooooooooo/`           DE: Xfce 
         ./ooosssso++osssssso+`          WM: Xfwm4 
        .oossssso-````/ossssss+`         WM Theme: XFCE_Colour_Lite_Pink 
       -osssssso.      :ssssssso.        Theme: XFCE_Colour_Lite_Pink [GTK2], X 
      :osssssss/        osssso+++.       Icons: Papirus [GTK2], Tela-orange [GT 
     /ossssssss/        +ssssooo/-       Terminal: tilix 
   `/ossssso+/:-        -:/+osssso+-     CPU: BCM2835 (4) @ 1.350GHz 
  `+sso+:-`                 `.-/+oso:    Memory: 333MiB / 901MiB 
 `++:.                           `-/+/
 .`                                 `/                           

I get an information like this. On my laptop:

                   -`                    sourav@archlinux 
                  .o+`                   ---------------- 
                 `ooo/                   OS: Arch Linux x86_64 
                `+oooo:                  Host: Inspiron 5567 
               `+oooooo:                 Kernel: 5.5.10-arch1-1 
               -+oooooo+:                Uptime: 3 hours 
             `/:-:++oooo+:               Packages: 1163 (pacman) 
            `/++++/+++++++:              Shell: bash 5.0.16 
           `/++++++++++++++:             Resolution: 1920x1080 
          `/+++ooooooooooooo/`           DE: Xfce 
         ./ooosssso++osssssso+`          WM: Xfwm4 
        .oossssso-````/ossssss+`         WM Theme: XFCE_Colour_Lite_Ruby 
       -osssssso.      :ssssssso.        Theme: XFCE_Colour_Lite_Purple [GTK2 
      :osssssss/        osssso+++.       Icons: Papirus [GTK2/3] 
     /ossssssss/        +ssssooo/-       Terminal: tilix 
   `/ossssso+/:-        -:/+osssso+-     CPU: Intel i3-6006U (4) @ 2.000GHz 
  `+sso+:-`                 `.-/+oso:    GPU: Intel Skylake GT2 [HD Graphics  
 `++:.                           `-/+/   Memory: 2814MiB / 3755MiB 
 .`                                 `/

My question is related to this question, but it doesn't answer my question because my raspberry pi can't run dmidecode, (no /sys/devices/virtual/dmi/ either), no lshw installed. Also, the /etc/hostname are not the computers' model name, instead they are just archlinux-arm and archlinux. The uname -a or cat /proc/version doesn't have the 'Rapsberry Pi' string on the raspberry pi.

Is there a way to get the hardware name like neofetch without using any dependency which should also run on most hardware?

15 Volts
  • 2,069
  • 1
    I'm using a Dell Latitude so I ran sudo grep -R "Latitude E7470" /proc/* 2> /dev/null and it gave me a few lines that show Dell Inc. Latitude E7470. Maybe you can try something similar and parse the returned strings? – Gordster Mar 25 '20 at 07:59
  • Yes, it's 9000 lines of bash script (comments included) and I have yet to see how really it works, just I can't find from where it gets the system name... – 15 Volts Mar 25 '20 at 14:21
  • Sorry for the late comment (not feeling well), I have managed to get the information from neofetch, which is just a bunch of conditions and in the end, it reads the /sys/ file system to show the details. These lines get the system model details: https://github.com/dylanaraps/neofetch/blob/1778941ddaacedf5a4c529bcd44d6078781be90c/neofetch#L1174 – 15 Volts Mar 25 '20 at 20:29

2 Answers2

6

Reading the source code of Neofetch made the confusion clear. Line 1174 for Neofetch version 7.0.0 has a condition check:

if [[ -d /system/app/ && -d /system/priv-app ]]; then
    model="$(getprop ro.product.brand) $(getprop ro.product.model)"

elif [[ -f /sys/devices/virtual/dmi/id/product_name ||
    -f /sys/devices/virtual/dmi/id/product_version ]]; then
    model=$(< /sys/devices/virtual/dmi/id/product_name)
    model+=" $(< /sys/devices/virtual/dmi/id/product_version)"

elif [[ -f /sys/firmware/devicetree/base/model ]]; then
    model=$(< /sys/firmware/devicetree/base/model)

elif [[ -f /tmp/sysinfo/model ]]; then
    model=$(< /tmp/sysinfo/model)
fi

It actually checks for various paths, and not a single path to get the details. So this isn't a hardcore check that works on every single GNU/Linux distribution. The first if condition for example, checks for specific path that can be found on Android.

I have tested the files on various distributions and hardware:

PCs and Laptops

For all of my systems the /sys/devices/virtual/dmi/id/product_name has the model info.

Raspberry Pi 3 Model B and Android (7.0 tested)

In my Raspberry Pi 3 Model B and Android smart phone, the file /sys/firmware/devicetree/base/model has the model info.

VirtualBox

Debian running in Virtualbox, Neofetch shows Virtualbox 1.2 as host, which can be found by cat /sys/devices/virtual/dmi/id/product_name /sys/devices/virtual/dmi/id/product_version.

Note that the product_version can be a just a newline character, so it's better strip the (strip, strip! in Ruby) the trailing newline characters after reading the files and concatenating the strings.

So it might make sense to put all the conditions and check for the existing files, and read the files to get the model info.

15 Volts
  • 2,069
3

There is no a portable, reliable, generic method to retrieve hardware model name in Linux. Let me describe 2 different cases: ARM-based Raspberry Pi with Raspbian installed and MIPS-based TP-LINK router with OpenWRT installed.

Raspberry Pi has an ARM CPU and ARM devices commonly use device-tree to describe hardware and Wikipedia article even mentions that it's mandatory since 2012. Device-tree structure is exposed to userspace and can be used for retrieving a model name by cating /proc/device-tree/model where /proc/device-tree itself is a symlink to /sys/firmware/devicetree/base like that (notice that there is no newline at the end of the device-tree files so we create a helper function called catn that cats the file and adds a newline):

pi@raspberrypi:~$ catn () { cat $1 && echo; }
pi@raspberrypi:~$ catn /proc/device-tree/model
Raspberry Pi 3 Model B Rev 1.2
pi@raspberrypi:~$ catn /sys/firmware/devicetree/base/model
Raspberry Pi 3 Model B Rev 1.2

or by manually dumping /sys/firmware/fdt flattened device-tree blob with dtc:

pi@raspberrypi:~$ sudo dtc /sys/firmware/fdt 2>/dev/null | grep model
    compatible = "raspberrypi,3-model-b\0brcm,bcm2837";
    model = "Raspberry Pi 3 Model B Rev 1.2";

If an official Raspberry Pi Linux fork is in use model is also written to /proc/cpuinfo:

pi@raspberrypi:~$ grep "^Model" /proc/cpuinfo
Model           : Raspberry Pi 3 Model B Rev 1.2

Also notice that the full name of the board - Raspberry Pi 3 Model B Rev 1.2 is constructed by low-level firmware and that you will not find a full string like that anywhere in the Linux kernel code:

pi@raspberrypi:~$ strings /boot/start.elf  | grep 'Raspberry Pi '
Raspberry Pi %s Rev %s
Raspberry Pi Bootcode

model is a standard device-tree property described in the DTSpec.

Other architectures such as RISC-V also use device tree to describe hardware but I don't have any RISC-V board to check.

There is no /proc/device-tree, no /sys/firmware/devicetree/base and no /sys/firmware/fdt on my TP-LINK router - it means that it either doesn't come with device-tree at all or that some appropriate Linux kernel config options have been disabled and device-tree is not exposed to the userspace. The former is, however, more likely as there is /tmp/sysinfo instead:

~ $ cat /tmp/sysinfo/board_name
tl-wdr4300
~ $ cat /tmp/sysinfo/model
TP-Link TL-WDR3600 v1

These values are generated by ar71xx.sh script which is rather long but you can see that name is assigned in line 1313:

*"TL-WDR3600/4300/4310")
        name="tl-wdr4300"
    ;;

based on TL-WDR4900 v2 which is in turn taken from machine field from /proc/cpuinfo:

machine=$(awk 'BEGIN{FS="[ \t]+:[ \t]"} /machine/ {print $2}' /proc/cpuinfo)

and is then assigned to AR71XX_BOARD_NAME and written to /tmp/sysinfo/board_name by the end of the script.

The full value of machine field in /proc/cpuinfo on this router is:

~ $ grep "^machine" /proc/cpuinfo
machine                 : TP-LINK TL-WDR3600/4300/4310

But Neofetch is not looking for /tmp/sysinfo/board_name, it's looking for /tmp/sysinfo/model. It's not taken from /proc/cpuinfo but read from the firmware flash partition:

~ $ cat /proc/mtd
dev:    size   erasesize  name
mtd0: 00020000 00010000 "u-boot"
mtd1: 0010c5a4 00010000 "kernel"
mtd2: 006c3a5c 00010000 "rootfs"
mtd3: 00490000 00010000 "rootfs_data"
mtd4: 00010000 00010000 "art"
mtd5: 007d0000 00010000 "firmware"
~ $ dd if=/dev/mtdblock5 bs=4 count=1 skip=16 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"'  && echo
36000001

Model is assigned in line 321:

"360000"*)
    model="TP-Link TL-WDR3600"
    ;;

Of course it's hard to imagine that a generic program such as Neofetch would have so much knowledge about each firmware, its flash layout etc. I could however imagine a MIPS-based implementation that wouldn't support device-tree and wouldn't provide any useful hardware model information in /tmp/sysinfo and anywhere else and in such cases /proc/cpuinfo could be used as a last resort to get any information about hardware.