Successivo: Funzioni Group, Precedente: Funzione getopt, Su: Funzioni di libreria [Contenuti][Indice]
Il vettore PROCINFO
(vedi la sezione Variabili predefinite)
dà accesso ai numeri ID reale ed effettivo dell’utente e del gruppo e, se
disponibili, alla serie di gruppi ulteriori a cui l’utente appartiene.
Comunque, poiché questi sono numeri, non forniscono informazioni molto utili per
l’utente medio. Bisogna trovare un modo per reperire informazioni
sull’utente associate con i numeri ID dell’utente e del gruppo. Questa
sezione illustra una raccolta di funzioni per ottenere le informazioni
dalla lista gli utenti. Vedi la sezione Leggere la lista dei gruppi per una raccolta di
funzioni simili per ottenere informazioni dalla lista dei gruppi.
Lo standard POSIX non definisce il file dove sono mantenute le informazioni
degli utenti. Invece, fornisce il file d’intestazione <pwd.h>
e diverse subroutine del linguaggio C per ottenere informazioni sugli
utenti. La funzione primaria è getpwent()
, che sta per “get password
entry”. La “password” proviene dal file originale della lista
degli utenti, /etc/passwd, che contiene le informazioni sugli utenti
assieme alle password criptate (da cui il nome).76
Sebbene un programma awk
possa semplicemente leggere
/etc/passwd direttamente, questo file può non contenere tutte le
informazioni su tutti gli utenti del sistema.77 Per
essere sicuri di poter produrre una versione leggibile e completa della banca
dati degli utenti, è necessario scrivere un piccolo programma in C che chiama
getpwent()
. getpwent()
viene definita in modo da restituire un
puntatore a una struct passwd
. Ogni volta che viene chiamata,
restituisce l’elemento successivo della lista. Quando non ci sono più
elementi, restituisce NULL
, il puntatore nullo. Quando accade ciò, il
programma C dovrebbe chiamare endpwent()
per chiudere la lista..
Quel che segue è pwcat
, un programma in C che “concatena” la
lista delle password:
/* * pwcat.c * * Genera una versione stampabile della lista delle password. */ #include <stdio.h> #include <pwd.h> int main(int argc, char **argv) { struct passwd *p; while ((p = getpwent()) != NULL) printf("%s:%s:%ld:%ld:%s:%s:%s\n", p->pw_name, p->pw_passwd, (long) p->pw_uid, (long) p->pw_gid, p->pw_gecos, p->pw_dir, p->pw_shell); endpwent(); return 0; }
Se non si conosce il linguaggio C, non è il caso di preoccuparsi.
L’output di pwcat
è la lista degli utenti, nel formato
tradizionale del file /etc/passwd con campi separati da due punti (:
).
I campi sono:
Il nome di login dell’utente.
La password criptata dell’utente. Può non essere disponibile su alcuni sistemi.
L’ID numerico dell’utente.
(Su alcuni sistemi, è un numero di formato long
[32bit]
del linguaggio C, e non nel formato int
[16bit].
Quindi, lo cambieremo in long
per sicurezza.)
L’ID di gruppo numerico dell’utente.
(Valgono le stesse considerazioni su long
al posto di int
.)
Il nome completo dell’utente, e talora altre informazioni associate all’utente.
La directory di login (o “home”) (nota ai programmatori di shell come
$HOME
).
Il programma che viene eseguito quando l’utente effettua l’accesso. Questo è comunemente una shell, come Bash.
Di seguito si riportano alcune righe di un possibile output di pwcat
:
$ pwcat -| root:x:0:1:Operator:/:/bin/sh -| nobody:x:65534:65534::/: -| daemon:x:1:1::/: -| sys:x:2:2::/:/bin/csh -| bin:x:3:3::/bin: -| arnold:x:2076:10:Arnold Robbins:/home/arnold:/bin/sh -| miriam:x:112:10:Miriam Robbins:/home/miriam:/bin/sh -| andy:x:113:10:Andy Jacobs:/home/andy:/bin/sh …
Dopo quest’introduzione, di seguito si riporta un gruppo di funzioni per ottenere informazioni sugli utenti. Ci sono diverse funzioni, che corrispondono alle omonime funzioni C:
# passwd.awk --- accedere alle informazioni del file delle password BEGIN { # modificare per adattarlo al sistema in uso _pw_awklib = "/usr/local/libexec/awk/" } function _pw_init( oldfs, oldrs, olddol0, pwcat, using_fw, using_fpat) { if (_pw_inizializzato) return oldfs = FS oldrs = RS olddol0 = $0 using_fw = (PROCINFO["FS"] == "FIELDWIDTHS") using_fpat = (PROCINFO["FS"] == "FPAT") FS = ":" RS = "\n" pwcat = _pw_awklib "pwcat" while ((pwcat | getline) > 0) { _pw_byname[$1] = $0 _pw_byuid[$3] = $0 _pw_bycount[++_pw_totale] = $0 } close(pwcat) _pw_contatore = 0 _pw_inizializzato = 1 FS = oldfs if (using_fw) FIELDWIDTHS = FIELDWIDTHS else if (using_fpat) FPAT = FPAT RS = oldrs $0 = olddol0 }
La regola BEGIN
imposta una variabile privata col nome
della directory in cui si
trova pwcat
.
Poiché è destinata a essere usata da una routine di
libreria di awk
, si è scelto di metterla in
/usr/local/libexec/awk; comunque, in un altro sistema potrebbe
essere messa in una directory differente.
La funzione _pw_init()
mette tre copie delle informazioni sull’utente in
tre vettori associativi. I vettori sono indicizzati per nome-utente
(_pw_byname
), per numero di ID-utente (_pw_byuid
), e per ordine di
occorrenza (_pw_bycount
).
La variabile _pw_inizializzato
è usata per
efficienza, poiché in questo modo _pw_init()
viene chiamata solo una volta.
Poiché questa funzione usa getline
per leggere informazioni da
pwcat
, dapprima salva i valori di FS
, RS
e $0
.
Annota nella variabile using_fw
se la suddivisione in campi
usando FIELDWIDTHS
è attiva o no.
Far questo è necessario, poiché queste funzioni potrebbero essere chiamate da
qualsiai parte all’interno di un programma dell’utente, e l’utente può
suddividere i record in campi a suo piacimento.
Ciò rende possibile ripristinare il corretto meccanismo di suddivisione dei
campi in un secondo momento. La verifica può restituire solo vero per
gawk
.
Il risultato può essere falso se si usa
FS
o FPAT
,
o in qualche altra implementazione di awk
.
Il codice che controlla se si sta usando FPAT
, utilizzando
using_fpat
e PROCINFO["FS"]
, è simile.
La parte principale della funzione usa un ciclo per leggere le righe della
lista, suddividere le righe in campi, e poi memorizzare la riga
all’interno di ogni vettore a seconda delle necessità. Quando il ciclo è
completato, _pw_init()
fa pulizia chiudendo la pipe,
impostando _pw_inizializzato
a uno, e ripristinando FS
(e FIELDWIDTHS
o FPAT
se necessario), RS
e $0
.
L’uso di _pw_contatore
verrà spiegato a breve.
La funzione getpwnam()
ha un nome utente come argomento di tipo
stringa. Se
quell’utente è presente nella lista, restituisce la riga appropriata.
Altrimenti, il riferimento a un elemento inesistente del vettore
aggiunge al vettore stesso un elemento il cui valore è la stringa nulla:
function getpwnam(nome) { _pw_init() return _pw_byname[nome] }
In modo simile, la funzione getpwuid()
ha per argomento
il numero ID di un utente.
Se un utente con quel numero si trova nella lista, restituisce la riga
appropriata. Altrimenti restituisce la stringa nulla:
function getpwuid(uid) { _pw_init() return _pw_byuid[uid] }
La funzione getpwent()
scorre semplicemnte la lista, un elemento
alla volta. Usa _pw_contatore
per tener traccia della posizione corrente
nel vettore _pw_bycount
:
function getpwent() { _pw_init() if (_pw_contatore < _pw_totale) return _pw_bycount[++_pw_contatore] return "" }
La funzione endpwent()
reimposta _pw_contatore
a zero,
in modo che chiamate successive a getpwent()
ricomincino da capo:
function endpwent() { _pw_contatore = 0 }
In questa serie di funzioni, il fatto che ogni subroutine chiami
_pw_init()
per inizializzare il vettore della lista utenti risponde a una precisa
scelta progettuale.
Il lavoro necessario per eseguire un processo separato che generi la
lista degli utenti, e l’I/O per esaminarla, si ha solo se il programma
principale dell’utente chiama effettivamente una di queste funzioni.
Se questo
file di libreria viene caricato assieme a un programma dell’utente, ma non
viene mai chiamata nessuna delle routine, non c’è nessun lavoro aggiuntivo
richiesto in fase di esecuzione.
(L’alternativa è quella di spostare il corpo di _pw_init()
all’interno di una regola BEGIN
, che esegua sempre pwcat
.
Questo semplifica il codice ma richiede di eseguire un processo extra
il cui risultato potrebbe non essere mai utilizzato dal programma.)
A sua volta, chiamare ripetutamente _pw_init()
non è troppo
dispendioso, perché la
variabile _pw_inizializzato
permette di evitare di leggere
i dati relativi agli utenti più di una
volta. Se la preoccupazione è quella di minimizzare il tempo di
esecuzione del programma awk
,
il controllo di _pw_inizializzato
potrebbe essere spostato
al di fuori di _pw_init()
e duplicato in tutte le altre funzioni.
In pratica, questo non è necessario, poiché la maggior parte dei
programmi di awk
è I/O-bound78,
e una tale modifica complicherebbe inutilmente il codice.
Il programma id
in Stampare informazioni sull’utente
usa queste funzioni.
Questo è
vero per le versioni più antiche di Unix. In quelle più recenti,
la password di ogni utente è stata trasferita nel file /etc/shadow,
un file non accessibile dall’utente normale. La struttura del file
/etc/passwd è rimasta la stessa, ma al posto del campo password
c’è una x
.
Capita spesso che le informazioni sulla password siano memorizzate in una lista in rete.
I programmi si distinguono tradizionalemente in CPU-bound e I/O-bound. Quelli CPU-bound effettuano elaborazioni che non richiedono molta attività di I/O, come ad esempio la preparazione di una tavola di numeri primi. Quelli I/O bound leggono dei file, ma richiedono poca attività di elaborazione per ogni record letto.
Successivo: Funzioni Group, Precedente: Funzione getopt, Su: Funzioni di libreria [Contenuti][Indice]