MODELLO di PROGRAMMA in UNIX

Documenti analoghi
SmallShell Piccolo processore comandi

I File in Unix. Primitive (System Call) Processo

Î Modello ad Ambiente Locale P1 P1. File System P2 P2 P3 P3. Processi in UNIX. Modello di Processo in UNIX

Processi in UNIX. Spazio di sistema (residente) Tabella dei. file APERTI OPEN FILE. Tabella dei codici

Modello di Programma in UNIX

System call per la gestione di processi

System call per la gestione di processi

I Processi nel SO UNIX

Il processo figlio : utilizza lo stesso codice che sta eseguendo il padre ;

La creazione di un nuovo processo in UNIX

&& (nessun altro processo ha il file aperto) && (il fd e chiuso) Cancella il file;

I Processi nel SO UNIX

I Processi nel SO UNIX

I Processi nel Sistema Operativo Unix. Gerarchie di processi Unix. Stati di un processo Unix. Stati di un processo Unix.

Directory. Le directory unix sono file.

Il File System di Unix

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Esercitazione 4. Gestione dei file in Unix

Comunicazione tra processi: pipe Le pipe sono un meccanismo UNIX di Inter Process Communication (IPC)

Sistemi Operativi Teledidattico

LABORATORIO DI SISTEMI OPERATIVI

Il File System di UNIX

UNIX file system: organizzazione logica. Il File System di UNIX. UNIX file system: organizzazione fisica

CORSO DI SISTEMI OPERATIVI A - ESERCITAZIONE 4

Scrivere alla fine di un file Vi sono due modi per scrivere alla fine di un file:

SISTEMI OPERATIVI. Processi in Linux. Giorgio Giacinto Sistemi Operativi

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Comandi. Sistema Operativo

LINUX: struttura generale

I Processi nel Sistema Operativo Unix

Programmazione di sistema in UNIX. Immagine di un processo in UNIX. Area dati. File comandi utente

Processi UNIX. I Processi nel SO UNIX. Gerarchie di processi UNIX. Modello di processo in UNIX

Corso di Sistemi Operativi A.A CHIAMATE DI SISTEMA PER FILE E SEMAFORI. Fabio Buttussi

Sistemi Operativi. II Semestre - Marzo/Giugno 2012 Matricole congr. 0 mod 3. File & Directory

Laboratorio di Sistemi Operativi Marzo-Giugno 2008 matricole congrue 0 mod 3

System Calls per la Gestione dei Processi

Università degli Studi di Cagliari Corso di Laurea Specialistica in Ingegneria Elettronica. SISTEMI OPERATIVI A.A. 2004/2005 Docente: Giorgio Giacinto

Laboratorio di Sistemi Operativi

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Capitolo 3 -- Stevens

Scrivere alla fine di un file Vi sono due modi per scrivere alla fine di un file:

Sistemi Operativi. II Semestre - Marzo/Giugno 2011 Matricole congr. 0 mod 3. File & Directory. Leggere Directory

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

LABORATORIO DI SISTEMI OPERATIVI

Modulo 13: System call relative al File System

Richiami sui Concetti Fondamentali dei Processi

Laboratorio di Sistemi Operativi

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Lab. di Sistemi Operativi - Lezione in aula - a.a. 2012/2013

CREAZIONE DI UN FILE

Sistemi di Calcolo - Secondo modulo (SC2) Programmazione dei Sistemi di Calcolo Multi-Nodo

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Lab. di Sistemi Operativi - Esercitazione n 7- -Gestione dei processi Unix-

Processi Concetti di base. Esecuzione parallela e sequenziale Il concetto di processo Gestione dei processi

Introduzione. P4 termina prima di P3, P2 e P3 prima di P1 P1 P2 P3 P4 P1 P1 P2 P3 P4. Padre. P1,..., P4 sono processi. Figlio

Chiamate di sistema. Pipe Flussi di I/O

Pag. 1. modello di esecuzione parallela

System call per l accesso a file

Esercitazione di Lab. di Sistemi Operativi 1 a.a. 2011/2012

Processi. Introduzione. Effective user/group id. Fork

Esercitazione di Lab. di Sistemi Operativi. - I/0 di basso livello

Le strutture. Una struttura C è una collezione di variabili di uno o più tipi, raggruppate sotto un nome comune.

Corso di Reti di Calcolatori T

eseguire comandi dati dall'utente, utilizzando una macchina reale, di livello inferiore,

Chiamate di sistema. Pipe Flus s i di I/O

Laboratorio di Sistemi Operativi primavera 2009 open

Corso di Laboratorio di Sistemi Operativi A.A

System calls. permettono ai programmi utente di richiedere servizi al Sistema Operativo. servizi come scrittura di file, stampa su video, ecc.

GESTIONE DELLA COMUNICAZIONE LOCALE TRA PROCESSI IN UNIX:

Progetto II: Il linguaggio C e le chiamate di sistema sui processi

Controllo dei Processi 1

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

File I/O. M. R. Guarracino: File I/O 1

Sistemi Operativi (M. Cesati)

Chiamate di sistema per la Gestione dei processi in POSIX. E.Mumolo, DEEI

La famiglia di system call exec. Modulo 6. Laboratorio di Sistemi Operativi I Anno Accademico

SC per Inter Process Comminication. Pipe senza nome e con nome (FIFO)

Sistemi Operativi 1. Mattia Monga. a.a. 2018/19. Dip. di Informatica Università degli Studi di Milano, Italia

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

La Comunicazione tra Processi in Unix

La Comunicazione tra Processi in Unix

Laboratorio di Sistemi Operativi primavera 2009

Capitolo 5 -- Stevens

5. I device driver. Device driver - gestori delle periferiche. Struttura interna del sistema operativo Linux. Tipi di periferiche. Tipi di periferiche

Corso di Programmazione Concorrente Processi. Valter Crescenzi

System Call EXEC EXEC P P. fork exec(new_prog) fork. sono_il_padre = fork(); if (!sono_il_padre) {

Input-Output di basso livello

Sistemi Operativi 1. Lezione III: Concetti fondamentali. Mattia Monga. 7 marzo 2008

Sistemi Operativi 1. Mattia Monga. 7 marzo Dip. di Informatica e Comunicazione Università degli Studi di Milano, Italia

Processi: Exit, Wait, Exec

Laboratorio di Sistemi Operativi primavera 2009

Sistemi Operativi. Marzo-Giugno 2011 matricole congrue 0 mod 3. Controllo dei processi - I

Lab. di Sistemi Operativi - Esercitazione n 9- -Thread-

SISTEMI OPERATIVI e LABORATORIO DI SISTEMI OPERATIVI (A.A ) 30 MARZO 2007

Scrivere alla fine di un file Vi sono due modi per scrivere alla fine di un file:

Sistemi Operativi 1. Mattia Monga. a.a. 2015/16. Dip. di Informatica Università degli Studi di Milano, Italia

Sistemi Operativi. Bruschi Monga Re. Shell Esercizi Shell programming Esercizi I/O. Sistemi Operativi. Bruschi Monga Re

Perchè i files? Realizzano la persistenza dei dati. Sono delle strutture di dati sequenziali. dati che sopravvivono all esecuzione del programma

Transcript:

MODELLO di PROGRAMMA in UNIX Un Programma ha Spazio di Indirizzamento per ogni singolo 352&(662 Spazio UTENTE AREE DATI Dati Globali 6WDWLFL 'LQDPLFL Heap Stack AREA di CODICE PROCESSO il processo può riferire dati codice Ma anche - argc int argc; numero di argomenti (incluso il comando) - argv char *argv[]; argv[0] è il comando stesso; argv[1]... argv[argc-1]: argomenti dal primo all'ultimo. - envp char ** envp; stringhe composte nome = valore Esempio: main (DUJFDUJYHQYS) int argc; char *argv[]; char **envp; { int i; for (i = 1; i < argc; i++) printf("%s%c", argv[i], (i < argc-1)? : \n ); i = 1; while (*envp!= (char *)0) printf ("%d %s\n", i++, *envp++); Spazio UTENTE Spazio di Indirizzamento AREA AREA di '$7, &2',&( per ogni singolo 352&(662 6WDWLFL 'LQDPLFL il processo può riferire dati aggiuntivi in AREA di KERNEL argc #argomenti argv envp stringhe ambiente L'area di KERNEL è generalmente NON visibile PATH=/bin:/usr/bin:.:/usr/antonio/bin Unix azioni primitive 1 Unix azioni primitive 2

UNIX: E i file? OPERAZIONI di Basso LIVELLO sui FILE create, open, close, read / write, lseek OPERAZIONI sul FILE SYSTEM: prologo, epilogo &5($7( fd = FUHDW(name,mode); int mode; /* attributi del file */ ===> sono i diritti di UNIX (di solito espressi in ottale) 23(1 fd =RSHQ(name, flag); char *name; int flag; /* 0 lettura, 1 scrittura, 2 entrambe */ int fd; /* file descriptor */ ===> apre il file di nome name con modalità flag ===> in /usr/include/fcntl.h sono definite le costanti O_RDONLY, O_WRONLY, O_RDWR &/26( retval = FORVH(fd); int fd, retval; Operazioni di RICHIESTA e RILASCIO risorse File descriptor => riferimento a istanze di tipi di dato astratti per riferire i file necessari OPERAZIONI ancora OPERAZIONI di prologo di sessione create, open &5($7( fd = FUHDW(name,mode); 23(1IG RSHQQDPHIODJPRGH char *name; int flag; /* 0 lettura, 1 scrittura, 2 entrambe */ int mode; /* attributi del file */ int fd; /* file descriptor */ ===> in /usr/include/fcntl.h altre costanti O_RDONLY, O_WRONLY, O_RDWR O_CREAT crea se non esiste, O_TRUNC distrugge il contenuto, O_APPEND aggiunge in fondo al file, O_EXCL fallisce se il file esiste già, #include /usr/include/fcntl.h fd1 = open("pippo", O_CREAT); fd2 = open("pluto", O_WRONLY O_TRUNC); fd3 = open("paperino", O_RDWR O_CREAT, 0764); fd4 = open("paperina", O_RDWR O_EXCL, 0764); se fd4 negativo, cosa vuol dire? NUMERI successivi associati ai file aperti Unix azioni primitive 3 Unix azioni primitive 4

FILE DESCRIPTOR stdin, stdout, stderror associati ai file descriptor 0, 1, 2 I file descriptor sono parte dello spazio di kernel e associati ad un processo Nuove operazioni di RICHIESTA producono nuovi file descriptor per un processo. FILE di UNIX Organizzazione a BYTE ACCESSO sequenziale I/O pointer associato al file OPERAZIONI di LETTURA E SCRITTURA 5($' nread = UHDG(fd, buf, n); :5,7( nwrite = ZULWH(fd, buf, n); int nread, nwrite, n, fd; char *buf; - lettura e scrittura di un file avvengono a partire dalla posizione corrente del file ed avanzano il pointer (I/O pointer) all interno del file - restituiscono il numero dei byte su cui hanno lavorato Ogni utente ha la propria visione dei file aperti Nel caso di più utenti che aprono lo stesso file ogni processo utente ha un proprio I/O pointer separato processo 0 1 2 area.(51(/ file SE un utente legge o scrive, modifica il proprio pointer gli altri utenti non modificano il proprio I/O pointer SE un utente chiude un file, non c'è impatto sugli altri utenti FILE SYSTEM CONDIVISO Un utente non ha visibilità delle azioni di un altro utente se non attraverso la modifica dei dati Unix azioni primitive 5 Unix azioni primitive 6

esempi di lettura/scrittura COPIA da un FILE ad un ALTRO #include <fcntl.h> #include <stdio.h> #define perm 0644 main () { char f1 [20]= "file", f2 [40]= "/temp/file2"; int infile, outfile; /* file descriptor */ int nread; char buffer [BUFSIZ]; infile = RSHQ (f1, O_RDONLY); outfile = FUHDW (f2, perm); COPIA da un FILE ad un ALTRO (uso argomenti) #define perm 0777 main (argc, argv) int argc; char **argv; { int infile, outfile, nread; char buffer [15]; infile = RSHQ (argv [1], 0); outfile = FUHDW (argv [2], perm); while (( nread = UHDG (infile, buffer, 1)) > 0 ) ZULWH(outfile, buffer, 1 ); FORVH (infile); FORVH (outfile); while ( (nread = UHDG(infile, buffer, BUFSIZ)) > 0 ) ZULWH (outfile, buffer, nread ); FORVH (infile); FORVH(outfile); Legge dal file file e scrive su file2 in temp Con RIDIREZIONE #define LUNG 1 main () { char buffer [LUNG]; while ( UHDG(0, buffer, LUNG) > 0 ) ZULWH (1, buffer, LUNG); Il sistema esegue i collegamenti tra file descriptor e file Unix azioni primitive 7 Unix azioni primitive 8

#include <fcntl.h> #include <stdio.h> #define perm 0744 /* tutti i diritti all owner lettura al gruppo ed altri */ LQWFRS\ILOHII char *f1, *f2; { int infile, outfile, nread; char buffer [BUFSIZ]; EXIIHUXVDWRSHULFDUDWWHUL if (( infile = RSHQ ( f1, O_RDONLY)) < 0) return (-1); if (( outfile = FUHDW ( f2, perm )) <0 ) {close (infile); return (-2); while (( QUHDG UHDG (infile, buffer, BUFSIZ)) > 0 ) { if ( ZULWH(outfile, buffer, nread ) <QUHDG ) { close (infile); close (outfile); return (-3); /* errore */ close (infile); close (outfile); return (0); main (argc, argv) int argc; char **argv; { int status; char *temp1, *temp2; if (argc >2) { temp1 = argv[1]; temp2 = argv[2]; else { printf (" errore "); exit (-2); status = FRS\ILOH(temp1, temp2); exit (status); Si passano i nomi dei file come argomenti ESEMPIO: INSERIMENTO DI CARATTERI IN UN FILE #include <fcntl.h> #define perm 0744 main (argc, argv) int argc; char **argv; { int fd; char *buff; int nr; printf("il nome del file su cui inserire i caratteri è %s\n", argv[1]); buff=(char *)malloc(80); ELVRJQD$//2&$5(PHPRULDSHULO%8))(5 if ((fd = open(argv[1], O_WRONLY)) < 0) fd = creat(argv[1], perm); printf("aperto o creato con fd = %d\n", fd); while ((nr=read(0, buff,80)) > 0) write(fd, buff, nr); close(fd); Unix azioni primitive 9 Unix azioni primitive 10

In generale, la lettura da fd 0 legge da stdin la scrittura su fd 1 scrive su stdout Questi due file descriptor sono aperti automaticamente dal sistema (shell) e collegati all I/O Per progettare FILTRI cioè usare RIDIREZIONE e PIPING i filtri leggono direttamente dal file descriptor 0 scrivono direttamente sul file descriptor 1 Completa Omogeneità dei file con i dispositivi fd = open ("/dev/printer", O_WRONLY); Anche per i dispositivi usiamo le stesse primitive open, read, write, close File e multiutenza Ogni utente ha un identificatore detto uid (user id) e appartiene a un gruppo gid (group id), contenuti nel file /etc/passwd. Esempio: antonio:itz7b:2:1:a.corradi:/home/antonio:/bin/csh Un processo acquisisce uid e gid dell utente che lo lancia. Il kernel memorizza per ogni file user id ed group id del processo creatore. Un processo può accedere a un file se: uid processo == 0 uid processo == uid proprietario file e diritti OK uid processo!= uid proprietario file ma gid processo == gid proprietario file e diritti OK uid e gid proc!= uid e gid file, ma diritti other OK Attenzione: in realtà il kernel guarda effective uid e gid del processo che accede al file Unix azioni primitive 11 Unix azioni primitive 12

OPERAZIONI non SEQUENZIALI /6((. newpos = OVHHN(fd, offset, origin); long int newpos, offset; int fd; int origin; /* 0 dall inizio, 1 dal corrente, 2 dalla fine*/ Si sposta la posizione corrente per un certo processo. Le successive operazioni di lettura/scrittura a partire dalla nuova posizione NON è garantita la Atomicità delle sequenze di operazioni. Per esempio se più processi mandano file sulla stampante Si possono mescolare le linee inviate alla stampante!!!! ==> Definizione di un gestore del file (system) che incapsula la risorsa Operazioni sui dispositivi e file solo sincrone FLRqFRQDWWHVDGHOFRPSOHWDPHQWRGHOORSHUD]LRQH Gestore File ATOMICITÀ della SINGOLA OPERAZIONE di lettura/ scrittura e di azione su un file. Operazioni primitive aazioni elementari e non interrompibili della macchina virtuale UNIX file P1 111111111 write P2 2222222222 write Come fare il progetto? Comunicare con il processo gestore attraverso file (si pensi alle open esclusive) Tipi di file - file ordinari - file direttori - file speciali (dispositivi fisici) in /dev speciali orientati al carattere (sono tipicamente stampanti, terminali, linee telefoniche) speciali orientati al blocco (dischi,nastri) Unix azioni primitive 13 Unix azioni primitive 14

ESEMPIO: ESEMPIO UNIX Le stringhe, lette da input vengono inserite in un file (senza distruggerne il contenuto) solo se soddisfano una certa condizione. Il nome del file é un parametro del programma. #include <stdio.h> #include <fcntl.h> #define perm 0744 int SDWWHUQ(s) char *s; { UHVWLWXLVFHVRORVHLOVHFRQGRFDUDWWHUHqXJXDOHDVHVHLO SHQXOWLPRqXQDFLIUD return ( s[1] == s && s[strlen(s)-2] >= 0 && s[strlen(s)-2] <= 9? 1 : 0 ); PDLQ (argc, argv) int argc; char **argv; { int fd; char stringa [80], answer [3]; char eol = \n ; long int pos = 0; printf("il nome del file su cui inserire le stringhe è %s\n", argv[1]); if ((fd = open(argv[1], O_WRONLY)) < 0) /* DSHUWXUDLQVFULWWXUD */ fd = creat(argv[1], perm); /*VHQRQHVLVWH FUHD]LRQH */ else pos = lseek(fd, 0L, 2); /*VHLOILOHHVLVWHFLVLSRVL]LRQDDOODILQH */ printf ("il file contiene %ld byte\n", pos); while ( printf("vuoi finire?(si/no)\n"), scanf("%s", answer), strcmp (answer,"si") ) { printf("fornisci la stringa da inserire\n"); scanf("%s", stringa); /* le stringhe vengono lette con )81=,21,&GL DOWROLYHOOR */ if (pattern(stringa)) { /* se si soddisfa il pattern, si inserisce nel file */ write(fd, stringa, strlen(stringa)); write(fd, &eol, 1); ; close (fd); Unix azioni primitive 15 Unix azioni primitive 16

ESEMPIO: Viene appeso ad un file (parametro del programma) il contenuto di un altro file. Quest'ultimo è lo standard input: possibilità di ridirezione File append.c #include <fcntl.h> #include <stdio.h> #define perm 0744 int DSSHQGILOH(f1) char *f1; { int outfile, nread; char buffer [BUFSIZ]; if ( (outfile = open ( f1, O_WRONLY)) < 0 ) DSHUWXUDLQVFULWWXUD { if (( outfile = creat ( f1, perm)) <0 ) VHLOILOHQRQHVLVWHYLHQHFUHDWR return (-1); else lseek (outfile, 0L, 2); VHLOILOHHVLVWHFLVLSRVL]LRQDDOODILQH while (( nread = UHDG (, buffer, BUFSIZ)) > 0 ) VLOHJJHGDOORVWDQGDUGLQSXW { if ( ZULWH(outfile, buffer, nread ) < nread ) { close (outfile); return (-2); /* errore scrittura */ /* fine del file di input */ close (outfile); return (0); /* NOTA: L apertura e la chiusura dello standard input (FD uguale a 0) sono a carico del Sistema Operativo */ PDLQ (argc, argv) int argc; char ** argv; { int integi; if (argc <= 1) /* controllo sul numero di argomenti */ { printf ("ERRORE: almeno un argomento \n"); exit (-3); integi = DSSHQGILOH (argv[1]); exit (integi); POSSIBILI INVOCAZIONI: C:> append fff abc def <CTRL-D> ===> si appende al file fff tutto ciò che si scrive da input C:> append fff < aaa ===> si appende al file fff tutto ciò che c'è nel file aaa Unix azioni primitive 17 Unix azioni primitive 18

ESEMPIO: IMPLEMENTAZIONE DEL COMANDO UNIX TEE tutti i caratteri dello standard input vanno nello standard output e nel file passato come parametro #include <fcntl.h> #include <stdio.h> #define perm 0744 main (argc, argv) int argc; char **argv; { char buff[bufsiz]; int nr, fd; if (argc!= 2) { printf ("Errore\n"); exit(-1); FRQWUROORGHOQXPHURGLSDUDPHWUL fd = creat(argv[1], perm); if (fd < 0) { printf ("Errore\n"); exit(-2); FRQWUROORVXOODFUHD]LRQH while ((nr=read(0, buff,bufsiz)) > 0) OHWWXUDGDOORVWDQGDUGLQSXW { write(1, buff, nr); VFULWWXUDVXOORVWDQGDUGRXWSXW write(fd, buff, nr); VFULWWXUDVXOILOH close (fd); ESEMPIO: IMPLEMENTAZIONE DEL COMANDO UNIX HEAD si filtrano in uscita le linee dello standard input a partire dall inizio nel numero specificato Prima soluzione: void main (argc, argv) int argc; char **argv; { int i, nr, n; char c; if (argc!= 2) { printf (" errore:\n Necessario 1 argomento per head"); exit (-1); else if (argv[1][0]!= - ) { printf (" errore:\n Necessario il simbolo di opzione"); exit (-2); else n = DWRL(&argv[1][1]); i = 1; while ((nr = read (0, &c, 1))!= 0) { if (c == \n ) i++; write(1, &c, 1); if (i > n) exit(0); INVOCAZIONE: head -30 < file Unix azioni primitive 19 Unix azioni primitive 20

Seconda soluzione: possibilità di DEFAULT void main (argc, argv) int argc; char **argv; { int i, nr, n; char c; if (argc > 2) { printf (" errore:\n Necessario 0 od 1 argomento"); exit (-1); else switch (argc) { case 2: if (argv[1][0]!= - ) { printf (" errore:\n Necessario il simbolo di opzione"); exit (-2); else n = atoi (&argv[1][1]); break; case 1:Q break; i = 1; while ((nr = read (0, &c, 1))!= 0) { if (c == \n ) i++; write(1, &c, 1); if (i > n) exit(0); INVOCAZIONI: head -30 < file head < file Terza soluzione: possibilità di indicare un file come argomento #include <fcntl.h> void main (argc, argv) int argc; char **argv; { int i, nr, n, fd; char c; int par = 0; char *op, *nf; if (argc > 3) { printf (" errore:\n Necessario 0, 1 od 2 argomenti"); exit (-1); else switch (argc) { case 3: op = argv[1]; nf = argv[2]; par = 1; if (op[0]!= - ) { printf ("errore:\n Necessario la opzione\n"); exit (-2); else n = atoi (op[1]); break; case 2: op = argv[1]; if (op[0]!= - ) { nf = op; n = 10; par = 1; else n = atoi (&(op[1])); break; case 1: n = 10; break; Unix azioni primitive 21 Unix azioni primitive 22

if (par == 1) { IG RSHQQI2B5'21/< if (fd == -1) { printf("errore\n FILE NON ESISTE\n"); exit(-3); else IG i = 1; while ((nr = read (IG, &c, 1))!= 0) { if (c == \n ) i++; if (i > n) write(1, &c, 1); VLOHJJHOLQSXWILQRDOOILQHGHOILOH INVOCAZIONI: head -30 < file head < file head -30 file head file PRIMITIVE si dicono primitive le azioni elementari della macchina virtuale UNIX con proprietà operazioni di base (con cui formare tutte le altre) operazioni atomiche (eseguite senza interruzione) operazioni protette (eseguite in ambiente di kernel) Le primitive sono visibili come normali procedure, ad esempio, invocabili da C Ma sono chiamate eseguite dal sistema operativo Implementativamente Una chiamata ad una read richiede il cambiamento di visibilità (allo stato kernel) e il trasferimento dei parametri viene espansa con un intermediario (stub) che tratta i parametri e chiede il passaggio al kernel con un trasferimento di controllo dinamico detto TRAP (operazione di basso livello: Assembler) registro x Stub in spazio utente x: parametri per la chiamata carica x system call READ INT SW istruzioni della system call READ return from INT IXQ]LRQHGLOLEUHULD VLVWHPDRSHUDWLYR Unix azioni primitive 23 Unix azioni primitive 24

UNIX OPERAZIONI di LINK e UNLINK 81/,1. retval= XQOLQN(name); char *name; int retval; Questa primitiva consente di cancellare (DISTRUGGERE) un file In realtà, come dice il suo nome, il suo compito è cancellare un link ===> nel caso in numero di link arrivi a ZERO allora si opera anche la DISTRUZIONE del file cioè la liberazione dello spazio su disco /,1. retval= OLQN(name1, name2); char *name1, name2; int retval; Questa primitiva consente di creare un nuovo NOME (un link) per un file esistente ===> viene incrementato il numero di link ESEMPIO: IMPLEMENTAZIONE DEL COMANDO UNIX MV (versione semplificata) main (argc, argv) int argc; char **argv; { if (argc!= 3) { printf ("Errore\n"); exit(-1); FRQWUROORGHOQXPHURGLSDUDPHWUL if (link(argv[1], argv[2]) < 0) { printf ("Errore\n"); exit(-2); FRQWUROORVXOODRSHUD]LRQHGLOLQN if (unlink(argv[1]) < 0) { printf ("Errore\n"); exit(-3); FRQWUROORVXOODRSHUD]LRQHGLXQOLQN printf ("Ok\n"); exit(0); Si considerino eventuali estensioni Tramite l'uso di queste due primitive viene realizzato, ad esempio, il comando mv di UNIX Unix azioni primitive 25 Unix azioni primitive 26

UNIX PRIMITIVE SUI DIRETTORI a) CAMBIO DI DIRETTORIO retval = FKGLU (nomedir); char *nomedir; int retval; Questa funzione restituisce 0 se successo (cioè il cambio di direttorio è avvenuto), altrimenti restituisce -1 (in caso di insuccesso) b) APERTURA DI DIRETTORIO #include <dirent.h> dir = RSHQGLU (nomedir); char *nomedir; DIR *dir; ',5qXQDVWUXWWXUDDVWUDWWDHQRQXVDELOHGDOOXWHQWH Questa funzione restituisce un valore diverso da NULL se ha successo (cioè l'apertura del direttorio è avvenuta), altrimenti restituisce NULL (in caso di insuccesso) c) CHIUSURA DI DIRETTORIO #include <dirent.h> FORVHGLU(dir); DIR *dir; Questa primitiva effettua la chiusura del direttorio d) LETTURA DI DIRETTORIO #include <sys/types.h> #include <dirent.h> descr = UHDGGLU (dir); DIR *dir; struct dirent *descr; La funzione restituisce un valore diverso da NULL se ha avuto successo (cioè a lettura del direttorio avvenuta), altrimenti restituisce NULL (in caso di insuccesso) In caso di successo, descr punta ad una struttura di tipo dirent struct GLUHQW { long d_ino; /* i_number */ off_t d_off; /* offset del prossimo */ unsigned short d_reclen; /* lunghezza del record */ unsigned short d_namelen; /* lunghezza del nome */ char d_name[1]; /* nome del file */ la stringa che parte da descr -> d_name rappresenta il nome di un file nel direttorio aperto Questa stringa termina con un carattere nullo (convenzione C) ===> possibilità di nomi con lunghezza variabile La lunghezza del nome è data dal valore di d_namelen Le primitive chdir, opendir, readdir e closedir sono INDIPENDENTI dalla specifica struttura interna del direttorio ===> valgono sia per Unix BSD che per Unix System V Unix azioni primitive 27 Unix azioni primitive 28

ESEMPIO: Implementazione del comando ls #include <sys/types.h> #include <dirent.h> #include <fcntl.h> my_dir (name) char *name; { DIR *dir; struct dirent * dd; int count = 0; dir = RSHQGLU (name); while ((dd = UHDGGLU(dir))!= NULL) { printf("trovato il file %s\n", dd-> d_name); count++; printf("numero totale di file %d\n", count); FORVHGLU (dir); return (0); main (argc, argv) int argc; char *argv[ ]; { if (argc <= 1) { printf("errore\n"); exit(-1); printf("esecuzione di mydir\n"); my_dir(argv[1]); exit(0); UNIX ESEMPIO: Si vuole operare su una gerarchia di DIRETTORI alla ricerca di un file con nome specificato Per ESPLORARE la gerarchia si utilizza la funzione per cambiare direttorio chdir e le funzioni opendir, readdir e closedir /* file dirfun.c */ #define NULL 0 #include <sys/types.h> #include <dirent.h> /* La soluzione seguente ASSUME che il nome del direttorio sia dato in modo ASSOLUTO. NOTA BENE: questa soluzione va bene se e solo se il direttorio di partenza non è la radice (/). PERCHÈ? */ void esplora (); main (argc, argv) int argc; char **argv; { if (argc!= 3) { printf (" errore\n "); exit (-1); if (chdir (argv[1])) exit(-2); esplora (argv[1], argv[2]); Unix azioni primitive 29 Unix azioni primitive 30

/* funzione di esplorazione di una gerarchia: opera in modo RICORSIVO */ void esplora (d, f) char *d, *f; { char nd [80]; DIR *dir; struct dirent *ff; GLU RSHQGLUG while ( ( (II UHDGGLUGLU)!= NULL) ) { if ( (strcmp (ff -> d_name, ".") == 0) (strcmp (ff -> d_name, "..") == 0) ) continue; ELVRJQDVDOWDUHLQRPLGHOGLUHWWRULRFRUUHQWHHGHOGLUHWWRULR SDGUH if (chdir(ff -> d_name)!= 0) qxqilohhqrqxqgluhwwrulr { if ( strcmp ( f, ff-> d_name) == 0) printf("trovato il file %s nel direttorio %s\n", f, d); /* HYHQWXDOLDOWULRSHUD]LRQLVXOILOH DGHVHPSLRDSHUWXUDHWF*/ else /* abbiamo trovato un direttorio */ { strcpy(nd, d); strcat(nd, "/"); strcat(nd, ff-> d_name); HVSORUDQGI chdir(".."); ELVRJQDWRUQDUHVXGLXQOLYHOOR SHUULWURYDUHLQRPLGHLILOH FORVHGLUGLU UNIX ESEMPIO: Si vuole operare su una gerarchia di DIRETTORI alla ricerca di un file con nome specificato Per ESPLORARE la gerarchia si utilizza la funzione per cambiare direttorio chdir IN QUESTO CASO SI DEVE: 1) O CONOSCERE LA STRUTTURA INTERNA DEL DIRETTORIO ===> Ad esempio: questa struttura è valida solo per UNIX/V che fissa una dimensione massima per la lunghezza dei nomi dei file GHILQH',56,= struct GLUHFW { ino_t d_ino; char d_name[dirsiz]; ATTENZIONE: se il nome è lungo 14 caratteri NON c'è il carattere di fine stringa ('\0'). ed usare le funzioni di accesso ai file open, read e close 2) O USARE FUNZIONI CHE ASTRAGGANO DALLA STRUTTURA INTERNA DEL DIRETTORIO ===> i programmi scritti sono indipendenti dalla struttura del file system Unix azioni primitive 31 Unix azioni primitive 32

La soluzione prevede la presenza di una funzione di nome findfiles il cui prototipo (che si trova nel file findfile.h) è: /* file findfile.h */ H[WHUQFKDUILQGILOHVFKDUG /* restituisce l'insieme dei nomi dei file (e direttori) del direttorio specificato ===> nasconde i dettagli relativi alla apertura, lettura e chiusura del file/direttorio */ NOTA: Il formato del valore ritornato da questa funzione è lo stesso di argv ed envp /* file dir.c */ /* La soluzione seguente ASSUME che il nome del direttorio di partenza della GERARCHIA sia dato in modo ASSOLUTO */ void esplora (); main (argc, argv) int argc; char **argv; { if (argc!= 3) { printf (" errore\n "); exit (-1); if (chdir (argv[1])) exit(-2); esplora (argv[1], argv[2]); /* funzione di esplorazione di una gerarchia: opera in modo RICORSIVO */ void esplora (d, f) char *d, *f; { char nd [80]; char **ff; II ILQGILOHVG UHVWLWXLVFH OD OLVWD GHL QRPL GHL ILOH H GLUHWWRUL GHO GLUHWWRULR VSHFLILFDWR while (*ff) { if (chdir(*ff)!= 0) qxqilohhqrqxqgluhwwrulr { if ( strcmp ( f, *ff) == 0) printf("trovato il file %s nel direttorio %s\n", f, d); else GLUHWWRULR { strcpy(nd, d); strcat(nd, "/"); strcat(nd, *ff); II HVSORUDQGI chdir(".."); Unix azioni primitive 33 Unix azioni primitive 34

ILOHILQGILOHF #define NULL 0 #include <fcntl.h> #include <sys/types.h> #include <dirent.h> #include <string.h> char ** findfiles (d) char *d; { nr, j, i=0; struct dirent * entrydir; DIR *dir; char tmp [DIRSIZ + 1]; char **reply; reply = malloc(100); dir = RSHQGLU(d); LOGLUHWWRULRqDSHUWR if (dir!= NULL) { puts("errore"); exit(-1); while ((entrydir = UHDGGLU (dir)))!= NULL) { if (!(strcmp (entrydir -> d_name, ".") == 0) &&!(strcmp (entrydir-> d_name, "..") == 0) ) { VLGHYRQRVDOWDUHLILOHHGLUHWWRULVSHFLDOL reply[i]=malloc(strlen(entrydir->d_name)); strcpy(reply[i], entrydir -> d_name); i++; reply[i] = NULL; /* indica la fine della lista */ FORVHGLU (dir); return reply; ALTRE PRIMITIVE UNIX 1) Creazione di un direttorio 0.',5 retval = PNGLU (pathname, mode); char * pathname; int mode; /* diritti sul direttorio */ int retval; La primitiva MKDIR crea un direttorio con il nome e i diritti specificati ===> vengono sempre creati i file. (link al direttorio corrente).. (link al direttorio padre) mkdir restituisce il valore 0 in caso di successo, altrimenti un valore negativo 2) Verifica sui diritti di accesso ad un file $&&(66 retval = DFFHVV(pathname, amode); char * pathname; int amode; int retval; La primitiva ACCESS consente di verificare il tipo di accesso consentito su un file Il parametro amode può essere: 04 read access; 02 write access 01 execute access; 00 existence access restituisce il valore 0 in caso di successo, altrimenti un valore negativo Unix azioni primitive 35 Unix azioni primitive 36

3) Verifica dello stato di un file 67$7 #include <sys/types.h> #include <sys/stat.h> retval = VWDW(pathname, &buff); char * pathname; struct stat buff; VWUXWWXUDFKHUDSSUHVHQWDLOGHVFULWWRUHGHOILOH int retval; )67$7 retval = IVWDW(fd, &buff); int fd; FSTAT può essere usato solo se il file è già aperto Entrambe le primitive, tornano il valore 0 in caso di successo, altrimenti un valore negativo Vediamo quali possono essere i campi della struct stat: struct VWDW { ushort st_mode; /* modo del file */ ino_t st_ino; /* I_ node number */ dev_t st_dev; /* ID del dispositivo */ dev_t st_rdev; /* solo per 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 */ ORGANIZZAZIONE FILE SYSTEM UNIX PARTE KERNEL Spazio UTENTE una entry per file aperto Tabella dei ),/($3(57, per ogni utente Spazio di SISTEMA,12'( un solo I-node per file Tabella dei ),/($77,9,,2SRLQWHU più entry per file Tabella dei ),/($3(57, nel FILE SYSTEM Dispositivi FISICI,QRGH file organizzazione su DISCO Spazio fisico sul DISPOSITIVO Unix azioni primitive 37 Unix azioni primitive 38

STRUTTURA FISICA DEL FILE SYSTEM Il disco viene suddiviso (formattato) in parti di dimensione fissa composti di blocchi fisici di lunghezza fissa in UNIX i blocchi sono passati da 512 a 4/8 kbyte boot-block "superblock" descrive il resto del disco "i-list" lista degli i-node Direttorio Un direttorio contiene per ogni file nomefile (non il cammino) i-number ".", i-numberdirettoriocorrente "..", i-numberdirettoriopadredeldircorrente ogni nome collegato in modo univoco all i-node del file ILOH KRPHDQWRQLR ILOH PLRGLU LOILOHGLUHWWRULRKRPHDQWRQLRFRQWLHQH blocchi occupati dai dati una lista dei blocchi liberi ILOH ILOH PLRGLU i-node LOLVW Cosa succede nel caso di link( file1, file3 )?? Unix azioni primitive 39 Unix azioni primitive 40

La struttura di un i-node per i dispositivi numero IDentificativo: numero maggiore driver di dispositivo (per una tabella di configurazione) numero minore quale dispositivo classe del dispositivo a blocchi / a caratteri Struttura di un i-node per file normali/direttori - tipo del file: (ordinario, direttorio o special file); - i bit SUID, SGID, e sticky ; - diritti read/write/execute per utente, gruppo e altri; RITROVARE i blocchi fisici del FILE I primi dieci indirizzi diretti L'undicesimo indirizzo è indiretto indirizzo di un area che contiene gli indirizzi dei blocchi 10+128 blocchi lunghezza: 70656 per 512 byte/blocco Il dodicesimo due livelli di indirettezza: lunghezza massima di file 10+128+128*128 blocchi Il tredicesimo tre livelli di indirettezza fino a Gbyte: 10+128+128*128+128*128*128 blocchi. Si favoriscono file di media lunghezza File di dimensioni teoricamente illimitata 0 1 - numero dei link del file; - identificatori user, group (UID e GID); - dimensione del file - indirizzi di tredici blocchi 10 11 12 Indirizzi Data blocks Unix azioni primitive 41 Unix azioni primitive 42

6SD]LR8WHQWH 3URFHVVR IG 7DEHOODGHL )LOH$SHUWL GHO3URFHVVR File System UNIX 6SD]LRGLVLVWHPD 7DEHOOD GHL)LOH $WWLYL,2SRLQWHU 7DEHOODGHL )LOH$SHUWL GL6LVWHPD 1 solo i-node per file LQRGH più entry per file 'LVSRVLWLYLILVLFL 0HPRULD GL0DVVD Tabelle globali: Tabella file attivi (i-node attivi) con un numero di entry pari al numero di file attivi Tabella dei file aperti, con una entry per ogni sessione di apertura di file (possibili più entry referenti lo stesso file) un puntatore al corrispondente i-node; un puntatore (I/0 pointer) punta al byte "corrente" del file a partire dal quale verranno effettuate le operazioni. L apertura di un file (system call open()) provoca: l allocazione di un elemento (individuato da un file descriptor) nella prima posizione libera della Tabella dei file aperti del processo l inserimento di un entry nella Tabella file aperti di sistema la copia del suo i-node nella tabella dei file attivi (se il file non è già stato aperto da un altro processo) Unix azioni primitive 43 Processi in UNIX In UNIX ogni attività è mappata in un processo (con le parti che abbiamo visto) e con uno spaziop di indirizzamento solo locale PROTEZIONE e CORRETTEZZA Modello di processi ad ambiente locale puro Eccezioni: il codice può essere condiviso il file system è suggerito per la condivisione P2 P2 P1 P1 P3 P3 File System Unix azioni primitive 44

CONDIVISIONE di FILE - aperture separate di uno stesso file portano condividere un sola entry della tabella degli i-node attivi, ma si avranno distinte entry nella tabella dei files aperti. Spazio di SISTEMA - Aperture di file di sottoprocessi dello stesso processo condividono la entry nella tabella dei files aperti, e anche la corrispondente entry nella tabella degli i-node attivi; lo stesso I/O pointer; Spazio di SISTEMA Spazio 87(17(,12'( Spazio 87(17(,12'( un solo I-node per file un solo I-node per file una entry per file aperto Tabella dei ),/($77,9, una entry per file aperto Tabella dei ),/($77,9, Tabella dei ),/($3(57,,2SRLQWHU Tabella dei ),/($3(57, per ogni utente per ogni utente,2srlqwhu Spazio 87(17(,2SRLQWHU Spazio 87(17( Tabella dei ),/($3(57, Tabella dei ),/($3(57, nel FILE SYSTEM nel FILE SYSTEM Unix azioni primitive 45 Unix azioni primitive 46

PROCESSI in UNIX TAVOLA dei 352&(66, nel SISTEMA Spazio di INDIRIZZAMENTO per ogni singolo 352&(662 il processo può riferire le sole SDUWLXWHQWH dati codice codice dati parte utente parte kernel 3URFHVV7DEOH Spazio di SISTEMA 3DUWH5HVLGHQWH 3DUWH6ZDSSDELOH Spazio UTENTE AREA DATI KERNEL Dati Stack UTENTE Dati Stack TAVOLA dei &2',&,&255(17, una entry per codice attivo 7H[W7DEOH AREA di CODICE Si noti che le tabelle di UNIX sono vettori di dimensioni fissate: non si può eccedere la dimensione MODI di esecuzione di un processo Un processo può eseguire in due modi diversi "processo di utente" (user process) "processo di sistema" (system process) in "modi" o stati: user, kernel La esecuzione delle primitive avviene in stato kernel BACKGROUND e FOREGROUND ancora due modi: - in modo interattivo (in the foreground) agganciato al terminale da cui provengono i comandi - in modo non interattivo (in the background) da shell & In un certo istante, un utente ad un terminale ha al più un processo di foreground può avere più processi di background Per processi background, stdin ridirezionato al file /dev/null Unix azioni primitive 47 Unix azioni primitive 48

Stati interni possibili di un processo UNIX: MODELLO DI PROCESSI IN UNIX Ogni processo ha un proprio spazio di indirizzamento completamente locale e non condiviso IDLE READY RUNNING SWAPPED stato iniziale pronto per la esecuzione in esecuzione immagine copiata su disco ====> MODELLO AD AMBIENTE LOCALE ECCEZIONI: * l'unica parte che si può condividere è il codice Il file system rappresenta un ambiente condiviso READY RUNNING IDLE SLEEPING TERMINATED C1 C2 SWAPPED ZOMBIE P1 P2 P3 P4 P5 SLEEPING TERMINATED ZOMBIE attesa di un evento per proseguire terminato terminato ma presentein attesa di consegna del risultato al padre che non ha aspettato il figlio ),/(6<67(0 Unix azioni primitive 49 Unix azioni primitive 50

Attributi di un Processo UNIX pid (process identifier) ppid (parent process identifier) pgid (process group id ) Un processo è lanciato da un utente, informazione di cui si tiene traccia in: real uid (real user identifier) real user gid (real user group identifier) che corrispondono allo uid e gid dell utente che ha lanciato il processo. Altre informazioni: environment (stringhe nome=valore) current working directory dimensione massima dei file creabili maschera dei segnali controlling terminal priorità processo (nice) PRIMITIVE PER LA GESTIONE DEI PROCESSI CREAZIONE )25. pid =IRUN ( ); int pid; Un processo ne genera un altro 2 processi concorrenti e indipendenti: - il parent (processo padre), quello originario - il child (processo figlio), quello generato. Processo 3DGUH...... printf( prima\n ); fork(); printf( dopo\n );...... PC Prima fork Dopo fork Processo 3DGUH...... printf( prima\n ); fork(); printf( dopo\n );...... PC Processo )LJOLR...... printf( prima\n ); fork(); printf( dopo\n );...... PC Unix azioni primitive 51 Unix azioni primitive 52

EFFETTI della FORK se la fork ha avuto successo (valore di ritorno >=0) in caso di errore la fork restituisce al parent valore -1 1- nuovo processo 2- duplica i dati e lo stack sia parte utente sia parte kernel; 3- stesso codice per padre e figlio Stessa tabella dei file aperti I file sono CONDIVISI come puntatore La fork restituisce l identificatore del processo creato (PID) al padre differenza tra i due processi nel child restituisce zero, nel parent un intero diverso da zero identificatore del child oltre al pid che è diverso per i processi SCHEMA di GENERAZIONE... if (fork()==0) {... /* codice eseguito dal FKLOG */... else { /* codice eseguito dal SDUHQW */... * variabili e i puntatori del parent sono copiati e non vengono condivisi da parent e child ma duplicati. * I file aperti dal processo sono condivisi condivisi anche i puntatori ai file usati per I/O I/O pointer si sposta per entrambi in seguito a letture o scritture eseguite da una famiglia di processi. Dopo la generazione del child il parent può decidere se operare contemporaneamente ad esso oppure se attendere la sua terminazione. Unix azioni primitive 53 Unix azioni primitive 54

:$,7 pid= ZDLW(&status); int status; Sincronizzazione tra padre e figlio int status; Processo 3$'5( )LOHGHVFULSWRU 0 if ((SLG IRUN) == 0) {... /* codice eseguito dal FKLOG */... else /* codice eseguito dal SDUHQW */... ZDLW VWDWXV; file1 file2 file3 In caso di più figli while ((rid = wait (&status)!= pid); OPERAZIONE DI WAIT La wait sospende in attesa della terminazione di un processo figlio 0 * sospensiva se ci sono processi child in esecuzione che devono terminare o interrotti. * Non sospensiva se tutti i processi figli sono terminati o se ci sono figli in attesa di un evento Processo ),*/,2 )LOHGHVFULSWRU I/O pointer unici = unica entry nella tabella file aperti Unix azioni primitive 55 Unix azioni primitive 56

Uso della WAIT /* il figlio scrive su un file; il padre torna all inizio e legge */ #include <stdio.h> #include <fcntl.h> int procfile (f1); char *f1; /* file di comunicazione */ {int nread, nwrite = 0, atteso, status, fileh, pid; char *st1 = " ", st2 [80]; if (( fileh = creat (f1, 0777)) < 0 ) return (-1); fileh = open (f1, O_RDWR); /* apertura in lettura/scrittura */ if ((pid = fork()) < 0) {close (fileh); return(-2); else if (pid == 0) /* FIGLIO */ {scanf ("%s\n", st1); nwrite = ZULWH (fileh, st1, strlen(st1)); exit (nwrite); else {atteso = ZDLW (&status); /* attesa del figlio */ OVHHN (fileh, 0L, 0); nread = UHDG (fileh, st2, 80); printf (" Il figlio ha avuto la stringa %s\n", st2); close (fileh); return (0); main (argc, argv)... { int integi; integi = procfile (temp1); exit (integi); Esecuzioni differenziate del padre e del figlio int status; if ((SLG IRUN) == 0) { /* codice eseguito dal FKLOG */ H[HFY ("bin/find", "find", "/usr/mydir", "-print", (char * 0); exit (-1); VLWRUQDVRORLQFDVRGLHUURUH... else { /* codice eseguito dal SDUHQW */ ZDLW VWDWXV VWDWXVFRQWLHQHQHOE\WHDOWRLOYDORUHSDVVDWRGDO ILJOLR printf ("exit di %d con%d\n", pid, status); Il figlio esegue immediatamente una exec e passa ad eseguire un altro programma si carica il nuovo codice, i nuovi dati e tutto lo stato del nuovo programma Si noti che il figlio non ritorna al suo stato precedente (GO TO) Unix azioni primitive 57 Unix azioni primitive 58

ESECUZIONE DI UN PROGRAMMA (primitiva EXEC) UNIX consente di cambiare l ambiente in cui il processo sta eseguendo usando la exec - NON si prevede di tornare al programma chiamante. - La primitiva non produce nuovi processi ma solo il cambiamento dell ambiente del processo interessato, sia come codice, sia come dati. Alcuni esempi di exec EXECL H[HFO(path, arg0, arg1,..., argn, (char *) 0); char *path, *arg0, *arg1,..., *argn; /* path è un pathname, assoluto o relativo*/ /* arg0 è il nome del file, seguono argomenti*/ EXECVE H[HFYH(name, argv, envp); char *name, *argv[], *envp[]; Il nuovo file può essere un file eseguibile o un file comandi per un interprete shell. Sono disponibili molte funzioni della famiglia exec: execl, execle, execlp, execv, execve, execvp p Ð la funzione prende un nome di file come argomento e lo cerca nei direttori specificati in PATH; l Ð la funzione riceve una lista di argomenti (NULL terminata); v Ð la funzione riceve un vettore argv[]; e Ð la funzione riceve anche un vettore envp[] invece di utlizzare l environment corrente. Altre conseguenze della execve: - i descrittori dei file aperti rimangono tali dopo la execve; NON è necessario riaprire i file: i FILE DESCRIPTOR sono ereditati IMPORTANTE è questo che rende possibile la ridirezione Unix azioni primitive 59 Unix azioni primitive 60

TERMINAZIONE di un processo modo volontario modo involontario VOLONTARIO - operazione primitiva "exit" o - alla conclusione del programma main; INVOLONTARIO a seguito di: - azioni non consentite (come riferimenti a indirizzi scorretti o tentativi di eseguire codici di operazioni non definite) - segnali generati dall utente da tastiera e ricevuti dal processo, oppure - segnali spediti da un altro processo tramite la system call kill. EXIT void H[LW(status); int status; La exit chiude tutti i file aperti, per il processo che termina Il valore ritornato viene passato al processo padre, se questo attende il processo che termina USO DI FORK ed EXEC Esecuzioni differenziate per padre e figlio main () { int pid; pid = IRUN(); if (pid == 0){ ILJOLR printf("esecuzione di ls\n"); H[HFO("/bin/ls", "ls", "-l", (char *)0); printf("errore in execl\n"); exit(1); if (pid > 0) { SDGUH ZDLW ((int *)0); printf("terminato ls\n"); exit (0); if (pid < 0) { IRUNIDOOLWD printf("errore in fork\n"); exit(1); Si noti che più processi con le primitive possono agire sugli stessi file insieme Unix azioni primitive 61 Unix azioni primitive 62

Evoluzione dei processi in UNIX Parentela Processi e Terminazione fork exec exec getty login shell PIDterminal1 PIDterminal1 PIDterminal1 Terminazione del Padre Padre init PIDinit fork... exec exec getty login shell PIDterminaln PIDterminaln PIDterminaln Figlio ppid figlio =1 Init pid=1 pid=1 Init eredita il Figlio Inizializzazione: il processo iniziale cura la fase iniziale e crea un processo shell per ogni terminale Terminazione del Figlio: Processi Zombie shell fork exec shell figlio comando utente PIDterminal1 PIDutente PIDutente continuazione/attesa terminazione Esecuzione in shell: il processo del terminale richiede dati e crea un processo per ogni comando Padre Figlio Attesa della wait del padre Zombie Unix azioni primitive 63 Unix azioni primitive 64

ESERCIZIO (esecuzione di comandi) Gestione degli errori In caso di fallimento, le System Call ritornano -1 #include <stdio.h> main (argc, argv) { int stato, atteso, pid; char st[80]; for (;;) { if ((pid = IRUN()) < 0) {perror("fork"); exit(1); In più, UNIX assegna alla variabile globale HUUQR il codice di errore occorso alla system call /usr/include/sys/errno.h per le corrispondenze codici di errori e loro descrizione (definire extern int errno nel programma) if (pid == 0) { /* FIGLIO: esegue i comandi */ printf("inserire il comando da eseguire:\n"); scanf ("%s", st); H[HFOS(st, (char *)0); perror("errore"); exit (0); else { /* PADRE */ atteso=zdlw (&stato); /*attesa figlio: VLQFURQL]]D]LRQH */ printf ("eseguire altro comando? (si/no) \n"); scanf ("%s", st); if (strcmp(st, "si") exit(0); SHUURU routine utilizzata nella gestione degli errori, stampa (su standard error) una stringa definita dall utente, seguita dalla descrizione dell errno avvenuto Esempio: perror( stringa descrittiva ); può stampare stringa descrittiva: No such file or directory Unix azioni primitive 65 Unix azioni primitive 66

Processi in UNIX I gruppi di processi 1 Tabella dei processi i PROCESS Spazio di sistema (residente) CODE Tabella dei codici Tabella dei file APERTI OPEN FILE ACTIVE FILE Tabella dei file ATTIVI Tutti i processi UNIX sono identificati dal pid e appartengono a un gruppo (identificato da pgid) L insieme di processi appartenenti a uno stesso gruppo è detto anche job esempio: antonio lia00 ~/ 10>P1 P2 P3 Spazio di utente (swappable) relativo ad un processo Spazio di utente (swappable) relativo ad un processo SURFHVV JURXSMRE Tabella dei file APERTI Ambiente PATH argc, argv USER STRUCTURE STACK DATI Stack per SYSTEM CALL Informazioni relative ai SIGNAL P1 leader pid=pgid P2 pid pgid P3 pid pgid In un gruppo di processi c è un solo group leader, che ha pid = pgid CODICE Le tabelle sono vettori di dimensioni fissate. processo di utente (user process) processo di sistema (system process) Un processo può trovarsi in due modi (stati) di esecuzione: user, kernel Shell senza Job Control (sh) La shell di login è il leader del gruppo e di sessione pid = pgid = sid Tutti i figli appartengono a questo gruppo e hanno lo stesso pgid e sid La esecuzione delle primitive avviene in stato kernel Unix azioni primitive 67 Unix azioni primitive 68

ESEMPIO $ sleep 10 & $ ps -xj PPID PID PGID TPGID COMMAND 29117 29118 29117 29117 sleep 10 1 29117 29117 29117 sh 29117 29119 29117 29117 ps-xj TPGID: pid processo leader gruppo foreground Ambienti SISTEMA OPERATIVO UNIX processore comandi (shell) linguaggio di sistema (C) 6HVVLRQH ps -xj sh sleep 10 *UXSSR session e group leader UNIX livelli utente programmatore processore comandi (shell) linguaggio di sistema (C) nucleo (primitive di sistema) Passaggio da un ambiente all altro $ ls -R sort more PPID PID PGID SID TPGID COMND 24643 24827 24827 24827 24827 sh 24827 24828 24827 24827 24827 more 24828 24829 24827 24827 24827 ls-r 24828 24830 24827 24827 24827 sort sh 24827 session e group leader fork sh 24828 foreground group fork fork exec sh 24829 more 24828 sh 24830 exec exec pipe ls -R 24829 pipe sort 24830 Uso di shell (fork) che crea un altro processo che fa una exec ed esegue in C fork exec wait exit passaggio argomenti e ambiente in avanti solo intero di ritorno Da C si crea un figlio e questo va ad eseguire in un file comandi shell Si noti lo stesso schema nei due casi Unix azioni primitive 69 Unix azioni primitive 70

Pipe strumento di comunicazione tra un solo processo produttore ed un solo processo consumatore I processi lavorano sulla pipe come se fosse un file (cioé con le primitive di accesso ai file) La pipe sincronizza le azioni produttore e consumatore un processo che legge da pipe si blocca a pipe vuota: il processo rimane in attesa di dati un processo che scrive su la pipe si blocca a pipe piena, in attesa di spazio libero PIPE retval = pipe(fd); int retval; int fd [2]; L array dei file descriptor, fd[0] e fd[1] sono destinati per la lettura e per la scrittura della pipe Il processo padre genera una pipe e la passa al figlio (ai figli) per l uso (anche tra loro) La pipe è associata ai file descriptor ai file descriptor non corrisponde un nome la dimensione di una pipe è fissa se i dati depositati dallo scrittore sono stati letti, la scrittura sulla pipe ricomincia all'inizio del file La memoria associata viene gestita come un buffer circolare da cui si preleva e su cui si deposita Esempio di pipe e generazione di processi Pipe aperta tra due processi in relazione di padre e figlio la condivisione dei file descriptor della pipe #include <stdio.h> #define MSGSIZE 23 LOWHUPLQDWRUHGHOOHVWULQJKHq? char *msg [10]= {" Salve. Messaggio #0", " Salve. Messaggio #1",...; main () { int j, pid; /* identità del figlio */ int piped[2]; char inpbuf [MSGSIZE]; FUHDODSLSH if (pipe (piped) < 0 ) { exit (1); &5($=,21(GHO),*/,2 if ((pid = fork()) < 0) exit (2); /* errore */ else if (pid!= 0) /* PADRE */ { close (piped [0]); /* chiusura della parte di lettura della pipe */ for (j =0; j < 10; j ++) write (piped[1], msg [j], MSGSIZE); wait ((int *)0); exit (0); /* si trascura il parametro di ritorno di stato */ else Unix azioni primitive 71 Unix azioni primitive 72

/* FIGLIO */ { close (piped [1]); /* chiusura della parte di scrittura della pipe */ for (j =0; j < 10; j ++) {read ( piped[0], inpbuf, MSGSIZE); printf ("%d :%s\n", j, inpbuf); exit (0); La pipe è aperta dal processo padre i file descriptor sono i primi liberi, il 3 e 4 SCHEMA di un PROCESSORE COMANDI #include "smallsh.h" #include <stdio.h> #define EOL 1 #define ARG 2 #define AMPERSAND 3 #define SEMICOLON 4 #define RIDIRIN 5 #define RIDIROUT 6 #define APPENDOUT 7 #define PIPE 8 0 1 2 3 4 Processo PADRE stdin stdout stderror piped[0] piped[1] (A) piped 3 4 0 1 2 3 4 Processo FIGLIO stdin stdout stderror piped[0] piped[1] 0 1 2 3 4 Processo PADRE stdin stdout stderror piped[0] piped[1] (B) piped 3 4 0 1 2 3 4 Processo FIGLIO stdin stdout stderror piped[0] piped[1] #define MAXARG 112 #define MAXBUF 112 #define FOREGROUND 0 #define BACKGROUND 1 #define MASK 777 char *prompt = "Comando>"; il processo figlio eredita i file descriptor del padre (A). Il padre chiude la parte di lettura della pipe ed il figlio chiude la parte di scrittura (B). Si chiudono tutti i file descriptor non necessari extern int userin(); extern void processalinea(); main () { while (XVHULQ(prompt)!= EOF) SURFHVVDOLQHD(); Unix azioni primitive 73 Unix azioni primitive 74

char LQSEXI [MAXBUF], /* buffer di ingresso */ WRNEXI [2*MAXBUF]; /* buffer per i token trovati */ int i, j; /* indici correnti nei buffer */ int XVHULQ (p) /* accetta i caratteri in ingresso */ char *p; { int c, count; printf ("%s ", p); i = j = count = 0; c = getchar (); while ((c!= \n ) && (count < MAXBUF) && (c!= EOF)) { inpbuf [count++] = c; c = getchar (); /* DFFXPXODLQLQSEXI */ if (count >= MAXBUF) { printf ("OLQHDWURSSROXQJD \n"); count = 0;inpbuf [count++] = \n ; inpbuf [count] = \0 ; return (count); ; if (c == EOF) return (EOF); if ((c == \n ) && (count < MAXBUF)) { inpbuf [count ++] = \n ; inpbuf [count] = \0 ; return (count); VLLQVHULVFRQRVLDLOILQHOLQHDVLDLOFDUDWWHUHGLILQH VWULQJD extern int inarg (); int JHWWRNHQ (outptr) char **outptr; SUHOHYDLFDUDWWHULGDOEXIIHUGLLQJUHVVRHOLWUDVIHULVFH QHOODUHDGLRXWSWU { int type; *outptr = &tokbuf[j]; /* togli EODQNVdal buffer di input */ while (inpbuf[i] == inpbuf[i] == \t ) i++; tokbuf[j++] = inpbuf[i]; switch (inpbuf[i++]) /* ULFRQRVFLPHQWRWRNHQ*/ { case \n : type = EOL; break; case & : type = AMPERSAND; break; case ; : type = SEMICOLON; break; case < : type = RIDIRIN; break; case > : if (inpbuf [i] == > ) { type = APPENDOUT; i++ ; break; else { type = RIDIROUT; break; case : type = PIPE; break; default: type = ARG; while (inarg(inpbuf[i])) tokbuf[j++] = inpbuf[i++]; LQDUJULFHUFDXQFDUDWWHUHVSHFLDOHULWRUQDYHUR SHUFDUDWWHULQRUPDOLIDOVRDOWULPHQWL tokbuf[j++] = \0 ; /* inserimento del fine stringa */ return (type); /* 3$56,1* */ Unix azioni primitive 75 Unix azioni primitive 76

static char VSHFLDO[] = {, \t, &, ;, <, >, \n, \0, ; FDUDWWHULFRQVLGHUDWLVSHFLDOLGDOORVKHOO int LQDUJ (c) char c; { char *wrk; for (wrk = special; *wrk!= \0 ; wrk++) if (c == *wrk) return (0); return (1); extern int UXQFRPDQGR (); static char *LQSILOH = "/dev/tty", /* nomi file input e output */ *RXWILOH = "/dev/tty"; static int DSSHQG = 0, /* necessità di appendere */ SLSHLQ = 0, /* pipe in ingresso */ SLSHRXW = 0; /* pipe in uscita */ void VHWILOH () LQL]LDOL]]DOHYDULDELOLGLVWDWRGHOFRPDQGR { inpfile = "/dev/tty"; outfile = "/dev/tty"; append = 0; pipein = pipeout = 0; int runcomando (); void SURFHVVDOLQHD () { char *arg[maxarg + 1]; DUUD\GLVWULQJKHFKH FRQWHQJRQROHSDUWLGHOFRPDQGR int narg; QXPHURGLDUJRPHQWL int toktype; WLSRGHOWRNHQ int type; %$&.*5281')25(*5281' toktype = ARG; /* inizializzazione */ type = FOREGROUND; narg = 0; while (toktype!= EOL) { DVHFRQGDGHOWLSRGLWRNHQRWWHQXWRHPHVVRLQDUJ switch (toktype = gettoken ( &arg [narg])) { int outfd; /* file descriptor per ULGLUH]LRQHLQXVFLWD */ int pipearray [2]; /* descrittori dei ILOHGHOODSLSH */ int i; case ARG: if (narg < MAXARG) narg ++; break; case RIDIRIN: gettoken (&inpfile); break; LQSILOHULSRUWDLOQRPHGHOILOHGLLQJUHVVR case RIDIROUT: gettoken (&outfile); outfd = creat (outfile, MASK); close (outfd); break; VLFUHDLOILOHLQXVFLWDLOVXRQRPHqLQRXWILOH Unix azioni primitive 77 Unix azioni primitive 78

case APPENDOUT: gettoken (&outfile); append = 1; break; RXWILOHULSRUWDLOQRPHGHOILOHLQDSSHQG case PIPE: pipe ( pipearray ); FUHD]LRQHGHOODSLSHODSULPDSDUWHGHOODSLSH YLHQHSDVVDWDDOFRPDQGRLQXVFLWD pipeout = pipearray [1]; arg [ narg] = NULL; UXQFRPDQGR (arg, type, pipein, pipeout); close (pipeout); if (pipein!= 0) close (pipein); ODVHFRQGDSDUWHGHOODSLSHSUHSDUDWDSHULO FRPDQGRVXFFHVVLYRFRPHLQJUHVVR pipein = pipearray [0]; narg = 0; break; case EOL: if (narg!= 0) { arg [narg] = NULL; UXQFRPDQGR (arg, type, pipein, NOARG); if (pipein!= 0) close (pipein); setfile (); VLUHVHWWDODHYHQWXDOHVLWXD]LRQHGLSLSH GHLSDVVLSUHFHGHQWL break; case SEMICOLON: if (narg!= 0) { arg [narg] = NULL; UXQFRPDQGR (arg, type, pipein, NOARG); if (pipein!= 0) close (pipein); setfile (); narg = 0; break; case AMPERSAND: type =%$&.*5281'; if (narg!= 0) { arg [narg] = NULL; UXQFRPDQGR (arg, type, pipein, NOARG); FRPDQGR LQ EDFNJURXQG XQD HYHQWXDOH SLSH YLHQH ULVSHWWDWD if (pipein!= 0) close (pipein); setfile (); narg = 0; break; Unix azioni primitive 79 Unix azioni primitive 80

int UXQFRPDQGR ( cline, where, ppipein, ppipeout) char **cline; int where; int ppipein, ppipeout; /* la runcomando esegue i comandi: RGLUHWWDPHQWH RJHQHUDQGRXQQXRYRSURFHVVRVKHOOSHUHVHJXLUH */ { int pid, exitst, returnst; int erroredup; WUDWWDPHQWRGLIIHUHQ]LDWRGHOFKDQJHGLUHFWRU\ if (strcmp (cline [0], "cd")== 0) { returnst = chdir (cline [1]); return (returnst); else WUDWWDPHQWRGLIIHUHQ]LDWRGHOORJRXWVLHVFHGDOORVKHOO { if (strcmp (cline [0], "lo") ==0) exit (); HYHQWXDOHWUDWWDPHQWRGLDOWULFRPDQGLGLDPELHQWH else { if ((pid = fork () ) < 0) HUURUHQHOODJHQHUD]LRQHGHOILJOLR { perror ("smallsh"); return (-1); if (pid == 0) ILJOLR { close (0); open (inpfile, 0);close (1); if (DSSHQG = 1) { open (outfile, 2); lseek (1, 0, 2); else open (outfile, 1); if (SSLSHRXW!= 0) { close (1); erroredup = dup (ppipeout); if (erroredup < 0) printf (" out 1 erroredup %d\n", erroredup); close (ppipeout); ; if (SSLSHLQ!= 0) { close (0); erroredup = dup (ppipein); if (erroredup < 0) printf (" in 2 erroredup %d\n", erroredup); close (ppipein); ; execvp (*cline, cline); perror (*cline); exit (127); Unix azioni primitive 81 Unix azioni primitive 82

LISLG SDGUH if (where == BACKGROUND ppipeout!= 0 ) /* in caso di background stampa pid ed esci */ { printf (" Process ID %d\n", pid); return (0); else { DWWHVDGHOSURFHVVRJHQHUDWRGDSDUWHGHOSDGUHVHqLOFDVR 6L DWWHQGH ILQR D FKH QRQ WHUPLQD LO SURFHVVR FKH q VWDWR JHQHUDWR while ((returnst = wait (&exitst))!= pid && returnst!= -1); return (returnst == -1? -1 : exitst); Esempi di filtri ESERCIZIO 1: FILTRO che passa nello standard output SOLO i caratteri dello standard input UGUALI AL CARATTERE passato come unico argomento #include <stdio.h> main (argc, argv) int argc; char **argv; { char c; if (argc!= 2) { printf ("Errore\n"); exit(-1); /* controllo del numero di parametri: cosa manca? */ while ( (c = getchar())!= EOF) if (c == argv[1][0]) putchar(c); ESERCIZIO 2: FILTRA in standard output SOLO i caratteri dello standard input DIVERSI dall argomento FDUDWWHUHDOIDEHWLFR #include <stdio.h> main (argc, argv) int argc; char **argv; { char c; if (argc!= 2) { printf ("Errore\n"); exit(-1); /* controllo del numero di parametri: cosa manca? */ Unix azioni primitive 83 while ( (c = getchar())!= EOF) if (c!= argv[1][0]) putchar(c); Unix azioni primitive 84