Dipende interamente da quali servizi vuoi avere sul tuo dispositivo.
Programmi
Puoi fare in modo che Linux si avvii direttamente in una shell . Non è molto utile in produzione - chi vorrebbe solo avere una shell lì - ma è utile come meccanismo di intervento quando si dispone di un bootloader interattivo:pass init=/bin/sh
alla riga di comando del kernel. Tutti i sistemi Linux (e tutti i sistemi Unix) hanno una shell in stile Bourne/POSIX in /bin/sh
.
Avrai bisogno di una serie di utility shell . BusyBox è una scelta molto comune; contiene una shell e utilità comuni per la manipolazione di file e testo (cp
, grep
, …), impostazione della rete (ping
, ifconfig
, …), manipolazione del processo (ps
, nice
, …) e vari altri strumenti di sistema (fdisk
, mount
, syslogd
, …). BusyBox è estremamente configurabile:puoi selezionare gli strumenti che desideri e persino le singole funzionalità in fase di compilazione, per ottenere il giusto compromesso tra dimensioni e funzionalità per la tua applicazione. A parte sh
, il minimo indispensabile senza il quale non puoi davvero fare nulla è mount
, umount
e halt
, ma sarebbe atipico non avere anche cat
, cp
, mv
, rm
, mkdir
, rmdir
, ps
, sync
e pochi altri. BusyBox si installa come un singolo binario chiamato busybox
, con un collegamento simbolico per ogni utilità.
Il primo processo su un normale sistema unix si chiama init
. Il suo compito è avviare altri servizi. BusyBox contiene un sistema init. Oltre al init
binario (di solito si trova in /sbin
), avrai bisogno dei suoi file di configurazione (solitamente chiamati /etc/inittab
- alcuni sostituti init moderni eliminano quel file ma non li troverai su un piccolo sistema integrato) che indicano quali servizi avviare e quando. Per BusyBox, /etc/inittab
è facoltativo; se manca, ottieni una shell di root sulla console e lo script /etc/init.d/rcS
(posizione predefinita) viene eseguito all'avvio.
Questo è tutto ciò di cui hai bisogno, oltre ovviamente ai programmi che consentono al tuo dispositivo di fare qualcosa di utile. Ad esempio, sul mio router di casa che esegue una variante OpenWrt, gli unici programmi sono BusyBox, nvram
(per leggere e modificare le impostazioni nella NVRAM) e utilità di rete.
A meno che tutti i tuoi eseguibili non siano collegati staticamente, avrai bisogno del caricatore dinamico (ld.so
, che possono essere chiamate con nomi diversi a seconda della scelta della libc e delle architetture del processore) e tutte le librerie dinamiche (/lib/lib*.so
, forse alcuni di questi in /usr/lib
) richiesto da questi eseguibili.
Struttura delle directory
Il Filesystem Hierarchy Standard descrive la struttura di directory comune dei sistemi Linux. È orientato alle installazioni desktop e server:molto può essere omesso su un sistema embedded. Ecco un minimo tipico.
/bin
:programmi eseguibili (alcuni potrebbero essere in/usr/bin
invece)./dev
:nodi del dispositivo (vedi sotto)/etc
:file di configurazione/lib
:librerie condivise, incluso il caricatore dinamico (a meno che tutti gli eseguibili non siano collegati staticamente)/proc
:punto di montaggio per il filesystem proc/sbin
:programmi eseguibili. La distinzione con/bin
è quel/sbin
è per i programmi che sono utili solo all'amministratore di sistema, ma questa distinzione non è significativa sui dispositivi embedded. Puoi fare/sbin
un collegamento simbolico a/bin
./mnt
:comodo da avere su filesystem root di sola lettura come punto di montaggio iniziale durante la manutenzione/sys
:punto di montaggio per il filesystem sysfs/tmp
:posizione per i file temporanei (spesso untmpfs
montare)/usr
:contiene le sottodirectorybin
,lib
esbin
./usr
esiste per file extra che non si trovano nel filesystem root. Se non ce l'hai, puoi fare/usr
un collegamento simbolico alla directory principale.
File del dispositivo
Ecco alcune voci tipiche in un /dev
minimo :
console
full
(scrivendoci riporta sempre “nessuno spazio rimasto sul dispositivo”)log
(un socket che i programmi usano per inviare voci di log), se hai unsyslogd
demone (come quello di BusyBox) che legge da essonull
(si comporta come un file sempre vuoto)ptmx
e unpts
directory, se si desidera utilizzare pseudo-terminali (ovvero qualsiasi terminale diverso dalla console) — ad es. se il dispositivo è connesso in rete e vuoi accedere tramite telnet o sshrandom
(restituisce byte casuali, rischia il blocco)tty
(indica sempre il terminale del programma)urandom
(restituisce byte casuali, non blocca mai ma può essere non casuale su un dispositivo appena avviato)zero
(contiene una sequenza infinita di byte nulli)
Oltre a ciò avrai bisogno di voci per il tuo hardware (tranne le interfacce di rete, queste non ottengono voci in /dev
):porte seriali, storage, ecc.
Per i dispositivi incorporati, normalmente creeresti le voci del dispositivo direttamente sul filesystem root. I sistemi di fascia alta hanno uno script chiamato MAKEDEV
per creare /dev
voci, ma su un sistema integrato lo script spesso non è raggruppato nell'immagine. Se alcuni hardware possono essere collegati a caldo (ad es. se il dispositivo ha una porta host USB), allora /dev
dovrebbe essere gestito da udev (potresti avere ancora un set minimo sul filesystem root).
Azioni all'avvio
Oltre al filesystem di root, è necessario montarne altri per il normale funzionamento:
- procfs su
/proc
(praticamente indispensabile) - sysfs su
/sys
(praticamente indispensabile) tmpfs
filesystem su/tmp
(per consentire ai programmi di creare file temporanei che saranno nella RAM, piuttosto che nel filesystem di root che potrebbe essere in flash o in sola lettura)- tmpfs, devfs o devtmpfs su
/dev
se dinamico (vedi udev in "File dispositivo" sopra) - sviluppa su
/dev/pts
se vuoi usare [pseudo-terminali (vedi l'osservazione supts
sopra)
Puoi creare un /etc/fstab
file e chiama mount -a
o eseguire mount
manualmente.
Avvia un demone syslog (così come klogd
per i log del kernel, se syslogd
il programma non se ne occupa), se hai un posto dove scrivere i log.
Successivamente, il dispositivo è pronto per avviare i servizi specifici dell'applicazione.
Come creare un filesystem root
Questa è una storia lunga e diversificata, quindi tutto ciò che farò qui è fornire alcune indicazioni.
Il filesystem di root può essere conservato nella RAM (caricato da un'immagine (solitamente compressa) in ROM o flash), o su un filesystem basato su disco (memorizzato in ROM o flash), o caricato dalla rete (spesso tramite TFTP) se applicabile . Se il filesystem di root è nella RAM, impostalo come initramfs — un filesystem RAM il cui contenuto viene creato al momento dell'avvio.
Esistono molti framework per assemblare immagini root per sistemi embedded. Ci sono alcuni suggerimenti nelle FAQ di BusyBox. Buildroot è popolare e ti consente di creare un'intera immagine root con una configurazione simile al kernel Linux e BusyBox. OpenEmbedded è un altro framework simile.
Wikipedia ha un elenco (incompleto) di popolari distribuzioni Linux embedded. Un esempio di Linux integrato che potresti avere vicino a te è la famiglia di sistemi operativi OpenWrt per dispositivi di rete (popolare sui router domestici degli armeggiatori). Se vuoi imparare dall'esperienza, puoi provare Linux da zero, ma è orientato verso sistemi desktop per hobbisti piuttosto che verso dispositivi embedded.
Una nota su Linux rispetto al kernel Linux
L'unico comportamento integrato nel kernel di Linux è che il primo programma avviato all'avvio. (Non entrerò qui nelle sottigliezze di initrd e initramfs.) Questo programma, tradizionalmente chiamato init, ha l'ID di processo 1 e ha alcuni privilegi (immunità ai segnali KILL) e responsabilità (raccogliere gli orfani). Puoi eseguire un sistema con un kernel Linux e avviare quello che vuoi come primo processo, ma poi quello che hai è un sistema operativo basato sul kernel Linux, e non quello che normalmente viene chiamato "Linux" - Linux, nel senso comune del termine, è un sistema operativo simile a Unix il cui kernel è il kernel Linux. Ad esempio, Android è un sistema operativo che non è simile a Unix ma basato sul kernel Linux.
Tutto ciò di cui hai bisogno è un eseguibile collegato staticamente, posizionato sul filesystem, in isolamento. Non hai bisogno di altri file. Quell'eseguibile è il processo init. Può essere occupato. Questo ti dà una shell e una miriade di altre utilità, tutto in sé. Puoi passare a un sistema completamente funzionante semplicemente eseguendo i comandi manualmente in busybox per montare il filesystem root in lettura-scrittura, creare nodi /dev, eseguire real init, ecc.
Se non hai bisogno di alcuna utilità di shell, un mksh
linkato staticamente binario (ad esempio contro klibc - 130K su Linux/i386) andrà bene. Hai bisogno di un /linuxrc
o /init
o /sbin/init
script che chiama solo mksh -l -T!/dev/tty1
in un ciclo:
#!/bin/mksh
while true; do
/bin/mksh -l -T!/dev/tty1
done
L'-T!$tty
opzione è un'aggiunta recente a mksh
che gli dice di generare una nuova shell sul terminale dato e di aspettarla. (Prima c'era solo -T-
per demonizzare un programma e -T$tty
per spawnare su un terminale ma non aspettarlo. Non è stato così bello.) Il -l
l'opzione gli dice semplicemente di eseguire una shell di login (che legge /etc/profile
, ~/.profile
e ~/.mkshrc
).
Ciò presuppone che il tuo terminale sia /dev/tty1
, sostituto. (Con più magia, il terminale può essere scoperto automaticamente. /dev/console
non ti darà il pieno controllo del lavoro.)
Hai bisogno di alcuni file in /dev
perché funzioni:
- /dev/console
- /dev/null
- /dev/tty
- /dev/tty1
Avvio con l'opzione del kernel devtmpfs.mount=1
elimina la necessità di un /dev
completo , lascia che sia una directory vuota (adatta per l'uso come punto di montaggio).
Normalmente vorrai avere alcune utilità (da klibc, busybox, beastiebox, toybox o toolbox), ma non sono realmente necessarie.
Potresti voler aggiungere un ~/.mkshrc
file, che imposta $PS1 e alcuni alias e funzioni di shell di base.
Una volta ho realizzato un initrd compresso da 171K (371K non compresso) per Linux/m68k usando solo mksh (e il suo file mkshrc di esempio) e klibc-utils. (Questo era prima che -T! fosse aggiunto alla shell, quindi ha generato la shell di login su /dev/tty2
invece e ha inviato un messaggio alla console dicendo all'utente di cambiare terminale.) Funziona bene.
Questo è un minimo davvero indispensabile impostare. Le altre risposte forniscono ottimi consigli verso sistemi un po' più caratterizzati. Questo è un vero caso speciale.
Dichiarazione di non responsabilità:sono lo sviluppatore mksh.