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 PNP0303Con -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 bitsSenza 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 $?
0Con -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 deviceCon -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.htmlL'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 CLASSEo-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 esempiopci,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
sudoper un risultato completo: senza privilegilshwscriveWARNING: 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 consudo. - 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:
lshwsi 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
-sanitizee 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,
lscpuolsblkrispondono subito; con-disablesi saltano le verifiche inutili. - Un componente elencato non è per forza funzionante:
lshwdice 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,sensorsesmartctl). Il formato dell'output può cambiare da una versione all'altra: in uno script usa-json, non il testo dell'albero.
Riepilogo
| Comando | Cosa fa |
|---|---|
sudo lshw -short | Una riga per componente: il punto di partenza |
sudo lshw | L'albero completo, con tutti i dettagli |
sudo lshw -class network | Solo la classe indicata (ripetibile con -c) |
sudo lshw -businfo | Con gli indirizzi sui bus (PCI, USB...) |
sudo lshw -json -c disk -quiet | Output in JSON, per gli script (con jq) |
sudo lshw -sanitize | Toglie seriali, MAC e IP: da usare prima di condividere |
sudo lshw -numeric | Aggiunge i codici costruttore:modello |
sudo lshw -html > hardware.html | Salva un rapporto in HTML |
sudo lshw -short -c memory -c cpu | Riepilogo di memoria e processore |
Nel prossimo articolo: dmidecode, per leggere le informazioni del firmware: modello della macchina, banchi di memoria, numeri di serie.