Successivo: , Precedente: , Su: Funzioni di libreria   [Contenuti][Indice]


10.6 Leggere la lista dei gruppi

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:

Nome del gruppo

Il nome del gruppo.

Password del gruppo

La password del gruppo criptata. In pratica, questo campo non viene mai usato; normalmente è vuoto o impostato a ‘x’.

Numero ID del gruppo

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.)

Lista dei membri del gruppo

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.


Note a piè di pagina

(79)

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: , Precedente: , Su: Funzioni di libreria   [Contenuti][Indice]