🦾 Il braccio in C: il modulo oa
Se coa è la mente che disegna il piano di volo, il binario oa ("uova") è il braccio che lo esegue. È deliberatamente minuscolo — poche centinaia di righe di C più il parser cJSON integrato — e deliberatamente cieco: non sa nulla di distribuzioni, YAML o template. Riceve /tmp/coa/oa-plan.json, lo percorre passo dopo passo e, in base al campo module di ciascun task, lo esegue nativamente in C oppure lo delega al tecnico Go (coa ell).
📥 1. Invocazione e struttura (main.c)
oa accetta il piano sia da file che da STDIN, oltre a offrire una maniglia di emergenza per lo smontaggio:
oa /tmp/coa/oa-plan.json # lettura da file
cat /tmp/coa/oa-plan.json | oa # lettura da STDIN (pipe)
oa cleanup [work_dir] # smontaggio di emergenza (default: /home/eggs)
Ogni passo viene registrato in /var/log/penguins-eggs.log.
🔀 2. Lo smistatore (engine.c)
L'intera logica di instradamento risiede in una funzione cristallina:
int is_native_module(const char *module) {
if (strcmp(module, "users") == 0 ||
strcmp(module, "umount") == 0) {
return 1; // eseguito nativamente in C
}
return 0; // delegato a coa ell (Go)
}
- Modulo nativo (
users,umount):run_native()lo esegue direttamente in-process tramite syscall di sistema. - Qualsiasi altro modulo:
run_go_worker()effettua unfork, invia il singolo task come JSON grezzo nelloSTDINdel processo figlio ed eseguecoa ell, raccogliendone l'output nel log condiviso e verificando l'exit code. Un task, un processo worker, un codice di uscita.
⚙️ 3. I moduli nativi in C (native.c e oa-yocto.c)
Solo le operazioni che richiedono davvero di lavorare a stretto contatto con il metallo risiedono in C:
A. users — pulizia e iniezione (stile OpenEmbedded/Yocto)
Gestisce l'identità del sistema live operando direttamente sui 6 database di account dentro <live_root>/etc/ (passwd, shadow, group, gshadow, subuid, subgid) tramite la micro-libreria oa-yocto.c:
- Purge: a meno che la modalità non sia
cloneocrypted, tutti gli utenti umani dell'host (UID1000–59999, secondo le soglie OpenEmbedded-Core) vengono rimossi dai database della live, preservando gli account di sistema e garantendo il funzionamento out-of-the-box dei container rootless (subuid/subgid). - Inject: inietta nativamente l'utente live dichiarato nel piano (credenziali predefinite
live/evolution), con password cifrata SHA-512, gruppi primari/secondari e permessi della home popolata da/etc/skel.
B. umount — la discesa sicura (MNT_DETACH)
Smonta l'albero di lavoro in ordine rigoroso utilizzando la syscall umount2() con il flag MNT_DETACH (lazy unmount), impedendo qualsiasi blocco del kernel o dell'host su mount occupati:
- API filesystem dentro
liveroot(dev/pts,dev,proc,sys,run,tmp); - Overlay mount (
usr,var); - Bind mount standard (
opt,root,srv); - I
lowerdirdell'overlay dentro.overlay; - Infine
liverootstesso.
È la medesima routine invocata da sudo eggs destroy e dal comando oa cleanup.
🧬 4. Anatomia dei sorgenti (oa/src/)
| File | Ruolo |
|---|---|
src/main.c | Entry point CLI: legge il piano JSON, lo analizza con cJSON e guida il ciclo dei task. |
src/engine.c | Il dispatcher: instrada ogni task verso il C (run_native) o verso coa ell (fork + pipe). |
src/native.c | I moduli nativi: users (Purge & Inject) e umount (lazy teardown). |
src/oa-yocto.c | Micro-libreria a zero dipendenze per la manipolazione dei file di identità (passwd, shadow, group, gshadow, subuid, subgid). |
src/logger.c | Logger minimale su file (/var/log/penguins-eggs.log). |
src/cJSON.c | Parser JSON vendored — l'unica dipendenza di terze parti. |