Terminal System Diagnostics: A Complete Picture Without GUI Tools
How to get a single complete picture of a machine's OS, boot mode, disk layout, memory, GPU, and network from one terminal pass, without guessing. A structured approach to hardware and OS discovery.

Goal: get a single complete picture of the machine — OS, boot mode, disk layout, partitions, bootloader, filesystems, swap, memory, GPU, network — from one terminal pass, without a GUI tool and without guessing at any of it. The kind of snapshot you want before repartitioning, before touching a bootloader, or before filing a bug report against a distro.
This document records every command, what it actually returned, and which ones failed and why.
The approach
One shell script, split into labelled sections with echo "===== NAME =====" headers. That
framing matters more than it looks: when a dozen commands dump output back to back, unlabelled
output is unreadable, and you cannot tell a command that printed nothing from a command that
failed silently. Headers make gaps visible.
Two structural decisions that paid off:
- Fallback chains with
||.lsblkwas invoked with a long column list and a shorter list as a fallback (lsblk -o A,B,C ... || lsblk -o A,B). This turned out to be necessary — see “Invalid column” below. 2>/dev/null || trueon the optional probes. LVM and btrfs tooling is absent or irrelevant on many systems. Without the guard, a missingbtrfsbinary aborts the run.
Section by section: command, and what it found
OS and kernel
cat /etc/os-release
uname -a
hostnamectl
/etc/os-release is the machine-readable source of truth: ID=pop, ID_LIKE="ubuntu debian",
VERSION_CODENAME=noble. That ID_LIKE line is the useful one — it tells a script that Debian
and Ubuntu instructions apply to Pop!_OS.
hostnamectl gave what the other two could not: hardware vendor and model (HP EliteBook 840 G8),
firmware version (T76 Ver. 01.23.00), firmware date, and firmware age. Firmware age is a genuinely
useful field that almost nobody checks — a BIOS three years stale is a plausible cause for a whole
class of suspend, thermal, and NVMe bugs.
Kernel: 7.0.11-76070011-generic — the -76 marks it as a System76-built kernel, not stock Ubuntu.
Boot mode
[ -d /sys/firmware/efi ] && echo "UEFI" || echo "Legacy BIOS"
The cleanest UEFI-vs-BIOS test there is. The kernel only creates /sys/firmware/efi when it
booted via EFI. No parsing, no tool to install. Result: UEFI.
This single line decides how every later answer should be read. On a UEFI system, “which bootloader” is a question about EFI variables and files on an ESP, not about bytes in an MBR.
Disks and partitions
lsblk -e7 -o NAME,SIZE,TYPE,FSTYPE,FSVER,LABEL,UUID,PARTUUID,MOUNTPOINTS
-e7 excludes loop devices (major number 7), which otherwise bury real disks under a wall of
snap mounts. The explicit -o column list is the point of the exercise — the default lsblk
output omits UUID, PARTUUID and filesystem version, which are exactly the fields you need when
editing /etc/fstab or debugging a boot failure.
What it found — a textbook dual-boot layout on nvme0n1 (476.9 GB):
| Partition | Size | Type | Role |
|---|---|---|---|
| p1 | 200M | vfat FAT32 | Original Windows ESP |
| p2 | 16M | (none) | Microsoft Reserved (MSR) |
| p3 | 217.2G | ntfs | Windows C: |
| p4 | 735M | ntfs | Windows Recovery |
| p5 | 1024M | vfat FAT32 | ESP in use, mounted at /boot/efi |
| p6 | 150.4G | ext4 | Pop!_OS root, mounted at / |
The interesting find: two EFI System Partitions. p1 (200M) is the one Windows created; p5 (1024M) is the one the Pop!_OS installer created and the one actually mounted. This is normal Pop!_OS behaviour — its installer prefers its own large ESP rather than crowding into Windows’ 200 MB — but it is a trap. Anyone who later runs a bootloader repair tool and lets it pick “the” ESP can write to the wrong one and produce a system that boots neither OS. Knowing there are two, and which is live, is the payoff for running the diagnostic at all.
Roughly 107 GB of the 477 GB disk is unallocated or otherwise unaccounted for by the partition sizes above — worth confirming with a partition-table dump (see the sudo section).
Filesystem usage
df -hT
-T adds the filesystem type column, which turns a usage report into a mount-type audit. Result:
root /dev/nvme0n1p6 ext4, 147G total, 85G used, 55G free, 61% used. ESP /dev/nvme0n1p5 at
437M of 1022M (43%) — that number matters, because a full ESP is a classic cause of failed kernel
updates.
Everything else in the list is tmpfs, which is a useful reminder that df output is mostly RAM
by line count: /run, /dev/shm, /run/lock, /run/qemu, /run/user/1000.
The EFI System Partition, specifically
findmnt /boot/efi
ls -lah /boot/efi
findmnt is the right tool over mount | grep — it takes a path argument and prints the source
device, filesystem type, and the full option string. It confirmed p5 as the live ESP with
fmask=0077,dmask=0077, i.e. root-only access, which is why the ls produced nothing readable
as a normal user.
Mounts and fstab
findmnt
cat /etc/fstab
Bare findmnt prints the whole mount tree as an actual tree, which beats mount for reading.
Root is mounted rw,noatime,errors=remount-ro — noatime is a deliberate SSD-longevity choice
the Pop installer makes.
/etc/fstab held the more interesting detail: the ESP is referenced by PARTUUID, while root
is referenced by UUID. That is not an inconsistency, it is correct — a partition UUID for a
FAT partition (whose filesystem UUID is a weak 32-bit volume serial), and a filesystem UUID for
ext4. Third line: /swapfile none swap sw 0 0.
Swap and memory
swapon --show
free -h
The sharpest finding of the whole run. swapon --show reported two swap devices:
/swapfile file 8G 0B -1
/dev/zram0 partition 15.3G 5.6G 1000
zram — compressed swap in RAM — at priority 1000, and an 8 GB disk swapfile at priority -1. The priorities mean zram fills completely before the disk file is touched at all, which is why the swapfile shows 0 B used while zram holds 5.6 GB.
And the memory state explains why that matters: 15 GB total, 12 GB used, 711 MB free, only 2.6 GB
available. This machine is under real memory pressure, and 5.6 GB of compressed pages are sitting
in zram. The free -h “Swap: 23Gi” total is the sum of both devices and is misleading on its own —
it looks like generous headroom, but 15.3 GB of it consumes the very RAM that is already short.
This is a diagnostic worth its own blog section: on a zram system, free alone will mislead you.
Always pair it with swapon --show.
Windows partitions
lsblk -o NAME,SIZE,FSTYPE,LABEL,PARTLABEL,PARTTYPE,MOUNTPOINTS | grep -Ei 'ntfs|Microsoft|Windows|basic'
PARTTYPE is the field that makes this section work — it prints the GPT partition type GUID, which
is authoritative where a label is just a string someone can rename:
c12a7328-f81f-11d2-ba4b-00a0c93ec93b— EFI System Partitione3c9e316-0b5c-4db8-817d-f92df00215ae— Microsoft Reservedebd0a0a2-b9e5-4433-87c0-68b6b72699c7— Basic Data (the Windows install)de94bba4-06d1-4d40-a16a-bfd50179d6ac— Windows Recovery
None of the Windows partitions are mounted, which is the correct and safe state for a dual-boot machine using Windows fast startup.
GPU and network
lspci | grep -Ei 'vga|3d|display'
ip -br addr
GPU: Intel TigerLake-LP GT2 (Iris Xe Graphics), integrated only — no discrete GPU, so no NVIDIA driver or hybrid-graphics complications to account for.
ip -br addr (brief mode) is the underused one here. It collapses per-interface output to one
line each, which is what you want in a diagnostic dump rather than the eight-line-per-interface
default. It showed Wi-Fi <WIFI_INTERFACE> up on 192.168.1.x/24 with two global IPv6 addresses, an
inactive wwan0 (the WWAN modem), and — notably — tun0 at 10.x.x.x/27, an active VPN tunnel.
A VPN interface showing up in a routine diagnostic is exactly the sort of thing you want to know
before debugging anything network-shaped.
What failed, and why
This is the half of a diagnostic run that people leave out of writeups, and it is the more instructive half.
Everything behind sudo returned nothing
Five sections came back with only sudo: a password is required:
sudo fdisk -l— partition tablessudo efibootmgr -v— EFI boot entries and their ordersudo find /boot -maxdepth 2 -type f— bootloader files on disksudo pvs/sudo vgs/sudo lvs— LVMsudo btrfs filesystem show/subvolume list /— btrfs
Cause: the script ran in a non-interactive context with no TTY available for a password prompt.
sudo had no way to ask. Using sudo -n (non-interactive) makes this failure explicit and
immediate rather than hanging, which is the right behaviour in a script — it fails in a
millisecond with a clear message instead of blocking on an invisible prompt.
The loss is real. efibootmgr -v was the one that would have answered the two-ESP question
definitively: it lists the firmware’s actual boot entries, in order, with the EFI binary path each
one points to. That is how you learn whether the firmware is booting systemd-boot from p5 or
something stale on p1. The workaround is simply to run those four commands yourself in an
interactive shell:
sudo fdisk -l
sudo efibootmgr -v
sudo find /boot -maxdepth 2 -type f | sort
Lesson for the blog: split a diagnostic script into a no-privilege half and a sudo half. Run the first anywhere; run the second interactively. Mixing them means a single missing password silently guts a third of your report.
Invalid lsblk column
The first lsblk invocation requested a PARTTUUIDS column. No such column exists — the real one
is PARTUUID (and PARTTYPE for the type GUID). lsblk rejects the whole invocation when any
single column name is unknown, so that command would have produced nothing at all.
The || fallback to a shorter column list is what saved the section. Worth knowing:
lsblk --help lists every valid column name, and checking there first is cheaper than debugging
an empty section.
sudo du -sh / — deliberately skipped
The script included a full-filesystem disk usage walk. It was dropped on purpose: du over an
entire root filesystem stats every inode on the disk, which takes minutes on a 147 GB filesystem
and produces one number that df -hT already reported instantly and accurately.
du earns its keep when you need a breakdown — du -xh --max-depth=1 / | sort -h is the
version actually worth running, where -x keeps it from wandering into other filesystems. A bare
du -sh / is the worst of both: slow and uninformative.
/etc/default/grub matched nothing
grep -E '^(GRUB|KERNEL|BOOT|ROOT|ESP|SWAP)=' /etc/default/grub
Zero matches — and that null result is itself a finding. Pop!_OS uses systemd-boot, not GRUB,
on UEFI installs. The file either does not exist or is a vestigial stub. A blank result here was
the first hint; bootctl status (not in the original script, and the right tool for a systemd-boot
machine) would confirm it.
Lesson: a diagnostic tuned for one distro’s assumptions quietly returns nothing on another. Probe
for what is actually there (bootctl alongside grub-install --version) rather than assuming.
Summary of findings
- Dual-boot HP EliteBook 840 G8: Windows (217.2 GB NTFS) + Pop!_OS 24.04 (150.4 GB ext4), UEFI.
- Two ESPs — a 200 MB Windows one and a 1 GB Pop one; only the latter is mounted and live. The main hazard on this machine.
- Bootloader is systemd-boot, not GRUB, so GRUB-based repair advice does not apply.
- ESP is 43% full — fine now, worth watching across kernel updates.
- Memory pressure is the live problem: 12 GB of 15 GB used, 2.6 GB available, 5.6 GB of compressed pages in zram. The 8 GB disk swapfile is completely untouched because zram’s priority 1000 beats its -1.
- Root filesystem 61% full (85 GB of 147 GB).
- Intel Iris Xe integrated graphics only.
- An active VPN tunnel (
tun0, 10.x.x.x/27) alongside Wi-Fi. - Roughly 107 GB of the disk unaccounted for by partition sizes — needs
sudo fdisk -lto confirm.
Note on provenance: the command output documented here was captured on the Pop!_OS 24.04 install described above (kernel 7.0.11-76070011-generic). This file was written from a later shell reporting a Fedora kernel (6.19.10-300.fc44), consistent with an in-progress Pop!_OS to Fedora migration on the same hardware. Re-run the script after the migration settles if you want a current baseline — the two-ESP and zram findings in particular are worth re-checking on Fedora.