Salta al contenuto principale

lshw: l'inventario completo dell'hardware

Inviato da tuxsa il

Negli ultimi articoli abbiamo guardato l'hardware pezzo per pezzo: lscpu per il processore, lspci per le schede, lsusb per le porte USB, lsblk per i dischi, free per la memoria. Quando serve un quadro d'insieme (per documentare un server, aprire una richiesta di assistenza, confrontare due macchine) conviene un solo comando che raccolga tutto: lshw.

Cos'è

lshw (list hardware) è un programma a sé, non fa parte di util-linux o di pciutils: su Debian e Ubuntu si installa con sudo apt install lshw (vedi l'articolo su apt). Raccoglie le informazioni da più fonti insieme: le tabelle del firmware (DMI/SMBIOS), il bus PCI, il bus USB, /proc e /sys (vedi l'articolo su uname per il kernel), i dischi, la rete. Poi le presenta come un albero: la macchina, la scheda madre, il processore, la memoria, i bus e tutto quello che c'è sopra.

Cosa fa

Mostra, per ogni componente, la descrizione, il prodotto e il costruttore, la posizione sul bus, il driver in uso, le capacità e, dove disponibili, dimensioni e numeri di serie. Può limitarsi a una o più classi di componenti, produrre una tabella compatta, oppure un output in JSON, XML o HTML. Non modifica niente.

Come si usa

$ sudo lshw [formato] [opzioni]

Gli esempi marcati "sandbox" sono output reali della macchina virtuale di prova (lshw della versione di Ubuntu 24.04, con 8 GiB di memoria, una CPU virtuale, sei dischi e una scheda di rete, tutti dispositivi virtuali virtio). Su una macchina virtuale mancano i dati del firmware, che su un server fisico sono invece abbondanti: gli esempi con web01, il server degli articoli precedenti, sono quindi illustrativi. Alcune righe molto lunghe (come l'elenco delle capabilities del processore) le ho omesse o accorciate.

Esempio 1: la tabella riassuntiva

$ sudo lshw -short
H/W path    Device    Class          Description
================================================
                      system         Computer
/0                    bus            Motherboard
/0/0                  memory         8GiB System memory
/0/1                  processor      Intel(R) Xeon(R) Processor @ 2.10GHz
/0/100                bridge         Intel Corporation
/0/100/2              storage        Virtio 1.0 block device
/0/100/2/0  /dev/vda  disk           Virtual I/O device
/0/100/3              storage        Virtio 1.0 block device
/0/100/3/0  /dev/vdb  disk           Virtual I/O device
...
/0/100/8              network        Virtio 1.0 network device
/0/100/8/0  eth0      network        Ethernet interface
/0/2                  communication  PnP device PNP0501
/0/3                  input          PnP device PNP0303

Con -short si ottiene una riga per componente: è il modo migliore per cominciare. La colonna H/W path è la posizione nell'albero: /0 è la scheda madre, /0/1 il processore, /0/100 il bridge del bus PCI e, sotto di lui, le schede (/0/100/8, la scheda di rete) con le periferiche collegate (/0/100/8/0, l'interfaccia eth0). Device è il nome che il sistema dà al componente (/dev/vda, eth0) e Class il tipo: memory, processor, storage, disk, network e così via. Da questo output reale si capisce subito che i dischi sono virtuali (virtio) e che non ci sono né scheda video né porte USB. Su un server fisico le righe sono decine: i singoli banchi di memoria, le schede di rete, i controller dei dischi, le periferiche USB.

Esempio 2: l'output completo

$ sudo lshw | head -n 18
vm
    description: Computer
    width: 64 bits
    capabilities: smp vsyscall32
  *-core
       description: Motherboard
       physical id: 0
     *-memory
          description: System memory
          physical id: 0
          size: 8GiB
     *-cpu
          product: Intel(R) Xeon(R) Processor @ 2.10GHz
          vendor: Intel Corp.
          physical id: 1
          bus info: cpu@0
          version: 6.207.2
          width: 64 bits

Senza opzioni lshw stampa l'albero completo. La prima riga è il nome della macchina (vm nel sandbox; su web01 sarebbe web01, lo stesso che mostra hostname). Ogni componente è introdotto da *- e rientrato rispetto a quello che lo contiene. I campi che si incontrano più spesso: description, product e vendor, physical id, bus info (l'indirizzo PCI o USB: lo stesso mostrato da lspci e lsusb), logical name (il nome nel sistema, come /dev/sda o eth0), serial, size, capabilities (le funzioni supportate) e configuration (driver in uso e impostazioni). Quando un componente non ha un driver, accanto al suo nome compare UNCLAIMED ("non reclamato"): nel sandbox lo si vede sui dispositivi virtuali. È l'equivalente della riga Kernel driver in use mancante in lspci -k, e su una macchina fisica con una scheda che non funziona è il primo indizio da cercare. L'output completo è molto lungo: si legge con less (vedi l'articolo relativo) o si salva in un file.

Esempio 3: solo certi componenti

$ sudo lshw -class network
  *-network
       description: Ethernet controller
       product: Virtio 1.0 network device
       vendor: Red Hat, Inc.
       physical id: 8
       bus info: pci@0000:00:08.0
...
$ sudo lshw -c network | grep -o -E 'logical name: .*|driver=[^ ]*|link=[^ ]*'
driver=virtio-pci
logical name: eth0
driver=virtio_net
link=yes
$ sudo lshw -short -c disk -c network
H/W path    Device    Class          Description
================================================
/0/100/2/0  /dev/vda  disk           Virtual I/O device
/0/100/3/0  /dev/vdb  disk           Virtual I/O device
...
/0/100/8              network        Virtio 1.0 network device
/0/100/8/0  eth0      network        Ethernet interface
$ sudo lshw -c bogus
$ echo $?
0

Con -class (o -c) si mostrano solo i componenti di una classe; l'opzione si può ripetere per averne più di una. Le classi che ho provato nel sandbox sono system, bus, memory, cpu (o processor), storage, disk, volume, network, input, communication e generic; su un server fisico se ne incontrano altre, come display (schede video) e power (alimentatori e batterie). Il secondo comando combina grep -o (vedi l'articolo su grep) per mostrare solo le righe che interessano: il nome dell'interfaccia (eth0), il driver della scheda (virtio_net) e lo stato del collegamento (link=yes). Attenzione: una classe che non esiste, o che non ha componenti (bogus, ma anche display nel sandbox, dove non c'è una scheda video), non produce errori: lshw non stampa niente e termina con codice 0. Un output vuoto non vuol dire quindi "classe sbagliata" o "errore".

Esempio 4: la posizione sui bus

$ sudo lshw -businfo | head -n 12
Bus info          Device    Class          Description
======================================================
                            system         Computer
                            bus            Motherboard
                            memory         8GiB System memory
cpu@0                       processor      Intel(R) Xeon(R) Processor @ 2.10GHz
pci@0000:00:00.0            bridge         Intel Corporation
pci@0000:00:01.0            generic        Virtio 1.0 memory balloon
virtio@0                    generic        Virtual I/O device
pci@0000:00:02.0            storage        Virtio 1.0 block device
virtio@1          /dev/vda  disk           Virtual I/O device
pci@0000:00:03.0            storage        Virtio 1.0 block device

Con -businfo al posto del percorso H/W path compare l'indirizzo sul bus: pci@0000:00:02.0 è lo stesso indirizzo che lspci scrive come 00:02.0 (con -D, 0000:00:02.0), mentre cpu@0 e virtio@1 sono altri tipi di collegamento. È utile per mettere in relazione l'output di lshw con quello di lspci -k e di dmesg, dove i dispositivi sono indicati proprio con questi indirizzi.

Esempio 5: JSON e jq

$ sudo lshw -json -c cpu -quiet | jq -r '.[0].product'
Intel(R) Xeon(R) Processor @ 2.10GHz
$ sudo lshw -json -c memory -quiet | jq -r '.[] | "\(.description) \(.size)"'
System memory 8589934592
$ sudo lshw -json -c disk -quiet | jq 'length'
6
$ sudo lshw -json -c disk -quiet | jq -r '.[].logicalname'

Con -json l'output diventa una struttura che jq sa interrogare (sudo apt install jq). Se si chiede una sola classe, il risultato è un elenco di oggetti, uno per componente; se non si specifica nessuna classe, è invece un unico oggetto con i componenti nidificati dentro children, più scomodo da usare. Le dimensioni sono in byte (8589934592 sono 8 GiB: vedi l'esempio 7). Con -quiet si toglie il messaggio di avanzamento sullo schermo. Nell'ultimo comando logicalname può contenere più valori per un componente (nel sandbox, per il disco con il file system principale ci sono due nomi: /dev/vda e /), perciò jq restituisce una lista; per questo l'ho lasciato senza output d'esempio, e per uno script conviene scegliere il primo elemento. Esistono anche -xml e -html: il primo è comodo per i programmi, il secondo produce una pagina che si apre in un browser (nel sandbox l'XML era di circa 28 KB).

Esempio 6: condividere l'output senza dati sensibili

$ sudo lshw -c network | grep -E 'serial|ip='
          serial: 02:fc:00:00:00:01
          configuration: ... ip=192.168.1.20 link=yes ...
$ sudo lshw -c network -sanitize | grep -E 'serial|ip='
          serial: [REMOVED]
          configuration: ... ip=[REMOVED] link=yes ...
$ sudo lshw -c network -numeric | grep -E 'product|vendor'
       product: Virtio 1.0 network device [1AF4:1041]
       vendor: Red Hat, Inc. [1AF4]
$ sudo lshw -notime -short | head -n 3
$ sudo lshw -sanitize -html > hardware.html

L'output completo contiene informazioni che non si vogliono diffondere: numeri di serie, indirizzi MAC, indirizzi IP. Con -sanitize vengono sostituiti con [REMOVED]: è l'opzione da usare prima di incollare l'output in un forum, in una segnalazione di errore o in un ticket di assistenza. Nell'esempio il MAC e l'indirizzo IP del primo blocco sono inventati (quelli reali del sandbox non li riporto); la sostituzione con [REMOVED] è invece quella vera. Con -numeric accanto ai nomi compaiono i codici costruttore:modello (gli stessi di lspci -nn): servono per cercare un driver senza ambiguità. Con -notime si escludono gli attributi che cambiano a ogni esecuzione (come l'ora), utile per confrontare due output con diff (vedi l'articolo relativo). L'ultimo comando salva un rapporto HTML pronto per essere archiviato. Un controllo in più prima di condividere un file: cerca a mano serial, ip= e il nome della macchina (la prima riga), perché -sanitize non copre ogni campo.

Esempio 7: uso negli script

#!/bin/bash
# Riepilogo hardware in una riga: CPU, memoria, numero di dischi
CPU=$(lshw -json -c cpu -quiet 2>/dev/null | jq -r '.[0].product')
RAM=$(lshw -json -c memory -quiet 2>/dev/null |
      jq -r '.[] | select(.description == "System memory") | .size')
DISCHI=$(lshw -json -c disk -quiet 2>/dev/null | jq 'length')
echo "CPU: $CPU | RAM: $((RAM / 1073741824)) GiB | Dischi: $DISCHI"

Lo script usa lshw -json e jq per costruire una riga di riepilogo: la CPU, la memoria (convertita da byte in GiB, dividendo per 1073741824, cioè 1024 al cubo) e il numero dei dischi. Nel sandbox ha risposto CPU: Intel(R) Xeon(R) Processor @ 2.10GHz | RAM: 8 GiB | Dischi: 6. Va lanciato con sudo (o dall'amministratore). Il campo select(.description == "System memory") serve perché, su un server fisico, -c memory elenca più elementi (firmware, cache, singoli banchi di memoria): lì conviene verificare con un lshw -c memory a mano prima di fidarsi del filtro.

Opzioni utili

  • lshw: albero completo; -short: una riga per componente; -businfo: con gli indirizzi sui bus.
  • -class CLASSE o -c CLASSE: solo una classe (ripetibile); -json, -xml, -html: altri formati.
  • -sanitize: toglie seriali, MAC e IP; -numeric: aggiunge i codici numerici; -notime: esclude i dati variabili.
  • -quiet: senza il messaggio di avanzamento; -disable TEST / -enable TEST: esclude o include una verifica (per esempio pci, isapnp, cpuid: l'elenco è nell'aiuto, lshw -h).
  • lscpu, lspci -k, lsusb, lsblk, free: le informazioni singole, più veloci e più semplici da elaborare.
  • dmidecode: i dati grezzi del firmware (banchi di memoria, numero di serie della macchina); hostnamectl: nome, sistema operativo, tipo di macchina.

Attenzione a

  • Serve sudo per un risultato completo: senza privilegi lshw scrive WARNING: you should run this program as super-user. e può mostrare meno dati (in particolare quelli che vengono dal firmware della macchina). Nel sandbox, con un utente senza privilegi, l'avviso è comparso e le informazioni di base (memoria, dischi, tabella -short) erano comunque stampate: non ho potuto verificare quanto manchi su un server fisico. Per un inventario serio si lancia sempre con sudo.
  • Nelle macchine virtuali e nei container i dati sono quelli che l'ambiente mostra: nel sandbox non c'erano né le tabelle del firmware (non c'è /sys/class/dmi) né un modello della macchina o del costruttore: il nome è vm, e la memoria è un unico blocco da 8 GiB. In un container si vedono di solito i dati della macchina ospite, o parti incomplete.
  • I dati possono essere imprecisi: lshw si fida del firmware e del kernel. Le dimensioni di un disco o della memoria sono generalmente affidabili, ma un campo come la velocità del collegamento o la frequenza dichiarata va controllato con lo strumento specifico (lscpu, lspci -vv, ethtool).
  • L'output completo contiene dati riservati: seriali, MAC, IP e il nome della macchina. Prima di condividerlo, usa -sanitize e controlla a mano (esempio 6).
  • Può essere lento: interroga molte fonti, e su un server con molti dischi o tante schede può impiegare alcuni secondi. Per un'informazione sola, lscpu o lsblk rispondono subito; con -disable si saltano le verifiche inutili.
  • Un componente elencato non è per forza funzionante: lshw dice che c'è, e se ha un driver (configuration: driver=...) o è UNCLAIMED. Se funziona, lo dicono i messaggi del kernel (dmesg).
  • Non è un programma di monitoraggio: fotografa l'hardware, non il carico di lavoro, la temperatura o lo stato di salute dei dischi (per questo servono top, sensors e smartctl). Il formato dell'output può cambiare da una versione all'altra: in uno script usa -json, non il testo dell'albero.

Riepilogo

ComandoCosa fa
sudo lshw -shortUna riga per componente: il punto di partenza
sudo lshwL'albero completo, con tutti i dettagli
sudo lshw -class networkSolo la classe indicata (ripetibile con -c)
sudo lshw -businfoCon gli indirizzi sui bus (PCI, USB...)
sudo lshw -json -c disk -quietOutput in JSON, per gli script (con jq)
sudo lshw -sanitizeToglie seriali, MAC e IP: da usare prima di condividere
sudo lshw -numericAggiunge i codici costruttore:modello
sudo lshw -html > hardware.htmlSalva un rapporto in HTML
sudo lshw -short -c memory -c cpuRiepilogo di memoria e processore

Nel prossimo articolo: dmidecode, per leggere le informazioni del firmware: modello della macchina, banchi di memoria, numeri di serie.