Il file di configurazione è a tutti gli effetti uno shell script di per sé stesso, che viene "incluso" dallo script principale con il comando "
source". Cosa che
è perfettamente equivalente a copiare il contenuto del file di configurazione direttamente all'interno dell'Init script. Ovvio che se introduci un errore di sintassi (della shell) ottieni risultati imprevisti (ed imprevedibili).
Questo non è nulla di "strano" o di specifico per il caso di squeezelite: è
il metodo standard con cui vengono gestiti quel tipo di files di configurazione, ed è adottato pressoché universalmente da tutti i servizi che ne hanno bisogno.
Se c'è un errore grossolano nel file di configurazione... è un problema dell'amministratore di sistema, non dello script: “chi è causa del suo mal, pianga se stesso”.
È parte integrante della
filosofia stessa di Unix: il sistema presuppone che l'utente, ed ancor più l'amministratore di sistema, sappia sempre esattamente ciò che fa ed agisca quindi con prudenza, attenzione e cognizione di causa. Non è previsto che il sistema faccia nulla che possa limitarne la libertà di azione o imporre vincoli o controlli superflui. Neanche per tentare di impedirgli di fare stupidaggini!
Ad es., in una riga di quel file "di configurazione" potresti anche scriverci "rm -rf /" e quel comando verrebbe eseguito senza battere ciglio. Con i privilegi di root. Azzerando in un sol colpo l'intero sistema e quant'altro conteneva!
Potresti pensare che ciò sia stupido, ma non lo è affatto. Tutt'altro. Perché ti offre la massima libertà di azione, permettendoti di fare qualsiasi cosa tu abbia necessità di fare. Incluso cose nuove e completamente diverse da quelle previste o immaginate in precedenza. Cosa che potrebbe risultare molto più difficile se non impossibile fare se tutto fosse già stato preordinato e vincolato secondo quanto previsto da chi ha creato il sistema (o un particolare pezzo del sistema).
Per dire, anziché limitarsi ad introdurre una banale configurazione "statica", definendo a priori le variabili previste, in quel "file di configurazione" potresti anche metterci invece tutto il codice necessario per identificare la scheda audio e quant'altro necessario e definire tali variabili automaticamente, in modo dinamico (ad es. banalmente per cambiare automaticamente configurazione se è collegato il dispositivo X piuttosto che quello Y). Oppure eseguire particolari operazioni preliminari, ad es. inizializzare o caricare il firmware di un dispositivo audio che non verrebbe gestito diversamente, ecc. Qualunque cosa tu voglia che sia eseguito ogni qual volta viene chiamato quel particolare Init script. Non ci sono limiti a ciò che puoi fare.
Il tutto senza la benché minima modifica al setup standard, quindi senza avere problemi in caso di aggiornamento di quel pacchetto (o dell'intero sistema), ecc.
non è che "lo considera nullo": se c'è un errore di sintassi (di shell) nella definizione della variabile è proprio quella variabile che viene definita "male" o non viene definita affatto. In generale lo script "chiamante" non ha modo di sapere se c'è un errore.
L'unica cosa che si potrebbe fare è cercare di "intercettare" eventuali errori grossolani dicendo alla shell di reagire in qualche modo se un qualsiasi comando (all'interno del file di configurazione) ritorna un exit status diverso da zero.
Ad es. si potrebbe aggiungere "set -e" subito prima di fare il source del file di configurazione (e poi disabilitare nuovamente tale opzione con "set +e" subito dopo). In questo modo in caso di errori lo script esce immediatamente ed il servizio non viene avviato.
Per azioni "più complicate" (come far scrivere un messaggio di errore) si potrebbe invece fare qualcosa del genere:
codice:
# this will trap any errors or commands with non-zero exit status by calling function catch_errors()
trap catch_errors ERR;
#
# ... do something
#
function catch_errors() {
#
# do whatever on errors ...
#
echo "script aborted, because of errors";
exit 1;
}
Ma non basterebbe. In qualche caso potrebbe anche capitare che l'errore sintattico sia tale per cui la shell non rileva alcun errore e la variabile viene effettivamente definita, ma è "vuota". Ad es., poni che nel file di configurazione ci sia scritto qualcosa del genere:
codice:
SB_EXTRA_ARGS= #"-h -C 1 -a 100:3:$bit_depth:1 -b 65536:65536 -r $ratesRange -u vIE:32::64:98"
c'è più di un errore evidente, ma per la shell va tutto bene: dal suo punto di vista si tratta di una sequenza di DUE cose distinte: la dichiarazione della variabile $SL_SOUNDCARD (cui è assegnato un valore
nullo, "empty string") seguita da un commento. Cosa perfettamente lecita. Ergo nessun errore rilevato, e variabile definita (ma vuota). Squeezelite verrebbe avviato senza alcun parametro aggiuntivo anche in presenza dei check di cui sopra.
Dici tu: OK, basta aggiungere un altro check: non limitiamoci a verificare che la variabile sia definita, ma controlliamo anche che "non sia vuota". Sorvoliamo sul fatto che questo (così come il resto...) violerebbe tutte le convenzioni e vediamo cosa succederebbe in un caso appena diverso, questo:
codice:
SB_EXTRA_ARGS=#"-h -C 1 -a 100:3:$bit_depth:1 -b 65536:65536 -r $ratesRange -u vIE:32::64:98"
notato la differenza? è uguale a prima, solo che adesso non c'è nessuno spazio tra '=' e '#'. Anche in questo caso, per la shell va tutto bene: non ci sono errori, e la variabile viene definita. Con quale valore? Ovviamente, questo:
codice:
#-h -C 1 -a 200:6::1 -b 65536:65536 -r -u vIE:32::64:98
ora questa variabile verrà utilizzata per costruire la riga di comando di squeezelite, che sarà qualcosa del genere:
codice:
/usr/bin/squeezelite [altre_opzioni] #-h -C 1 -a 200:6::1 -b 65536:65536 -r -u vIE:32::64:98
e cosa succede quando viene eseguita? ovviamente, che tutto ciò che segue '#' viene considerato un commento e quindi ignorato (ed ancora una volta SL verrebbe avviato ugualmente, senza opzioni e senza errori).
In definitiva avremmo aggiunto un bel po' di complicazioni e di codice superfluo, deviato dalle convenzioni, introdotto innumerevoli limitazioni e vincoli non necessari a ciò che si può fare nel file "di configurazione" e, nonostante tutto, siamo ancora punto e a capo: non abbiamo risolto il (tuo) problema.
D'altro canto, nulla di nuovo sotto al sole. Idiot proof systems cannot be made: Nothing is foolproof to a sufficiently talented fool.
Per giunta, mai dimenticare il principio di Shaw: “Build a system that even a fool can use, and only a fool will want to use it”.
Qual è allora la soluzione?
KISS. Lasciare che le cose siano semplici! Non cercare di "riparare" ciò che non è rotto. Non cambiare ciò che è stato fatto e funziona bene fin dal 1970 o giù di lì. Imparare invece a seguire le regole del gioco.
Fare sempre
una sola modifica alla volta. Prestare attenzione a ciò che si fa. Verificare ciò che si è fatto. Se ciò nonostante si ottiene un risultato diverso da quello atteso, dare per scontato che abbiamo commesso un errore. Il sistema ha sempre ragione: noi sbagliamo, lui no. Se abbiamo seguito la prima regola e quindi modificato una sola cosa, sappiamo già esattamente dove guardare per trovarlo.
ad essere eseguito da un utente diverso è solo il processo di squeezelite avviato dall'Init script. Ma l'Init script stesso devi sempre (ed anzi a maggior ragione) eseguirlo come root!
Comunque, come detto questa è una cosa che ho in mente di fare per una prossima versione dei pacchetti (ma non è così banale: non basta aggiungere due righe all'Init script, bisogna anche prevedere la creazione/eliminazione dell'utente quando si installa/rimuove il pacchetto, gestire i permessi di files e directories coninvolte, ecc... altrimenti lo avrei fatto fin dal principio).
Per giunta, l'init script semplificato indicato in quel post non prevede l'uso di un file di configurazione "esterno": per cambiare la configurazione dovresti modificare direttamente lo script stesso! Il che significa che, se aggiorni il pacchetto (installi una versione aggiornata), l'Init script viene sovrascritto e ti perdi la configurazione. Per chi eventualmente usi "falcon" forse potrebbe anche essere un problema minore, ma per tutti gli altri è -come minimo- una bella seccatura.
fare il "boot da ram" mi pare cosa alquanto improbabile...
...magari volevi dire "caricare l'intero sistema in ram" e lavorare lì, senza accedere ai dischi.
Cosa che senza dubbio si può fare, sia partendo da un file-system (o una "immagine") su un disco locale che facendo il boot da rete (sistema "diskless", completamente privo di memoria di massa locale). Di soluzioni del genere ce ne sono già a bizzeffe; per non dover reinventare la ruota basta seguire le orme di chi lo ha già fatto...
Vedi ad es. il link che avevo postato tempo addietro (in altro topic, mi pare), dove si parla di un modo per includere un intero sistema all'interno del "
Init RAM disk" del kernel.
per fare questo non è necessario evitare lo shutdown del sistema e spegnere brutalmente tutto. Basta "rivoltare" il problema, utilizzando il pulsante di accensione/spegnimento del sistema e le relative linee di controllo sulla M/B per comandare l'alimentazione generale. Come in un comune PC ben configurato: quando pigi il bottone si accende tutto, quando lo pigi di nuovo parte lo shutdown. Che alla fine spegne tutto.