leggi-passwd.c
Transcript
leggi-passwd.c
leggi-passwd.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 25/11/2015 #include <stdio.h> #include <string.h> #include <assert.h> #define SIZE 100 /* dimensione dei buffer di lettura */ #define DIM 100 /* dimensione del vettore nomi */ int main(int argc, char **argv) { FILE *fin = fopen(argv[1], "r"); FILE *fout = argc<3 ? stdout : fopen(argv[2], "w"); /* * assert termina il programma se il test non è vero * con un messaggio del tipo % ./leggi-passwd file-che-non-esiste assertion "fin && fout" failed: file "leggi-passwd.c", line 23 * serve per il debugging non per l'utente finale * se definisco la macro NDEBUG il compilatore non considera * assert(...) */ assert(fin && fout); /* richiede assert.h */ 1 leggi-passwd.c 25/11/2015 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #if 0 45 nelle versioni recenti di Unix la password non viene memorizzata ( in questo file) nelle vecchie era presente ma crittograta (qualcosa come $1$ oTc1DHLi$m4cqP7MVPu2Plrw/6Ov.v/) #endif 43 44 46 /* * si noti che SIZE e DIM pur assumendo lo stesso valore * sono logicamente indipendenti */ char nome[SIZE], passwd[SIZE], dir[SIZE], shell[SIZE]; /* buffer mi serve per leggere una riga intera */ char buffer[1000]; char *nomi[DIM]; esempio di file /etc/passwd: root:x:0:0:root:/root:/bin/bash bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh kermit:x:1000:1000:Kermit the Frog,,,:/home/kermit:/bin/bash nome utente:password:identificativo utente:identificativo gruppo: descrizione:directory di lavoro:shell utilizzata 2 leggi-passwd.c 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 25/11/2015 /* * legge al massimo DIM righe oppure fino al termine del file * fgets restituisce NULL se si incontra EOF (end of file) */ int n; for(n=0; n<DIM && fgets(buffer, sizeof(buffer), fin); n++) { /* * %[^:]: legge una stringa costituita da un qualunque carattere * escluso ':' poi viene letto necessariamente il carattere ':' * * %*d l'asterisco indica che viene letto un dato * (in questo caso un intero) ma non memorizzato */ int id; /* è usata solo nel ciclo */ if(sscanf(buffer, "%[^:]:%[^:]:%d:%*d:%*[^:]:%[^:]:%s", nome, passwd, &id, dir, shell) != 5) { fprintf(stderr,"Errore nella riga %d\n%s\n",n+1,buffer); } fprintf(fout, "%s %s %d %s %s\n", nome, passwd, id, dir, shell); nomi[n] = nome; } 3 leggi-passwd.c 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 25/11/2015 #if __STDC_VERSION__ < 199901L int i; for(i=0; i<n; i++) { printf("%2i %s\n", i+1, nomi[i]);// %i è equivalente a %d } #else for(int i=0; i<n; i++) { sprintf(buffer, "%2i %s.\n", i+1, nomi[i]); fputs(buffer, stdout); } #endif return 0; } #if 0 in analogia a sscanf esiste anche sprintf (scrive in un buffer di caratteri - cioè crea una stringa) si può sostituire la riga 72 con: sprintf(buffer, "%2i %s\n", i+1, nomi[i]); fputs(buffer, stdout); lo standard C99 ammette la definizione di variabili in un ciclo for vedi riga 75 (compilare con l'opzione -std=c99) #endif 4 leggi-passwd.c 94 95 96 97 98 99 100 101 102 103 25/11/2015 /* * nomi[n] = nome; * va corretto in: * nomi[n] = strdup(nome); * * char* strdup(char *s) (duplica stringa - richiede string.h) fa * una copia della stringa in una nuova locazione di memoria il cui * indirizzo viene restiuito come risultato della funzione */ 5