Herdiansyah


The Woes of Finding System Information

In a lot of OS, finding system information can be a very daunting task, scattered between commands, files, etc. However, there are many tools to gather them all so they can be in one place, formatted nicely.

There are many tools to find system information. Like inxi, screenfetch, and lshw (hardware only). Personally, I have been contributing to Neofetch.

So, I have been thinking that most of the tools that have been mentioned have supported either one or more of these OS: Linux, BSDs, macOS, or Windows (Cygwin/MinGW). As of now there are no ports to obscure systems like Solaris, AIX, IRIX, and HP-UX.

I thought, why don’t we add support for those OS? Well. Unfortunately, it’s not that easy to add support for those system.

First problem: they are not as common as Linux, BSDs, Macs or Windows.

Because they are not as common as the OS I mentioned above, they are certainly harder to access and their documentation probably will be harder to obtain.

As for the case of Solaris, there are two “flavors” I have tried to add support for Neofetch, the Oracle version, and OpenIndiana. Surprisingly, they have free download links (as for OpenIndiana, it’s actually open-source since it is kind of the spiritual successor of the dead OpenSolaris project), so I can easily “play” with the system in a VM.

Progress of adding support for Solaris actually went smoothly, as they actually have good documentation to fetch information.

But, when I finally got to a function which fetches the installation date. A new problem arises, Oracle Solaris doesn’t use GNU coreutils, but OpenIndiana does.

About install date itself, before release 3.0, Neofetch used to have an approach to hardcode the way we get install_date, with fixed ls flags across OS. Something like this:

...
case "$os" in
    "Linux" | "iPhone OS")
    install_date="$(ls -alct --full-time / | awk '/lost\+found|private/ {printf  $6 " " $7}')"
    ;;
    "Mac OS X")
    install_date="$(ls -lUT /var/log/install.log | awk '{printf $9 " " $6 " " $7 " " $8}')"
    ;;
...
    "Windows")
    install_date="$(ls -alct --full-time /cygdrive/c/Windows/explorer.exe | awk '{printf $8 " " $9}')"
    ;;
    "Solaris")
    install_date="$(ls -alct --full-time /var/sadm/system/logs/install_log | awk '{printf $6 " " $7}')"
    ;;
...

But, aside from the Oracle vs OpenIndiana problem I mentioned above, what if someone on Linux uses Busybox? What if someone uses GNU coreutils on BSDs?

Therefore, we got to the second problem: Different userland needs different approach.

I decided to rewrite the whole thing from scratch. Because it’s possible to have different ls, I decided to determine the install file/directory per OS, then detect the ls program being used by using ls --version.

But what if ls --version yields nothing? We redirect the output of stderr to stdout, of course. And detect it based on the error output instead.

...
case "$os" in
    "Linux") install_file="/lost+found" ;;
    "Mac OS X") install_file="/var/log/install.log" ;;
...
    "Solaris") install_file="/var/sadm/system/logs/install_log" ;;
    "Haiku") install_file="/boot" ;;
esac

ls_prog="$(ls --version 2>&1)"
case "$ls_prog" in
    *"BusyBox"*) install_date="$(ls -tdce "$install_file" | awk '{printf $10 " " $7 " " $8 " " $9}')" ;;
    *"crtime"*) install_date="$(ls -tdcE "$install_file" | awk '{printf $6 " " $7}')" ;; # xpg4 (Solaris)
    *"ACFHLRSZ"*) install_date="$(ls -dl "$install_file" | awk '{printf $6 " " $7}')" ;; # Toybox
    *"GNU coreutils"*) install_date="$(ls -tcd --full-time "$install_file" | awk '{printf $6 " " $7}')" ;;
    *) install_date="$(ls -dlctT "$install_file" | awk '{printf $9 " " $6 " "$7 " " $8}')" ;;
esac

We encountered the same problem with df, and decided to do the same approach.

It took only 2 days maximum to get the support for Solaris up and running in Neofetch. The rest are just refining the commands to make it faster.

Months later, a new issue appeared on GitHub, requesting support for AIX.

Here comes the third problem: We practically have no physical or virtual access to these systems. We have to rely on external documentations and external outputs.

Thankfully, our requester responds to our inquiries and has been very helpful, so I only need a week to get full AIX support running with his confirmation that everything worked correctly.

Three months later, someone requested IRIX support. Everything actually went smoothly because they have good documentation provided by their community and also feedbacks by the requester. However, when we tried to test the result, there are no replies from them. So, I’m kinda stuck because we actually have no access to these systems whatsoever.

I’m starting to look to rent a server, I kept looking until I found Polarhome, a service that gives you shell account on certain servers. Currently, they support access to a very wide range of OS, including Linux, BSDs, Solaris (SPARC), AIX, HP-UX, and IRIX. Perfect. I can refine Neofetch even more with the access. We solved the third problem.

I bought 5 shell accounts for 5 different servers for $10 (the advantage of living in a country with no denomination of 10), and started to test Neofetch. It took 2 months total to merge the IRIX support, but that’s mostly because of the long wait.

Now, one last actively-developed Unix (as in the certified one) yet, HP-UX.

Now, HP-UX is an interesting case, because different architecture has different commands, and some commands require root. Therefore, for obvious reason we can not use the commands (unless you want to use root as your default user, but you don’t want to run any systems as root unless absolutely necessary).

Another problem is a command on different version of HP-UX can yield different results.

This has been addressed in the man page for machinfo(1).

The machinfo command output is not suitable for parsing by scripts since its content and format is subject to change based on product updates, os version, hardware platform, and/or system configuration

My only question is, why?

Speaking of different hardware - different output problem, I also had the same frustation with /proc/cpuinfo in Linux, as different architecture produces different results, we had to rewrite the get_cpu mechanism to support different architecture in Linux.

However, there are striking differences of how this is handled in Linux and HP-UX. Since (at least) Linux kernel version 2.4.21, the main output of /proc/cpuinfo (model name, etc) has never changed (at least in x86). Now, if /proc/cpuinfo produces different output in different OS version/system configuration/“product updates”, that would be frustrating for end-user. (Unless of course, the OS have syscalls that fetches these information (but since neofetch is a shell program, it doesn’t do syscalls like C programs), but if the syscalls change every OS release, that would be ridiculous as that means no stable interface).

Oh well.