#include <sys/stat.h> #include <fcntl.h> CREAZIONE DI UN FILE fd = creat(filename, mode); int fd, mode; char *filename; La primitiva creat crea un file, se non ne esiste uno col nome specificato, oppure distrugge il contenuto del file: prepara il file per la riscrittura, se esso esiste già. La creat restituisce un numero intero, fd, che rappresenta il file descriptor per il file se l operazione è riuscita (valore positivo o nullo), altrimenti restituisce un valore negativo, interpretato come un codice d errore. Il file è aperto in sola scrittura. Il parametro filename è il nome del file su cui operare nel file system: per nome intendiamo sia nome relativo, sia assoluto. Se il file è un nuovo file, il parametro mode consente di specificare il modo di protezione per il file assegnando tramite esso i nove diritti di lettura, scrittura, esecuzione per proprietario, gruppo, ed altri utenti. Ciò può essere indicato esprimendo mode con codifica ottale. Se il file esiste già, i diritti rimangono inalterati. #include <sys/stat.h> #include <fcntl.h> APERTURA DI UN FILE fd = open(filename, flag); int fd, flag; char *filename; La open apre una sessione di interazione con un file. Il puntatore di I/O è posizionato al primo byte del file. Nella chiamata, nomefile specifica il nome del file, come per la creat, e flag specifica se il file deve essere letto (0 o O_RDONLY), scritto (1 o O_WRONLY), o aggiornato, cioè letto e scritto (2 o O_RDWR). La open restituisce un file descriptor, fd, positivo o nullo, in caso di successo (come per la creat). Se si è verificato un errore, la open restituisce un valore negativo. Il file <fcntl.h> contiene le definizione di costanti simboliche (O_RDONLY, O_WRONLY, O_RDWR), che possono essere specificate nel parametro flag. Quelle elencate sopra non sono le sole possibilità di accesso al file: il file <fcntl.h> fornisce apertura con creazione se il file non esiste: O_CREAT, apertura per appendere al file, col posizionamento alla fine del file: O_APPEND, apertura producendo un errore se si tenta di aprire un file che esiste già: O_EXCL. Primitive UNIX - Pagina 1 di 10
CHIUSURA DI UN FILE retval = close(fd); int retval, fd; La primitiva close elimina la connessione fra il programma e il file (precedentemente a- perto) che ha per descrittore fd. Il valore retval specifica se l operazione è andata a buon fine (0), o meno (-1). CREAZIONE DI UN LINK retval = link(filename1, filename2); int retval; char *filename1, *filename2; Viene creato un link per il file di nome filename1 (già esistente); il link crea un file di nome filename2, che identifica il file, sia come nome che come sottodirettorio di appartenenza. Viene così creato un nuovo file, con il nome relativo ed il direttorio specificato da filename2. La primitiva link non crea un nuovo i-node, ma solo un nuovo collegamento ad un i-node esistente. Il nuovo ed il vecchio collegamento condividono gli stessi diritti di accesso sull oggetto file fisico. Il valore di ritorno, retval, è 0 in caso di successo. CANCELLAZIONE DI UN LINK retval = unlink(path); int retval, char *path; unlink rimuove l entry di un file da un direttorio in cui esso è presente; entrambi (il file e il direttorio) vengono specificati dal path, nome completo indicato nell invocazione. Se questo entry è l ultimo (o unico) link per quel file, tutte le risorse associate con il file vengono rese disponibili. Se però il file è raggiungibile attraverso altri link, la distruzione viene ritardata. In caso di riuscita unlink restituisce 0 in retval, altrimenti restituisce -1. Primitive UNIX - Pagina 2 di 10
LETTURA DA UN FILE nread = read(fd, buf, n); int nread, fd, n; char *buf; Vengono letti dal file specificato con il file descriptor fd fino a n byte a partire dalla posizione corrente e vengono memorizzati nell area di bufferizzazione specificata da buf. La read restituisce il numero nread di byte effettivamente trasferiti: tale numero può essere minore del numero n di byte richiesti nel caso in cui si raggiunga la fine del file prima della conclusione dell operazione di lettura. Nel caso di lettura del terminale (trattato come un file) la lettura viene di solito effettuata fino al successivo carattere di newline, per poi fornire solo i caratteri richiesti e mantenere gli altri per le successive operazioni. La fine del file, in questo caso, si specifica con <CTRL> D. Nel caso di file veri e propri, la lettura avviene o dal buffer già letto o riempiendo l intero buffer (con informazioni disponibili per successive letture). Se il valore restituito è negativo, si è verificato un errore. SCRITTURA SU UN FILE nwrite = write(fd, buf, n); int nwrite, fd, n; char *buf; Vengono scritti n byte sul file rappresentato da fd, presi dal buffer buf, a partire dalla posizione corrente. Il valore restituito, nwrite, è il numero di byte realmente scritti, ed è, in generale, un errore se esso è diverso dal numero n di byte che si volevano scrivere. newpos = lseek(fd, offset, origin); int fd, origin; long int newpos, offset; POSIZIONAMENTO ALL INTERNO DI UN FILE La primitiva lseek consente di spostare la posizione corrente nel file a partire dalla quale verrà effettuata la successiva operazione di read o di write, realizzando così un accesso diretto al file nella posizione voluta. Il puntatore di I/O del file identificato da fd viene spostato nella posizione determinata dallo spiazzamento specificato da offset rispetto alla posizione origin. origin può essere 0, 1, 2 per specificare un offset preso a partire rispettivamente dall origine del file, dalla posizione corrente o dalla fine del file (e in quest ultimo caso negativo, se all interno del file stesso). Primitive UNIX - Pagina 3 di 10
CAMBIAMENTO DI DIRETTORIO CORRENTE retval = chdir(path); int retval; char *path; Accede al direttorio specificato in path. Ritorna 0 in caso di successo in retval. #include <fcntl.h> #include <sys/stat.h> CREAZIONE DI UN DIRETTORIO retval = mkdir(pathname, mode); int retval, mode; char *pathname; Crea un direttorio con nome e posizione specificati da pathname e con diritti specificati da mode (040777 R/W/X per tutti). VERIFICA DELL ACCESSO retval = access(pathname, amode); int retval, amode; char *pathname; La primitiva access consente di verificare il tipo di accesso consentito sul file il cui percorso assoluto è specificato da pathname. Il parametro amode può essere: 00 existence F_OK 01 execute access X_OK 02 write access W_OK 04 read access R_OK Nel file <unistd.h> sono definite le costanti F_OK, R_OK, W_OK, X_OK. #include <sys/stat.h> VERIFICA DELLO STATO DI UN FILE retval = stat(pathname, &buff); int retval; char *pathname; struct stat buff; Primitive UNIX - Pagina 4 di 10
L accesso ad informazioni di un file, noto il suo nome, pathname, si può ottenere attraverso la primitiva stat. Se invece si possiede il file descriptor, fd, del file in questione si può usare la funzione fstat. retval = fstat(fd, &buff); int retval, fd; struct stat buff; Il valore di ritorno è 0 in caso di successo, un valore negativo altrimenti. All interno della struttura buff vengono scritte le informazioni relative al file. I campi della struct stat sono: struct stat { ushort st_mode; // modo del file ino_t st_ino; // numero dell i-node dev_t st_dev // id del dispositivo dev_t st_rdev // solo per i file speciali short st_nlink // numero di link ushort st_uid // user id del proprietario ushort st_gid // group id del proprietario off_t st_size //lunghezza del file in byte time_t st_atime //tempo dell ultimo accesso time_t st_mtime //tempo dell ultima modifica time_t st_ctime //tempo dell ultimo cambiamento di stato } CREAZIONE DI UN PROCESSO pid = fork(); int pid; In seguito ad una fork si hanno due processi concorrenti e indipendenti: il parent (processo padre), quello originario il child (processo figlio), quello generato Entrambi eseguono a partire dall istruzione successiva alla fork. La fork restituisce in pid un valore differente per i due processi e ciò costituisce l unico modo di distinguere l uno dall altro: nel child tale valore è zero, nel parent un valore diverso da zero che è l identificatore (il process identifier) di quel child. Per qualsiasi errore la fork restituisce al parent un valore negativo, altrimenti l identificatore di processo associato al figlio. Primitive UNIX - Pagina 5 di 10
#include <wait.h> #include <sys/wait.h> SOSPENSIONE DI UN PROCESSO pid = wait(&status); int pid, status; La primitiva wait sospende il parent in attesa della fine del suo (uno dei suoi) child. In pid c è 1 in caso di insuccesso o, in caso di successo, il pid del figlio che ha terminato. Se il figlio termina volontariamente, nel valore di ritorno, status, si ha: nel byte alto c è il valore ritornato dal figlio con la exit nel byte basso c è zero Se il figlio termina in seguito alla ricezione di un segnale, nel valore di ritorno si ha: nel byte alto c è zero nel byte basso c è il numero del segnale che ha provocato la terminazione del figlio Se non interessa il valore di ritorno, invocare: pid = wait((int*)0); Sono definite le seguenti macro che permettono un agevole interpretazione del valore contenuto in status: WIFEXITED(status) Ritorna un valore diverso da zero se il figlio ha terminato normalmente. WEXITSTATUS(status) Ritorna il valore della exit del figlio. Questa macro può essere usata solo se WIFEXI- TED ha ritornato un valore diverso da zero. WIFSIGNALED(status) Ritorna TRUE se il processo figlio ha terminato a causa di un segnale non intercettato. WTERMSIG(status) Ritorna il numero del segnale che ha causato la terminazione del figlio. Questa macro può essere usata solo se WIFSIGNALED ha ritornato un valore diverso da zero. TERMINAZIONE void exit(status); int status; Termina il processo che la esegue, chiudendo tutti i file aperti del processo stesso. Il valore del parametro status viene passato al processo padre, se questo sta attendendo il processo che termina. Per convenzione: il valore zero rappresenta una terminazione normale un valore diverso da zero rappresenta un problema Primitive UNIX - Pagina 6 di 10
ESECUZIONE DI UN PROGRAMMA execv(pathname, argv); char *pathname, *argv[ ]; Esegue il comando identificato, in modo assoluto, da pathname passandogli come parametri le stringhe precedentemente memorizzate nell array argv. execl(pathname, argv0, argv1,, argvn); char *pathname, *argv0, *argv1,, *argvn; Esegue il comando identificato, in modo assoluto, da pathname passandogli come parametri le stringhe argv0,, argvn. execvp(name, argv); char *name, *argv[ ]; Esegue il comando di nome name passandogli come parametri le stringhe precedentemente memorizzate nell array argv. NB: Il direttorio dove si trova l eseguibile deve essere nel PATH! execlp(name, argv0, argv1,, argvn); char *name, *argv0, *argv1,, *argvn; Esegue il comando di nome name passandogli come parametri le stringhe argv0,, argvn. NB: Il direttorio dove si trova l eseguibile deve essere nel PATH! IDENTIFICAZIONE DI UN PROCESSO pid = getpid(); int pid; Restituisce il process identifier del processo corrente. pid = getppid(); int pid; Restituisce il process identifier del padre del processo corrente. Primitive UNIX - Pagina 7 di 10
#include <signal.h> DEFINIZIONE DI UN HANDLER signal(sig, function); int sig; void(*func)(); Si specifica: quale segnale trattare (sig). NB: non può essere SIGKILL come trattarlo (function) Per quanto riguarda function vi sono tre possibilità: l indirizzo di una funzione gestore ignorare il segnale (SIG_IGN) riportare all azione di default (SIG_DFL) Nel caso venga specificato un gestore, all occorrenza del segnale sig viene invocata function che riceve il numero del segnale come argomento. a) Comportamento UNIX BSD: quando un segnale collegato ad una funzione non è ignorato da un processo, ed esso arriva una prima volta, successivi arrivi del segnale vengono automaticamente bloccati prima di chiamare la funzione di gestione. Al termine dell esecuzione del gestore, il ritorno della funzione sblocca il segnale e il processo riprende l esecuzione dal punto in cui era stato interrotto. Altri eventuali arrivi di quel segnale nel frattempo non vengono considerati. b) Comportamento UNIX System V: non appena il segnale viene ricevuto, e quando la funzione non è stata ancora effettivamente chiamata, lo stato del segnale viene riportato a SIG_DFL, senza bloccarlo. L arrivo di un secondo segnale può allora risultare mortale per il processo. Elenco dei principali segnali: Nome Numero Significato SIGHUP 1 hangup: sconnessione dal terminale SIGINT 2 interrupt da terminale (in genere <CTRL> C) SIGQUIT 3 quit da un programma con salvataggio dell immagine di memoria (<CTRL> \) SIGILL 4 istruzione non consentita SIGKILL 9 uccisione (non intercettabile o ignorabile) SIGSYS 12 errore di argomento in una system call SIGPIPE 13 scrittura su pipe che no ha lettore SIGALRM 14 allarme da orologio (ricevuto quando è passato un intervallo di tempo stabilito con la funzione alarm) SIGTERM 15 terminazione software: generato dalla terminazione del codice SIGUSR1 16 segnale lasciato all utente per sincronizzazione Primitive UNIX - Pagina 8 di 10
SIGUSR2 17 segnale lasciato all utente per sincronizzazione SIGCHLD 18 lo stato del child è cambiato (stop o exit del child) NB: L azione di default è SIG_IGN!! INVIO TEMPORIZZATO DI UN ALLARME unsigned alarm(numerosecondi); unsigned numerosecondi; Questa primitiva consente di inviare al processo corrente dopo un certo tempo (espresso in secondi) un segnale di allarme. È quindi una richiesta di attivazione di un gestore di allarme temporizzato. Se il segnale non è gestito vale l azione di default (terminazione). void pause(); SOSPENSIONE IN ATTESA SI UN QUALUNQUE SEGNALE Questa primitiva richiede la sospensione del processo corrente fino all arrivo di un segnale qualunque. È quindi adatta a processi che vogliano attendere il verificarsi di un qualunque segnale. Il processo rimane in stato sospeso fino al verificarsi di un evento, quindi un processo può mettersi in attesa di un evento ed essere risvegliato dal segnale relativo che lo rimette in esecuzione. NB: Un segnale ignorato non viene ricevuto, quindi un processo in pause non viene risvegliato all occorrenza di questo segnale!! SOSPENSIONE TEMPORIZZATA unsigned sleep(numerosecondi); unsigned numerosecondi; La primitiva consente una sospensione del processo che la invoca per il numero di secondi specificato. Naturalmente, la sospensione può durare un numero di secondi superiore a quanto richiesto a causa dello scheduling del sistema. Primitive UNIX - Pagina 9 di 10
#include <signal.h> INVIO DI SEGNALI AD ALTRI PROCESSI retval = kill(pid, sig); int retval, pid, sig; kill è una system call che consente di mandare il segnale sig ad un processo specificato dal suo identificatore pid. sig può essere uno qualsiasi dei segnali, oppure essere 0, nel qual caso non viene mandato alcun segnale e viene invece fatta una ricerca di un eventuale errore nella chiamata. Questo modo di invocazione si utilizza per vedere se l identificatore pid è corretto, cioè se appartiene ad un processo esistente. Il valore di ritorno, retval, specifica se l azione ha avuto l effetto desiderato. Il processo che spedisce e quello che riceve il segnale devono avere lo stesso identificatore di utente effettivo : solo il superutente può mandare segnali ad un qualunque processo. CREAZIONE DI UNA PIPE retval = pipe(fd); int retval, fd[2]; In retval c è 0 in caso di successo, un valore negativo altrimenti. Vengono forniti come parametri di ritorno due file descriptor fd[0] e fd[1], rispettivamente per la lettura e la scrittura della pipe. È compito del processo padre generare una pipe, e quindi con l esecuzione di una (o più) fork generare i processi che possono usufruirne: la primitiva fork prevede il passaggio dei file descriptor aperti dal padre al figlio. Se viene operata una scrittura su una pipe con una sola parte aperta, cioè che non ha lettori, viene generato l apposito segnale SIGPIPE. La pipe viene implementata come se fosse un file, cioè tramite file descriptor, ma con queste differenze: al file descriptor non corrisponde alcun nome nel file system; la dimensione di una pipe è fissa; una volta che dei dati depositati dallo scrittore sono stati letti, la scrittura ricomi n- cia all inizio del file. La memoria associata viene gestita come un buffer circolare da cui si preleva e su cui si deposita. Primitive UNIX - Pagina 10 di 10