Successivo: Visitare vettori, Precedente: Funzioni Passwd, Su: Funzioni di libreria [Contenuti][Indice]
Molto di quel che è stato detto
in
Leggere la lista degli utenti
vale anche per la lista dei gruppi. Sebbene questa sia tradizionalmente
contenuta in
un file ben noto (/etc/group) in un altrettanto noto formato,
lo standard
POSIX prevede solo una serie di routine della libreria C
(<grp.h>
e getgrent()
)
per accedere a tali informazioni.
Anche se il file suddetto è disponibile, potrebbe non contenere delle
informazioni
complete. Perciò, come per la lista degli utenti, è necessario avere un
piccolo programma in C che genera la lista dei gruppi come suo output.
grcat
, un programma in C che fornisce la lista dei gruppi,
è il seguente:
/* * grcat.c * * Genera una versione stampabile della lista dei gruppi. */ #include <stdio.h> #include <grp.h> int main(int argc, char **argv) { struct group *g; int i; while ((g = getgrent()) != NULL) { printf("%s:%s:%ld:", g->gr_name, g->gr_passwd, (long) g->gr_gid); for (i = 0; g->gr_mem[i] != NULL; i++) { printf("%s", g->gr_mem[i]);
if (g->gr_mem[i+1] != NULL) putchar(','); }
putchar('\n'); } endgrent(); return 0; }
Ciascuna riga nella lista dei gruppi rappresenta un gruppo. I campi sono
separati da due punti (:
) e rappresentano le seguenti informazioni:
Il nome del gruppo.
La password del gruppo criptata. In pratica, questo campo non viene mai usato; normalmente è vuoto o impostato a ‘x’.
Il numero ID del gruppo in formato numerico;
l’associazione del nome al numero dev’essere univoca all’interno di questo file.
(Su alcuni sistemi, è un numero nel formato long
[32bit]
del linguaggio C, e non nel formato int
[16bit].
Quindi, lo cambieremo in long
per sicurezza.)
Una lista di nomi utente separati da virgole.
Questi utenti sono i membri del gruppo.
I sistemi Unix moderni consentono agli utenti di appartenere a
diversi gruppi simultaneamente. Se il sistema in uso è uno di questi, ci sono
elementi in PROCINFO
che vanno da "group1"
fino a
"groupN"
per quei numeri di ID di gruppo.
(Si noti che PROCINFO
è un’estensione gawk
;
vedi la sezione Variabili predefinite.)
Di seguito si riporta quel che grcat
potrebbe produrre:
$ grcat -| wheel:x:0:arnold -| nogroup:x:65534: -| daemon:x:1: -| kmem:x:2: -| staff:x:10:arnold,miriam,andy -| other:x:20: …
Qui ci sono le funzioni per ottenere informazioni relative alla lista dei gruppi. Ce ne sono diverse, costruite sul modello delle omonime funzioni della libreria C:
# group.awk --- funzioni per il trattamento del file dei gruppi BEGIN { # Modificare in base alla struttura del proprio sistema _gr_awklib = "/usr/local/libexec/awk/" } function _gr_init( oldfs, oldrs, olddol0, grcat, using_fw, using_fpat, n, a, i) { if (_gr_inizializzato) return oldfs = FS oldrs = RS olddol0 = $0 using_fw = (PROCINFO["FS"] == "FIELDWIDTHS") using_fpat = (PROCINFO["FS"] == "FPAT") FS = ":" RS = "\n" grcat = _gr_awklib "grcat" while ((grcat | getline) > 0) { if ($1 in _gr_byname) _gr_byname[$1] = _gr_byname[$1] "," $4 else _gr_byname[$1] = $0 if ($3 in _gr_bygid) _gr_bygid[$3] = _gr_bygid[$3] "," $4 else _gr_bygid[$3] = $0 n = split($4, a, "[ \t]*,[ \t]*") for (i = 1; i <= n; i++) if (a[i] in _gr_groupsbyuser) _gr_groupsbyuser[a[i]] = _gr_groupsbyuser[a[i]] " " $1 else _gr_groupsbyuser[a[i]] = $1 _gr_bycount[++_gr_contatore] = $0 } close(grcat) _gr_contatore = 0 _gr_inizializzato++ FS = oldfs if (using_fw) FIELDWIDTHS = FIELDWIDTHS else if (using_fpat) FPAT = FPAT RS = oldrs $0 = olddol0 }
La regola BEGIN
imposta una variabile privata con il nome della
directory in cui si trova grcat
.
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.
Queste routine seguono le stesse linee generali delle routine per formare la
lista degli utenti (vedi la sezione Leggere la lista degli utenti).
La variabile _gr_inizializzato
è usata per
essere sicuri che la lista venga letta una volta sola.
La funzione _gr_init()
dapprima salva FS
,
RS
e
$0
, e poi imposta FS
e RS
ai valori da usare nel
passare in rassegna le informazioni di gruppo. Inoltre
viene annotato se si stanno usando FIELDWIDTHS
o FPAT
, per
poter poi
ripristinare il meccanismo di suddivisione in campi appropriato.
Le informazioni sui gruppi sono memorizzate in diversi vettori associativi.
I vettori sono indicizzati per nome di gruppo (_gr_byname
), per
numero ID del gruppo (_gr_bygid
), e per posizione nella lista
(_gr_bycount
). C’è un vettore aggiuntivo indicizzato per nome utente
(_gr_groupsbyuser
), che è una lista, separata da spazi, dei
gruppi ai quali ciascun utente appartiene.
Diversamente dalla lista degli utenti, è possibile avere più record nella lista per lo stesso gruppo. Questo è frequente quando un gruppo ha un gran numero di membri. Un paio di tali voci potrebbero essere come queste:
tvpeople:x:101:johnny,jay,arsenio tvpeople:x:101:david,conan,tom,joan
Per questo motivo, _gr_init()
controlla se un nome di gruppo o un numero
di ID di gruppo è stato già visto. Se così fosse, i nomi utente vanno
semplicemente concatenati con la precedente lista di utenti.79
Infine, _gr_init()
chiude la pipe a grcat
, ripristina
FS
(e FIELDWIDTHS
o FPAT
, se necessario), RS
e
$0
, inizializza _gr_contatore
a zero
(per essere usato più tardi), e rende _gr_inizializzato
diverso da zero.
La funzione getgrnam()
ha come argomento un nome di gruppo, e se quel
gruppo esiste, viene restituito.
Altrimenti, il riferimento a un elemento inesistente del vettore aggiunge al vettore stesso un elemento il cui valore è la stringa nulla:
function getgrnam(group) { _gr_init() return _gr_byname[group] }
La funzione getgrgid()
è simile; ha come argomento un numero ID di
gruppo e controlla le informazioni assiciate con quell’ID di gruppo:
function getgrgid(gid) { _gr_init() return _gr_bygid[gid] }
La funzione getgruser()
non ha un equivalente in C. Ha come argomento un
nome-utente e restituisce l’elenco dei gruppi di cui l’utente è membro:
function getgruser(user) { _gr_init() return _gr_groupsbyuser[user] }
La funzione getgrent()
scorre la lista un elemento alla volta.
Usa _gr_contatore
per ricordare la posizione corrente nella lista:
function getgrent() { _gr_init() if (++_gr_contatore in _gr_bycount) return _gr_bycount[_gr_contatore]
return "" }
La funzione endgrent()
reimposta _gr_contatore
a zero in modo che
getgrent()
possa ricominciare da capo:
function endgrent() { _gr_contatore = 0 }
Come con le routine per la lista degli utenti, ogni funzione chiama
_gr_init()
per inizializzare i vettori.
Così facendo si avrà il solo
lavoro aggiuntivo di eseguire grcat
se queste funzioni vengono
usate (rispetto a spostare il corpo di _gr_init()
all’interno della
regola BEGIN
).
La maggior parte del lavoro consiste nell’ispezionare la lista e nel
costruire i vari vettori associativi. Le funzioni che l’utente chiama sono
di per sé molto semplici, poiché si appoggiano sui vettori associativi di
awk
per fare il lavoro.
Il programma id
in Stampare informazioni sull’utente
usa queste funzioni.
C’è un
piccolo problema col codice appena illustrato. Supponiamo che la prima volta
non ci siano nomi. Questo codice aggiunge i nomi con una virgola iniziale.
Inoltre non controlla che ci sia un $4
.
Successivo: Visitare vettori, Precedente: Funzioni Passwd, Su: Funzioni di libreria [Contenuti][Indice]