[Avanti]  [Indietro]  [Su]  

10.1.5 Prescrizioni per un programma daemon

Come sottolineato fin da sez. 1.1.1, in un sistema unix-like tutte le operazioni sono eseguite tramite processi, comprese quelle operazioni di sistema (come l'esecuzione dei comandi periodici, o la consegna della posta, ed in generale tutti i programmi di servizio) che non hanno niente a che fare con la gestione diretta dei comandi dell'utente.

Questi programmi, che devono essere eseguiti in modalità non interattiva e senza nessun intervento dell'utente, sono normalmente chiamati demoni, (o daemons), nome ispirato dagli omonimi spiritelli che svolgevano compiti vari, di cui parlava Socrate (che sosteneva di averne uno al suo servizio).21

Se però si lancia un programma demone dalla riga di comando in un sistema che supporta, come Linux, il job control esso verrà comunque associato ad un terminale di controllo e mantenuto all'interno di una sessione, e anche se può essere mandato in background e non eseguire più nessun I/O su terminale, si avranno comunque tutte le conseguenze che abbiamo appena visto in sez. 10.1.3 (in particolare l'invio dei segnali in corrispondenza dell'uscita del leader di sessione).

Per questo motivo un programma che deve funzionare come demone deve sempre prendere autonomamente i provvedimenti opportuni (come distaccarsi dal terminale e dalla sessione) ad impedire eventuali interferenze da parte del sistema del job control; questi sono riassunti in una lista di prescrizioni22 da seguire quando si scrive un demone.

Pertanto, quando si lancia un programma che deve essere eseguito come demone occorrerà predisporlo in modo che esso compia le seguenti azioni:

  1. Eseguire una fork e terminare immediatamente il processo padre proseguendo l'esecuzione nel figlio. In questo modo si ha la certezza che il figlio non è un process group leader, (avrà il pgid del padre, ma un pid diverso) e si può chiamare setsid con successo. Inoltre la shell considererà terminato il comando all'uscita del padre.
  2. Eseguire setsid per creare una nuova sessione ed un nuovo raggruppamento di cui il processo diventa automaticamente il leader, che però non ha associato nessun terminale di controllo.
  3. Assicurarsi che al processo non venga associato in seguito nessun nuovo terminale di controllo; questo può essere fatto sia avendo cura di usare sempre l'opzione O_NOCTTY nell'aprire i file di terminale, che eseguendo una ulteriore fork uscendo nel padre e proseguendo nel figlio. In questo caso, non essendo più quest'ultimo un leader di sessione non potrà ottenere automaticamente un terminale di controllo.
  4. Eseguire una chdir per impostare la directory di lavoro del processo (su / o su una directory che contenga dei file necessari per il programma), per evitare che la directory da cui si è lanciato il processo resti in uso e non sia possibile rimuoverla o smontare il filesystem che la contiene.
  5. Impostare la maschera dei permessi (di solito con umask(0)) in modo da non essere dipendenti dal valore ereditato da chi ha lanciato originariamente il processo.
  6. Chiudere tutti i file aperti che non servono più (in generale tutti); in particolare vanno chiusi i file standard che di norma sono ancora associati al terminale (un'altra opzione è quella di redirigerli verso /dev/null).

In Linux buona parte di queste azioni possono venire eseguite invocando la funzione daemon, introdotta per la prima volta in BSD4.4; il suo prototipo è:

La funzione restituisce (nel nuovo processo) 0 in caso di successo, e -1 in caso di errore, nel qual caso errno assumerà i valori impostati dalle sottostanti fork e setsid.

La funzione esegue una fork, per uscire subito, con _exit, nel padre, mentre l'esecuzione prosegue nel figlio che esegue subito una setsid. In questo modo si compiono automaticamente i passi 1 e 2 della precedente lista. Se nochdir è nullo la funzione imposta anche la directory di lavoro su /, se noclose è nullo i file standard vengono rediretti su /dev/null (corrispondenti ai passi 4 e 6); in caso di valori non nulli non viene eseguita nessuna altra azione.

Dato che un programma demone non può più accedere al terminale, si pone il problema di come fare per la notifica di eventuali errori, non potendosi più utilizzare lo standard error; per il normale I/O infatti ciascun demone avrà le sue modalità di interazione col sistema e gli utenti a seconda dei compiti e delle funzionalità che sono previste; ma gli errori devono normalmente essere notificati all'amministratore del sistema.

Una soluzione può essere quella di scrivere gli eventuali messaggi su uno specifico file (cosa che a volte viene fatta comunque) ma questo comporta il grande svantaggio che l'amministratore dovrà tenere sotto controllo un file diverso per ciascun demone, e che possono anche generarsi conflitti di nomi. Per questo in BSD4.2 venne introdotto un servizio di sistema, il syslog, che oggi si trova su tutti i sistemi Unix, e che permettesse ai demoni di inviare messaggi all'amministratore in una maniera standardizzata.

Il servizio prevede vari meccanismi di notifica, e, come ogni altro servizio in un sistema unix-like, viene gestito attraverso un apposito programma, syslogd, che è anch'esso un demone. In generale i messaggi di errore vengono raccolti dal file speciale /dev/log, un socket locale (vedi sez. 14.3.4) dedicato a questo scopo, o via rete, con un socket UDP, o da un apposito demone, klogd, che estrae i messaggi del kernel.23

Il servizio permette poi di trattare i vari messaggi classificandoli attraverso due indici; il primo, chiamato facility, suddivide in diverse categorie i vari demoni in modo di raggruppare i messaggi provenienti da operazioni che hanno attinenza fra loro, ed è organizzato in sottosistemi (kernel, posta elettronica, demoni di stampa, ecc.). Il secondo, chiamato priority, identifica l'importanza dei vari messaggi, e permette di classificarli e differenziare le modalità di notifica degli stessi.

Il sistema di syslog attraverso syslogd provvede poi a riportare i messaggi all'amministratore attraverso una serie differenti meccanismi come:

secondo le modalità che questo preferisce e che possono essere impostate attraverso il file di configurazione /etc/syslog.conf (maggiori dettagli si possono trovare sulle pagine di manuale per questo file e per syslogd).

Le glibc definiscono una serie di funzioni standard con cui un processo può accedere in maniera generica al servizio di syslog, che però funzionano solo localmente; se si vogliono inviare i messaggi ad un'altro sistema occorre farlo esplicitamente con un socket UDP, o utilizzare le capacità di reinvio del servizio.

La prima funzione definita dall'interfaccia è openlog, che apre una connessione al servizio di syslog; essa in generale non è necessaria per l'uso del servizio, ma permette di impostare alcuni valori che controllano gli effetti delle chiamate successive; il suo prototipo è:

La funzione non restituisce nulla.

La funzione permette di specificare, tramite ident, l'identità di chi ha inviato il messaggio (di norma si passa il nome del programma, come specificato da argv[0]); la stringa verrà preposta all'inizio di ogni messaggio. Si tenga presente che il valore di ident che si passa alla funzione è un puntatore, se la stringa cui punta viene cambiata lo sarà pure nei successivi messaggi, e se viene cancellata i risultati potranno essere impredicibili, per questo è sempre opportuno usare una stringa costante.

L'argomento facility permette invece di preimpostare per le successive chiamate l'omonimo indice che classifica la categoria del messaggio. L'argomento è interpretato come una maschera binaria, e pertanto è possibile inviare i messaggi su più categorie alla volta; i valori delle costanti che identificano ciascuna categoria sono riportati in tab. 10.1, il valore di facility deve essere specificato con un OR aritmetico.




Valore Significato




LOG_AUTH Messaggi relativi ad autenticazione e sicurezza, obsoleto, è sostituito da LOG_AUTHPRIV.
LOG_AUTHPRIV Sostituisce LOG_AUTH.
LOG_CRON Messaggi dei demoni di gestione dei comandi programmati (cron e at).
LOG_DAEMON Demoni di sistema.
LOG_FTP Server FTP.
LOG_KERN Messaggi del kernel
LOG_LOCAL0 Riservato all'amministratore per uso locale
LOG_LOCAL7 Riservato all'amministratore per uso locale
LOG_LPR Messaggi del sistema di gestione delle stampanti
LOG_MAIL Messaggi del sistema di posta elettronica
LOG_NEWS Messaggi del sistema di gestione delle news (USENET)
LOG_SYSLOG Messaggi generati dallo stesso syslogd
LOG_USER Messaggi generici a livello utente
LOG_UUCP Messaggi del sistema UUCP



Tabella 10.1: Valori possibili per l'argomento facility di openlog.

L'argomento option serve invece per controllare il comportamento della funzione openlog e delle modalità con cui le successive chiamate scriveranno i messaggi, esso viene specificato come maschera binaria composta con un OR aritmetico di una qualunque delle costanti riportate in tab. 10.2.


Valore Significato




LOG_CONS Scrive sulla console quando.
LOG_NDELAY Sostituisce LOG_AUTH.
LOG_NOWAIT Messaggi dei demoni di gestione dei comandi programmati (cron e at).
LOG_ODELAY .
LOG_PERROR Stampa anche su stderr.
LOG_PID Inserisce nei messaggi il pid del processo chiamante.



Tabella 10.2: Valori possibili per l'argomento option di openlog.

La funzione che si usa per generare un messaggio è syslog, dato che l'uso di openlog è opzionale, sarà quest'ultima a provvede a chiamare la prima qualora ciò non sia stato fatto (nel qual caso il valore di ident è nullo). Il suo prototipo è:

La funzione non restituisce nulla.

Il comportamento della funzione è analogo quello di printf, e il valore dell'argomento format è identico a quello descritto nella pagina di manuale di quest'ultima (per i valori principali si può vedere la trattazione sommaria che se ne è fatto in sez. 7.2.6); l'unica differenza è che la sequenza %m viene rimpiazzata dalla stringa restituita da strerror(errno). Gli argomenti seguenti i primi due devono essere forniti secondo quanto richiesto da format.

L'argomento priority permette di impostare sia la facility che la priority del messaggio. In realtà viene prevalentemente usato per specificare solo quest'ultima in quanto la prima viene di norma preimpostata con openlog. La priorità è indicata con un valore numerico24 specificabile attraverso le costanti riportate in tab. 10.3. Nel caso si voglia specificare anche la facility basta eseguire un OR aritmetico del valore della priorità con la maschera binaria delle costanti di tab. 10.1.




Valore Significato




LOG_EMERG Il sistema è inutilizzabile.
LOG_ALERT C'è una emergenza che richiede intervento immediato.
LOG_CRIT Si è in una condizione critica.
LOG_ERR Si è in una condizione di errore.
LOG_WARNING Messaggio di avvertimento.
LOG_NOTICE Notizia significativa relativa al comportamento.
LOG_INFO Messaggio informativo.
LOG_DEBUG Messaggio di debug.



Tabella 10.3: Valori possibili per l'indice di importanza del messaggio da specificare nell'argomento priority di syslog.

Una ulteriore funzione, setlogmask, permette di filtrare preliminarmente i messaggi in base alla loro priorità; il suo prototipo è:

La funzione restituisce il precedente valore.

Le routine di gestione mantengono per ogni processo una maschera che determina quale delle chiamate effettuate a syslog verrà effettivamente registrata. La registrazione viene disabilitata per tutte quelle priorità che non rientrano nella maschera; questa viene settata usando la macro LOG_MASK(p) dove p è una delle costanti di tab. 10.3. É inoltre disponibile anche la macro LOG_UPTO(p) che permette di specificare automaticamente tutte le priorità fino ad un certo valore.


[Avanti]  [Indietro]  [Su]  
© 2000-2003 Simone Piccardi
Pubblicazione web curata da Mirko Maischberger