1 Chiamate di sistema Introduzione Errori : perror() Chiamate che lavorano su file
2 Chiamate di sistema Sappiamo bene cosa sono …. Dal C è possibile invocare le chiamate di sistema POSIX utilizzando la libreria standard –header vari da includere : unistd.h, sys/types.h, sys/wait.h etc... Queste informazioni tipicamente si ricavano dai manuali in linea –es. man 2 fork
3 Manuali in linea... Tipico formato : NAME perror - print a system error msg SYNOPSIS include,prototipi, globali DESCRIPTION descrizione a parole CONFORMING TO standard... SEE ALSO funzioni collegate
4 Manuali in linea …(2) Ci sono 3 sezioni : –1 (default) le utility chiamabili da shell –2 le system call –3 le funzioni di libreria standard C Ci sono utility che hanno lo stesso nome delle funzioni nelle sezioni 2/3, –specificare la sezione per avere l’informazione corretta Se non funzionano: –controllare il valore della variabile di ambiente MANPATH
5 UNIX: struttura generale Utenti Programmi di utilità standard (shell, editori, compilatori etc.) Libreria standard (Open, close, read, write …) Sistema operativo Unix (gestione processi, memoria, file system, I/0..) Hardware Modo utente Interfaccia di libreria C Interfaccia delle chiamate di sistema Modo kernel
6 Chiamate di sistema: errori Le chiamate di sistema possono fallire –in caso di fallimento ritornano un valore diverso da 0 (tipicamente -1) –il codice relativo all’errore rilevato è inserito nella variabile globale errno ( errno.h ) –i codici di errore sono definiti in vari file di include –perror() routine della libreria standard che stampa i messaggi di errore relativi a diversi codici ( stdio.h )
7 Chiamate di sistema: errori (2) Esempi di codici di errore /* no such file or directory*/ #define ENOENT 2 /* I/O error*/ #define EIO 5 /* Operation not permitted */ #define EPERM 1
8 Chiamate di sistema: errori (3) Come funziona perror(“pippo”) –legge il codice di errore contenuto nella globale errno – stampa “pippo” seguito da “:” seguito dal messaggio di errore relativo al codice –uso tipico : perror(“fun, descr”) dove fun è il nome della funzione che ha rilevato l’errore, descr descrive cosa stiamo tentando di fare –la stampa viene effettuata sullo standard error del processo in esecuzione (tipic. schermo)
9 Chiamate di sistema: errori (4) Es. int main (void) { errno = 1; /* EPERM */ perror(“main, provaerr”); return 0; } Compilato ed eseguito ….. $ a.out main, provaerr : Operation not permitted $
10 Chiamate di sistema: errori (5) Errno viene sovrascritto dalla SC successiva (se erronea) Il programma deve controllare l’esito di ogni SC immediatamente dopo il ritorno ed agire L’azione minima è chiamare la perror() per stampare un messaggio di errore Nel corso utilizzeremo delle macro con parametri che inseriscono test e perror() ad ogni chiamata
11 In sysmacro.h /* stampa errore e termina */ #define IFERROR(s,m) \ if((s)==-1) {perror(m); exit(errno);} /* stampa errore ed esegue c */ #define IFERROR3(s,m,c) \ if((s)==-1) {perror(m); c;}
12 In sysmacro.h (2) #define IFERROR(s,m) \ if((s)==-1) {perror(m); exit(errno);} #define IFERROR3(s,m,c) \ if((s)==-1) {perror(m); c;} /* uso tipico */ int main (void) { IFERROR(read(…),”main, des”, return -1); IFERROR(read(…),”main, des”); }
13 SC che operano su file (1) open(), read(), write(), close()
14 Apertura di un file : SC open() int open(const char * pathname, int flags) –pathname : PN relativo o assoluto del file –flags : indicano come voglio accedere al file O_RDONLY sola lettura, O_WRONLY sola scrittura, O_RDWR entrambe eventualmente messe in or bit a bit una o più delle seguenti maschere : O_APPEND scrittura in coda al file, O_CREAT se il file non esiste deve essere creato, O_TRUNC in fase di creazione, se il file esiste viene sovrascritto, O_EXCL in fase di creazione, se il file esiste si da errore
15 Apertura di un file : SC open() (2) int open(const char * pathname, int flags) –risultato : un intero, il descrittore di file (fd) Tabella dei descrittori di file (nella user area) -- Array di strutture, una per ogni file aperto -- Di ampiezza fissa (max 20) Il fd è l’indice del descrittore assegnato al file appena aperto
16 Apertura di un file : SC open() (3) Tipico codice di apertura di un file : int fd; /*file descriptor */ /* tento di aprire */ fd = open(“s.c”, O_RDONLY); /* controllo errori*/ if(fd==-1) { perror(“fk, in apertura”); exit(errno); /* termina */ }
17 Apertura di un file : SC open() (4) Tipico codice di apertura di un file –uso della macro IFERROR : int fd; /*file descriptor */ /* apertura e controllo errori usando la macro */ IFERROR(fd = open(“s.c”, O_RDONLY), “fk, in apertura”));
18 Apertura di un file : SC open() (5) Cosa fa la open : –segue il path del file per recuparare l’i-node corrispondente – controlla i diritti i accesso (li confronta con le richieste in flags) –se l’accesso è consentito assegna al file l’indice di una posizione libera nella tabella dei descr. ( fd ) aggiorna le strutture dati interne al nucleo … –se si è verificato un errore ritorna -1 (errno) –altrimenti ritorna fd, che deve essere usato come parametro per tutti gli accessi successivi
19 Tabella dei file aperti Copia dell’i-node Tabella degli i-node attivi Tabella dei descrittori di file (user area) fd Pos.Corrente 0 write/read Apertura di un file : SC open() (6) Strutture di nucleo legate ai file
20 Lettura: SC read() Es: lung = read(fd,buffer,N) File descriptor (void *) puntatore all’area di memoria dove andare a scrivere i dati Numero massimo di byte da leggere -1 : errore n > 0 : numero byte letti 0 : Pos.Corrente è a fine file Effetto: Legge al più N byte a partire da Pos.Corrente, Pos.Corrente += lung
21 Lettura: SC read() (2) Tipico ciclo di lettura da file: int fd, lung; /* fd, n byte letti */ char buf[N]; /*buffer*/ /* apertura file */ IFERROR(fd = open(“s.c”, O_RDONLY), “fk, in apertura”)); while ((lung = read(fd,buf,N))>0){ … } IFERROR(lung,”fk, in lettura”);
22 Scrittura: SC write() Es: lung = write(fd,buffer,N) File descriptor (void *) puntatore all’area di memoria dove andare a prendere i dati Numero massimo di byte da scrivere -1 : errore n => 0 : numero byte scritti Effetto: Scrive al più N byte a partire da Pos.Corrente, Pos.Corrente += lung
23 Lettura: SC write() (2) Es. scrittura sullo stdout (fd 1): int fd, lung; /* fd, n byte letti */ char buf[N]; /*buffer*/ IFERROR(fd = open(“s.c”, O_RDONLY), “fk, in apertura”)); while ((lung = read(fd,buf,N))>0){ IFERROR(write(1, buf, lung), “fk, in scrittura”)); } IFERROR(l,”fk, in lettura”);
24 Chiusura: la SC close() Libera le aree di occupate nelle varie tabelle Provoca la scrittura su file di eventuali buffer non pieni int close (int fd)
25 Chiusura: SC close() (2) Es. chiusura di un file …. int fd, lung; /* fd, n byte letti */ char buf[N]; /*buffer*/ IFERROR(fd = open(“s.c”, O_RDONLY), “fk, in apertura”)); while ((lung = read(fd,buf,N))>0){ IFERROR(write(1, buf, lung), “fk, in scrittura”)); } IFERROR(l,”fk, in lettura”); IFERROR(close(fd),”fk, in chiusura”);
26 Standard input, output and error Ogni processo Unix ha dei ‘canali di comunicazione’ predefiniti con il mondo esterno –es. $sort P stdin stdout stderr Tipicamente la tastiera Tipicamente lo schermo
27 Tabella dei descrittori di file (user area) 0 Standard input, output and error (2) Un esempio stdin stdout stderr 1 2 Tabella dei file aperti Copia dell’i-node di ttyX Tabella degli i-node attivi