Capitolo 3. Inizializzazione del sistema

Indice

3.1. Panoramica del processo di avvio
3.1.1. Stadio 1: l'UEFI
3.1.2. Stadio 2: il bootloader
3.1.3. Stadio 3: il mini-sistema Debian
3.1.4. Stadio 4: il normale sistema Debian
3.2. Systemd
3.2.1. Init systemd
3.2.2. Login di systemd
3.3. I messaggi del kernel
3.4. I messaggi di sistema
3.5. Gestione del sistema
3.6. Altri strumenti di monitoraggio del sistema
3.7. Configurazione del sistema
3.7.1. Il nome host
3.7.2. Il filesystem
3.7.3. Inizializzazione delle interfacce di rete
3.7.4. Inizializzazione del sistema cloud
3.7.5. Esempio di personalizzazione per modificare il servizio sshd
3.8. Il sistema udev
3.9. L'inizializzazione dei moduli del kernel

È bene che l'amministratore di sistema conosca almeno a grandi linee come viene avviato e configurato il sistema Debian. Anche se i dettagli precisi sono nei file sorgenti dei pacchetti installati e nella loro documentazione, essi sono un po' troppo per la maggior parte degli utenti.

Ecco una panoramica di base dei punti principali dell'inizializzazione di un sistema Debian. Dato che un sistema Debian è in costante evoluzione, si dovrebbe far riferimento alla documentazione più recente.

Il sistema del computer passa attraverso varie fasi del processo di avvio, dall'accensione a quando offre all'utente il sistema operativo (SO) pienamente funzionante.

Per semplicità la spiegazione è limitata alla piattaforma PC tipica con l'installazione standard.

Il normale processo di avvio è come un razzo a quattro stadi. Ogni stadio del razzo passa il controllo del sistema allo stadio successivo.

Naturalmente questo può essere configurato in modo diverso. Per esempio, se è stato compilato un kernel personalizzato, si potrebbe saltare la fase con il mini-sistema Debian. Non dare per scontato che quanto detto valga per il proprio sistema fino a che non si abbia controllato direttamente.

La Unified Extensible Firmware Interface (UEFI) definisce un gestore di avvio come parte della specifica UEFI. Quando un computer viene acceso, il gestore dell'avvio è il primo stadio del processo di avvio che controlla la configurazione di avvio e, in base alle sue impostazioni, esegue poi il boot loader del sistema operativo specificato o il kernel del sistema operativo (solitamente il boot loader). La configurazione di avvio è definita dalle variabili memorizzate nella NVRAM, incluse variabili che indicano i percorsi del file system dei caricatori dei SO o dei kernel dei SO.

Una partizione di sistema EFI (ESP, EFI System Partition) è una partizione di dispositivo per archiviazione di dati che è utilizzata nei computer che sono conformi alla specifica UEFI. Il firmware UEFI accede ad essa quando un computer viene acceso, essa memorizza le applicazioni UEFI e i file che tali applicazioni devono eseguire, inclusi i boot loader dei sistemi operativi. (Nei sistemi PC vecchi può essere invece utilizzato il BIOS memorizzato nella MBR.)

Il bootloader è il secondo stadio del processo di avvio che è iniziato dall'UEFI. Carica l'immagine kernel del sistema e l'immagine initrd in memoria e passa il controllo ad esse. L'immagine initrd è l'immagine del file system radice ed il suo supporto dipende dal bootloader usato.

Il sistema Debian normalmente usa il kernel Linux xome kernel di sistema predefinito. L'immagine initrd per l'attuale kernel Linux 5.x è tecnicamente l'immagine initramfs (Initial RAM filesystem, file system RAM iniziale).

Sono disponibili molti bootloader e opzioni di configurazione.


[Avvertimento] Avvertimento

Non mettere mano ai bootloader senza aver creato supporti avviabili di ripristino (chiavette USB, CD o floppy) create da immagini nel pacchetto grub-rescue-pc. Questo permette di avviare il sistema anche senza un bootloader funzionante sul disco fisso.

Per i sistemi UEFI, GRUB2 prima legge la partizione ESP e usa l'UUID specificato per search.fs_uuid in "/boot/efi/EFI/debian/grub.cfg" per determinare la partizione del file di configurazione del menu di GRUB2 "/boot/grub/grub.cfg".

La parte della chiave del file di configurazione del menu di GRUB2 è simile a:

menuentry 'Debian GNU/Linux' ... {
        load_video
        insmod gzio
        insmod part_gpt
        insmod ext2
        search --no-floppy --fs-uuid --set=root fe3e1db5-6454-46d6-a14c-071208ebe4b1
        echo    'Loading Linux 5.10.0-6-amd64 ...'
        linux   /boot/vmlinuz-5.10.0-6-amd64 root=UUID=fe3e1db5-6454-46d6-a14c-071208ebe4b1 ro quiet
        echo    'Loading initial ramdisk ...'
        initrd  /boot/initrd.img-5.10.0-6-amd64
}

Per questa porzione di /boot/grub/grub.cfg, questa voce di menu significa quanto segue.


[Suggerimento] Suggerimento

si può abilitare la visualizzazione dei messaggi del log di avvio del kernel rimuovendo quiet in "/boot/grub/grub.cfg". Per fare la modifica in modo persistente, modificare la riga "GRUB_CMDLINE_LINUX_DEFAULT="quiet"" in "/etc/default/grub".

[Suggerimento] Suggerimento

Si può personalizzare la schermata grafica di GRUB impostando la variabile GRUB_BACKGROUND in "/etc/default/grub" in modo che punti al file dell'immagine o mettendo l'immagine stessa in "/boot/grub/".

Vedere "info grub" e grub-install(8).

Il mini-sistema Debian è il terzo stadio del processo di avvio che viene iniziato dal bootloader. Esegue il kernel del sistema con il suo filesystem root in memoria. Questo è uno stadio opzionale preparatorio del processo di avvio.

[Nota] Nota

L'espressione "sistema Debian mini" è stata coniata per descrivere il terzo stadio del processo di avvio in questo documento. Normalmente ci si riferisce a questo sistema come sistema initrd o initramfs. Un sistema simile in memoria è usato dall'installatore Debian.

Il programma "/init" viene eseguito come primo programma in questo file system root in memoria. È un programma che inizializza il kernel in spazio utente e passa il controllo allo stadio successivo. Questo mini-sistema Debian offre flessibilità al processo di avvio, come la possibilità di aggiungere moduli del kernel prima del processo di avvio principale o di montare il file system root come cifrato.

  • Il programma "/init" è uno script di shell se initramfs è stato creato da initramfs-tools.

    • Si può interrompere questa parte del processo di avvio per ottenere una shell di root fornendo il parametro di avvio per il kernel "break=init" etc. Vedere lo script "/init" per ulteriori condizioni di interruzione. Questo ambiente shell è abbastanza sofisticato da fare una buona ispezione dell'hardware della macchina.

    • I comandi disponibili in questo mini-sistema Debian sono versioni minimali e vengono principalmente forniti da uno strumento GNU chiamato busybox(1).

  • Il programma "/init" è un programma binario di systemd se initramfs è stato creato da dracut.

    • I comandi disponibili in questo mini-sistema Debian sono un ambiente systemd(1) ridotto al minimo.

[Attenzione] Attenzione

È necessario usare l'opzione "-n" per il comando mount quando si è nel filesystem root in sola lettura.

Il sistema Debian normale è il quarto stadio del processo di avvio che viene iniziato dal mini-sistema Debian. Il kernel di sistema del mini-sistema Debian continua ad essere in esecuzione anche in questo ambiente. Il filesystem root viene cambiato da quello in memoria all'effettivo filesystem sul disco fisso.

Il programma init viene eseguito come primo programma con PID=1 per effettuare il processo principale di avvio di far partire molti programmi. Il percorso di file predefinito per il programma init è «/usr/sbin/init», ma può essere cambiato con un parametro di avvio del kernel come in «init=/percorso/del/programma_init».

"/usr/sbin/init" è un collegamento simbolico a "/lib/systemd/systemd" a partire da Debian 8 Jessie (rilasciata nel 2015).

[Suggerimento] Suggerimento

Si può verificare quale è l'effettivo comando init nel proprio sistema con il comando «ps --pid 1 -f».


[Suggerimento] Suggerimento

Vedere la pagina del Wiki Debian sulla velocizzazione del processo di avvio per i più recenti suggerimenti su come velocizzare il processo di avvio.

Quando il sistema si avvia, /usr/sbin/init che è un collegamento simbolico a /usr/lib/systemd viene avviato come processo init del sistema (PID=1) con proprietario root (UID=0). Vedere systemd(1).

Il processo di init systemd lancia processi in parallelo sulla base dei file di configurazione delle unità (vedere systemd.unit(5)) che sono scritti in stile dichiarativo invece che in stile procedurale come per SysV.

I processi avviati sono messi in singoli gruppi di controllo (control group) Linux che prendono il nome dall'unità a cui appartengono nella gerarchia privata di systemd (vedere cgroups e Sezione 4.7.5, «Funzionalità di sicurezza di Linux»).

Le unità per le modalità di sistema sono caricate dal "System Unit Search Path" come descritto in systemd.unit(5). Quelle principali sono, in ordine di importanza, le seguenti:

  • "/etc/systemd/system/*": unità di sistema create dall'amministratore

  • "/run/systemd/system/*": unità runtime

  • "/lib/systemd/system": unità di sistema installate dal gestore dei pacchetti della distribuzione

Le loro inter-dipendenze sono specificate dalle direttive "Wants=", "Requires=", "Before=", "After=", … (vedere "MAPPING OF UNIT PROPERTIES TO THEIR INVERSES" in systemd.unit(5)). Sono definiti anche i controlli delle risorse (vedere systemd.resource-control(5)).

Il suffisso dei file di configurazione delle unità codifica il loro tipo in questo modo:

  • *.service descrive un processo controllato e supervisionato da systemd. Vedere systemd.service(5).

  • *.device descrive un device esposto in sysfs(5) come albero di device udev(7). Vedere systemd.device(5).

  • *.mount descrive un punto di mount del file system controllato e supervisionato da systemd. Vedere systemd.mount(5).

  • *.automount descrive un punto di mount automatico del file system controllato e supervisionato da systemd. Vedere systemd.automount(5).

  • *.swap descrive un device o file di swap controllato e supervisionato da systemd. Vedere systemd.swap(5).

  • *.path descrive un percorso monitorato da systemd per l'attivazione basata su percorso. Vedere systemd.path(5).

  • *.socket descrive un socket controllato e supervisionato da systemd per l'attivazione basata su socket. Vedere systemd.socket(5).

  • *.timer descrive un timer controllato e supervisionato da systemd per l'attivazione basata su timer. Vedere systemd.timer(5).

  • *.slice gestisce risorse con cgroups(7). Vedere systemd.slice(5).

  • *.scope viene creato programmaticamente usando le interfacce di bus di systemd per gestire un insieme di processi di sistema. Vedere systemd.scope(5).

  • *.target raggruppa altri file di configurazione di unità per creare punti di sincronizzazione durante l'avvio. Vedere systemd.target(5).

All'avvio del sistema (cioè init) il processo systemd cerca di avviare "/lib/systemd/system/default.target" (normalmente un collegamento simbolico a "graphical.target"). Come prima cosa alcune speciali unità target (vedere systemd.special(7)) come "local-fs.target", "swap.target" e "cryptsetup.target" sono richiamate per montare i file system. Poi altre unità target vengono anch'esse richiamate dalle dipendenze delle unità target. Per i dettagli leggere bootup(7).

systemd offre funzionalità di compatibilità all'indietro. Gli script di avvio in stile SysV in "/etc/init.d/rc[0123456S].d/[KS]name" sono comunque analizzati e telinit(8) viene tradotto in richieste di attivazione di unità systemd.

[Attenzione] Attenzione

Run level emulati da 2 a 4 hanno tutti collegamenti simbolici al corrispondente "multi-user.target".

I messaggi di errore del kernel visualizzati nella console possono essere configurati impostando il loro livello di soglia.

# dmesg -n3

Sotto systemd sia i messaggi del kernel sia quelli di sistema sono registrati nei log dal servizio journal systemd-journald.service (alias journald) o in dati binari persistenti dentro "/var/log/journal" o in dati binari volatili dentro "/run/log/journal/". A questi dati binari di log si può accedere tramite il comando journalctl(1). Ad esempio si può visualizzare il log dall'ultimo avvio con:

$ journalctl -b

In systemd l'utilità per il registro di log di sistema, rsyslogd(8), può essere disinstallato. Se è installato, cambia il comportamento per leggere i dati del log binario volatile (invece del predefinito pre-systemd "/dev/log") e per creare dati log di sistema ASCII tradizionali permanenti. Questo può essere personalizzato da "/etc/default/rsyslog" e "/etc/rsyslog.conf" sia per il file di log sia per la visualizzazione a schermo. Vedere rsyslogd(8) e rsyslog.conf(5). Vedere anche Sezione 9.3.2, «Analizzatori di registro».

systemd offre non solo un sistema init, ma anche funzionalità generiche di gestione del sistema, con il comando systemctl(1).

Tabella 3.6. Elenco di tipici esempi di comandi systemctl

Operazione Esempio di comando
Elencare tutti i tipi di unità disponibili "systemctl list-units --type=help"
Elencare tutte le unità target in memoria "systemctl list-units --type=target"
Elencare tutte le unità di servizi in memoria "systemctl list-units --type=service"
Elencare tutte le unità di device in memoria "systemctl list-units --type=device"
Elencare tutte le unità di mount in memoria "systemctl list-units --type=mount"
Elencare tutte le unità socket in memoria "systemctl list-sockets"
Elencare tutte le unità timer in memoria "systemctl list-timers"
Avviare "$unit" "systemctl start $unit"
Fermare "$unit" "systemctl stop $unit"
Ricaricare la configurazione specifica di un servizio "systemctl reload $unit"
Fermare e riavviare tutte le "$unit" "systemctl restart $unit"
Avviare "$unit" e fermare tutte le altre "systemctl isolate $unit"
Passare alla modalità "graphical" (sistema GUI) "systemctl isolate graphical"
Passare alla modalità "multi-user" (sistema CLI) "systemctl isolate multi-user"
Passare alla modalità "rescue" (sistema CLI a singolo utente) "systemctl isolate rescue"
Inviare il segnale kill a "$unit" "systemctl kill $unit"
Controllare se il servizio "$unit" è attivo "systemctl is-active $unit"
Controllare se il servizio "$unit" è fallito "systemctl is-failed $unit"
Controllare lo stato di "$unit|$PID|device" "systemctl status $unit|$PID|$device"
Mostrare le proprietà di "$unit|$job" "systemctl show $unit|$job"
Ripristinare "$unit" fallita "systemctl reset-failed $unit"
Elencare le dipendenze di tutti i servizi unità "systemctl list-dependencies --all"
Elencare i file di unità installati sul sistema "systemctl list-unit-files"
Abilitare "$unit" (aggiungere collegamento simbolico) "systemctl enable $unit"
Disabilitare "$unit" (rimuovere collegamento simbolico) "systemctl disable $unit"
Togliere maschera a "$unit" (rimuovere collegamento simbolico a"/dev/null") "systemctl unmask $unit"
Mascherare "$unit" (aggiungere collegamento simbolico a"/dev/null") "systemctl mask $unit"
Ottenere l'impostazione del target predefinito "systemctl get-default"
Impostare default-target a "graphical" (sistema GUI) "systemctl set-default graphical"
Impostare default-target a "multi-user" (sistema CLI) "systemctl set-default multi-user"
Mostrare l'ambiente del lavoro "systemctl show-environment"
Impostare la variabile "variable" dell'ambiente di lavoro al valore "value" "systemctl set-environment variable=value"
Disimpostare la variabile "variable" dell'ambiente di lavoro "systemctl unset-environment variable"
Ricaricare tutti i file di unità e i demoni "systemctl daemon-reload"
Spegnere il sistema "systemctl poweroff"
Spegnere e riavviare il sistema "systemctl reboot"
Sospendere il sistema "systemctl suspend"
Ibernare il sistema "systemctl hibernate"

Negli esempi soprastanti "$unit" può essere un singolo nome di unità (suffissi come .service e .target sono opzionali) o, in molti casi, la specifica di più unità (con glob in stile shell "*", "?", "[]" usando fnmatch(3) con corrispondenze con i nomi primari di tutte le unità attualmente in memoria).

I comandi che cambiano lo stato del sistema negli esempi soprastanti sono tipicamente preceduti da "sudo" per ottenere i privilegi amministrativi necessari.

L'output di "systemctl status $unit|$PID|$device" usa il colore del puntino ("●") per riassumere lo stato dell'unità a prima vista.

  • Un "●" bianco indica uno stato "inattivo" o "deattivato".

  • Un "●" rosso indica uno stato di "fallimento" o "errore".

  • Un "●" verde indica uno stato "attivo", "in ricaricamento" o "in attivazione".

Ecco un elenco di altri esempi di comandi per il monitoraggio in systemd. Leggere le relative pagine di manuale, inclusa cgroups(7).


Le opzioni usate per montare i file system normali dei dischi e di rete sono impostate in "/etc/fstab". Vedere fstab(5) e Sezione 9.6.7, «Ottimizzare il file system con opzioni di mount».

La configurazione dei file system cifrati è impostata in "/etc/crypttab". Vedere crypttab(5)

Vedere wvdial(1) e wvdial.conf(5).

[Avvertimento] Avvertimento

Dopo aver montato tutti i filesystem, i file temporanei in "/tmp", "/var/lock" e "/var/run" vengono ripuliti ad ogni avvio.

L'istanza del sistema cloud può essere lanciata come clone di "immagini cloud ufficiali Debian" o immagini simili. Per tali istanze di sistema, entità come nome host, file system, rete, localizzazione, chiavi SSH, utenti e gruppi, possono essere configurate usando funzionalità fornite dai pacchetti cloud-init e netplan.io con diverse fonti di dati, come i file posizionati nell'immagine del sistema originale e dati esterni forniti durante il suo avvio. Questi pacchetti permettono la configurazione dichiarativa del sistema usando dati YAML.

Vedere ulteriori informazioni in "Cloud Computing with Debian and its descendants", "Documentazione di Cloud-init" e Sezione 5.4, «La configurazione moderna della rete per il cloud».

Con l'installazione predefinita molti servizi di rete (vedere Capitolo 6, Applicazioni per la rete) vengono avviati come processi demone dopo network.target al momento dell'avvio di sistema da systemd. "sshd non fa eccezione. Come esempio di personalizzazione cambiamo questo comportamento nell'avvio on-demand di "sshd".

Come prima cosa disabilitare l'unità di servizio installata dal sistema.

 $ sudo systemctl stop sshd.service
 $ sudo systemctl mask sshd.service

Il sistema di attivazione on-demand dei socket dei servizi classici Unix avveniva attraverso il superserver inetd (o xinetd). Con systemd il comportamento equivalente può essere abilitato aggiungendo file di configurazione di unità *.socket e *.service.

sshd.socket per specificare un socket su cui restare in ascolto

[Unit]
Description=SSH Socket for Per-Connection Servers

[Socket]
ListenStream=22
Accept=yes

[Install]
WantedBy=sockets.target

sshd@.service come file di servizio corrispondente di sshd.socket

[Unit]
Description=SSH Per-Connection Server

[Service]
ExecStart=-/usr/sbin/sshd -i
StandardInput=socket

Poi ricaricare.

 $ sudo systemctl daemon-reload

Il sistema udev fornisce un meccanismo di rilevazione e inizializzazione automatiche dell'hardware (vedere udev(7)) a partire dal kernel Linux 2.6. Per ogni dispositivo rilevato dal kernel, il sistema udev avvia un processo utente che usa le informazioni del file system sysfs (vedere Sezione 1.2.12, «procfs e sysfs»), carica, usando il programma modprobe(8) (vedere Sezione 3.9, «L'inizializzazione dei moduli del kernel»), i moduli del kernel necessari per il supporto del dispositivo e crea i nodi di device corrispondenti.

[Suggerimento] Suggerimento

Se, per una qualche ragione "/lib/modules/versione-kernel/modules.dep non viene generato in modo appropriato dal depmod(8), i moduli non possono essere caricati come dovuto dal sistema udev. Per risolvere il problema eseguire "depmod -a".

Per le regole di montaggio in "/etc/fstab", non è necessario che i nodi di device siano statici. Si possono usare gli UUID per montare i dispositivi, al posto dei nomi di device come "/dev/sda". Vedere Sezione 9.6.3, «Accedere alle partizioni usando UUID».

Dato che il sistema udev è in qualche modo in costante evoluzione, in questo documento sono fornite informazioni base, lasciando i dettagli ad altra documentazione.

[Avvertimento] Avvertimento

Non cercare di eseguire programmi con tempi di esecuzione lunghi, come script di backup con RUN in regole udev, come detto in udev(7). Creare invece un file systemd.service(5) corretto e attivarlo. Vedere Sezione 10.2.3.2, «Backup attivato da eventi di mount».

Il programma modprobe(8) permette di configurare il kernel Linux in esecuzione da processi utente, aggiungendo e rimuovendo moduli del kernel. Il sistema udev (vedere Sezione 3.8, «Il sistema udev») automatizza la sua invocazione per facilitare l'inizializzazione dei moduli del kernel.

Ci sono moduli non-hardware e speciali moduli con driver hardware, come quelli elencati in seguito, che devono essere precaricati elencandoli nel file "/etc/modules" (vedere modules(5)).

I file di configurazione per il programma modprobe(8) sono contenuti nella directory "/etc/modprobes.d/", come spiegato in modprobe.conf(5). (Se si desidera evitare l'autocaricamento di alcuni moduli del kernel, considerare la loro aggiunta nella lista nera nel file "/etc/modprobes.d/blacklist".)

Il file "/lib/modules/versione/modules.dep" generato dal programma depmod(8) descrive le dipendenze dei moduli usate dal programma modprobe(8).

[Nota] Nota

Se si hanno problemi di caricamento dei moduli all'avvio o con modprobe(8), "depmod -a" potrebbe risolverli rigenerando il file "modules.dep".

Il programma modinfo(8) mostra informazioni su un modulo del kernel Linux.

Il programma lsmod(8) formatta in un bel modo i contenuti di "/proc/modules", mostrando quali moduli del kernel siano attualmente caricati.

[Suggerimento] Suggerimento

Si può identificare l'esatto hardware sul proprio sistema. Vedere Sezione 9.5.3, «Identificazione dell'hardware».

Si può configurare l'hardware all'avvio per attivare le funzionalità dell'hardware desiderate. Vedere Sezione 9.5.4, «Configurazione dell'hardware».

Si può probabilmente aggiungere il supporto per il proprio speciale dispositivo ricompilando il kernel. Vedere Sezione 9.10, «Il kernel».