Introduzione ai sistemi operativi con UNIX | ||
---|---|---|
Prec | 3. Alcune system call di UNIX per l'I/O | Succ |
int open(const char *path, int flags, ...);
#define O_RDONLY 0x0000 /* open for reading only */ #define O_WRONLY 0x0001 /* open for writing only */ #define O_RDWR 0x0002 /* open for reading and writing */ #define O_NONBLOCK 0x0004 /* do not block on open */ #define O_APPEND 0x0008 /* append on each write */ #define O_CREAT 0x0200 /* create if nonexistent */ #define O_TRUNC 0x0400 /* truncate to zero length */ #define O_EXCL 0x0800 /* error if create and file exists */ #define O_SHLOCK 0x0010 /* atomically obtain a shared lock */ #define O_EXLOCK 0x0020 /* atomically obtain an exclusive lock */ #define O_DIRECT 0x00010000 /* eliminate or reduce cache effects */ #define O_FSYNC 0x0080 /* synchronous writes */ #define O_NOFOLLOW 0x0100 /* do not follow symlinks */Se tutto va bene, open(2) ritorna il descrittore del file, ossia un intero positivo o nullo (non negativo), altrimenti ritorna -1 e setta errno. Tra i vari errori possibili notiamo quello di codice 24 (EMFILE) "Too many open files". Il sistema limita il numero di descrittori di file che uno stesso processo può tenere aperti contemporaneamente. Questo numero rappresenta il numero di righe della tabella di descrittori del processo. Se scrivete un programma che per errore continua ad aprire file senza mai chiuderli raggiungerete facilmente questo limite, nonostante possa essere praticamente più che sufficiente per programmi corretti (sul mio sistema ad esempio il limite imposto dal kernel è 2743, come ritornato dalla system call getdtablesize(2), ma la costante NOFILE definita nella libreria C in <sys/param.h> definisce un valore molto inferiore, 64). Una buona pratica di codifica di programmi che devono girare in sistemi multiprogrammati è di liberare tutte le risorse che si utilizzano quanto prima possibile, ossia non appena non servono più. Per i file quindi chiudeteli non appena non servono più utilizzando la system call close(2). Quando un programma C termina tutti i file aperti vengono chiusi automaticamente dalla exit(3) implicita o esplicita.
In FreeBSD il massimo numero di file che un processo può tenere aperti è una variabile di stato del kernel che si legge e scrive da shell tramite il comando sysctl(8):
$ sysctl kern.maxfilesperproc kern.maxfilesperproc: 2743 # sysctl kern.maxfilesperproc=1000 kern.maxfilesperproc: 2743 -> 1000le descrizioni delle variabili si trovano in sysctl(3).
Il sistema operativo mantiene aggiornato per ogni file un puntatore che marca la posizione corrente, e la open lo pone inizialmente all'inizio del file.
I flag possono essere combinati con l'operatore di OR logico bit a bit, che in C si indica con |. Se attivato il flag O_CREAT indica che il file deve essere creato se non esiste. Se O_CREAT non è specificata e si tenta di aprire un file inesistente si verifica l'errore ENOENT. Ad esempio:
int d=open(path, O_CREAT | O_TRUNC | O_WRONLY, mode);chiede di creare il file il cui nome si trova nella stringa path se non esiste (O_CREAT). Notare che se il file non esiste verrà creato coi permessi specificati dal terzo parametro. Esistono costanti simboliche per specificare i permessi e sono descritte in chmod(2). Parleremo meglio dei permessi di UNIX in seguito. Tenete anche presente che il valore di umask(2) viene invertito tramite NOT bit a bit e poi posto in AND bit a bit con la maschera di permessi specificata, per ottenere la maschera realmente utilizzata. Se invece il file esiste, si chiede di troncarlo a dimensione zero, in modo da riscriverlo completamente (O_TRUNC), senza che i suoi permessi correnti vengano variati. In entrambi i casi il file viene aperto in modalità di sola scrittura.
Un'altro uso tipico della open(2) è il seguente:
fd=open(name, O_RDONLY, 0);oppure semplicemente:
fd=open(name, O_RDONLY);l'effetto è di aprire in sola lettura un file esistente. Come detto prima si verifica errore 2 (ENOENT) "No such file or directory" se il file non esiste.
Continuando l'esempio del comando cat(1) ecco una estensione di mycat che accetta un qualsiasi numero di file da visualizzare come parametri sulla riga di comando, proprio come il vero cat(1). Da notare l'utilizzo di close(2) non appena abbiamo finito di leggere tutto il file. Non dimenticate di chiamare la close(2) in questi casi!
/* mycat.c :) */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> /* return status to pass to the environment */ int status=EXIT_SUCCESS; void cat(int d) { char buf[BUFSIZ]; int n; while ((n=read(d, buf, BUFSIZ)) > 0) write(1, buf, n); if (n) status=EXIT_FAILURE; } int main(int argc, char *argv[]) { int d; if (argc==1) /* no arguments, use stdin */ cat(0); else while (--argc > 0) if (!strcmp(*++argv, "-")) cat(0); else if ((d=open(*argv, O_RDONLY))==-1) { perror(*argv); status=EXIT_FAILURE; } else { cat(d); close(d); } exit(status); }
Proprio come cat(1), mycat se il nome del file non è specificato, oppure se questo è un trattino o meno (`-'), legge da stdin.
Prec | Indice | Succ |
write | Livello superiore | Elenco delle principali system call |