From: Simone Piccardi Date: Sun, 3 Jun 2001 21:05:07 +0000 (+0000) Subject: Fatta una bella passata di spell su tutto quanto ... X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=66765a9be9a61085dd00abd92d99a24b23dc844b;p=gapil.git Fatta una bella passata di spell su tutto quanto ... --- diff --git a/elemtcp.tex b/elemtcp.tex index 6707447..50d8994 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -1,7 +1,7 @@ \chapter{Socket TCP elementari} \label{cha:elem_TCP_sock} -In questo capitolo iniziamo ad approndire la conoscenza dei socket TCP, +In questo capitolo iniziamo ad approfondire la conoscenza dei socket TCP, tratteremo qui dunque il funzionamento delle varie funzioni che si sono usate nei due esempi elementari forniti in precedenza (vedi \secref{sec:net_cli_sample} e \secref{sec:net_serv_sample}), previa una @@ -27,11 +27,11 @@ significato di alcuni dei vari stati che il protocollo assume durante la vita di una connessione, che possono essere osservati per ciascun socket attivo con l'uso del programma \texttt{netstat}. -\subsection{La creazione della connessione: il \textit{three way handushake}} +\subsection{La creazione della connessione: il \textit{three way handshake}} \label{sec:TCPel_conn_cre} Il processo che porta a creare una connessione TCP è chiamato \textit{three - way handushake}; la successione tipica degli eventi (la stessa che si + way handshake}; la successione tipica degli eventi (la stessa che si verifica utilizzando il codice dei due precedenti esempi elementari \figref{fig:net_cli_code} e \figref{fig:net_serv_code}) che porta alla creazione di una connessione è la seguente: @@ -55,7 +55,7 @@ creazione di una connessione che implementa il protocollo) per realizzare la comunicazione, fra questi dati ci sono una serie di flag usati per gestire la connessione, come \texttt{SYN}, \texttt{ACK}, \texttt{URG}, \texttt{FIN}, alcuni di essi, - come \texttt{SYN} (che sta per \textit{sincronize}) corrispondono a + come \texttt{SYN} (che sta per \textit{syncronize}) corrispondono a funzioni particolari del protocollo e danno il nome al segmento, (per maggiori dettagli vedere \capref{cha:tcp_protocol})}, in sostanza viene inviato al server un pacchetto IP che contiene solo gli header IP e TCP (con @@ -125,15 +125,15 @@ regolare la connessione. Normalmente vengono usate le seguenti opzioni: \item \textit{MSS option} Sta per \textit{maximum segment size}, con questa opzione ciascun capo della connessione annuncia all'altro il massimo ammontare di dati che vorrebbe accettare per ciascun segmento nella - connesione corrente. È possibile leggere e scrivere questo valore attraverso + connessione corrente. È possibile leggere e scrivere questo valore attraverso l'opzione del socket \texttt{TCP\_MAXSEG}. \item \textit{window scale option} come spiegato in \capref{cha:tcp_protocol} il protocollo TCP implementa il controllo di flusso attraverso una \textsl{finestra annunciata} (\textit{advertized window}) con la quale ciascun capo della comunicazione dichiara quanto spazio disponibile ha in - memoria per i dati. Questo è un numero a 16 bit dell'haeader, che così può - indicare un massimo di 65535 bytes (anche se linux usa come massimo 32767 + memoria per i dati. Questo è un numero a 16 bit dell'header, che così può + indicare un massimo di 65535 bytes (anche se Linux usa come massimo 32767 per evitare problemi con alcuni stack bacati che usano l'aritmetica con segno per implementare lo stack TCP); ma alcuni tipi di connessione come quelle ad alta velocità (sopra i 45Mbits/sec) e quelle che hanno grandi @@ -159,13 +159,13 @@ La MSS protocollo, le ultime due opzioni (trattate nell'RFC 1323) sono meno comuni; vengono anche dette \textit{long fat pipe options} dato che questo è il nome che viene dato alle connessioni caratterizzate da alta velocità o da ritardi -elevati. In ogni caso linux supporta pienamente entrambe le opzioni. +elevati. In ogni caso Linux supporta pienamente entrambe le opzioni. \subsection{La terminazione della connessione} \label{sec:TCPel_conn_term} Mentre per creare una connessione occorre un interscambio di tre segmenti, la -procedura di chiusura ne richede quattro; ancora una volta si può fare +procedura di chiusura ne richiede quattro; ancora una volta si può fare riferimento al codice degli esempi \figref{fig:net_cli_code} e \figref{fig:net_serv_code}, in questo caso la successione degli eventi è la seguente: @@ -179,7 +179,7 @@ seguente: \item L'altro capo della connessione riceve il FIN ed esegue la \textit{chiusura passiva} (da \textit{passive close}); al FIN, come per tutti i pacchetti, viene risposto con un ACK. Inoltre il ricevimento del FIN - viene passato al processo che ha aperto il socket come un end of file sulla + viene passato al processo che ha aperto il socket come un end-of-file sulla lettura (dopo che ogni altro eventuale dato rimasto in coda è stato ricevuto), dato che il ricevimento di un FIN significa che non si riceveranno altri dati sulla connessione. @@ -195,7 +195,7 @@ seguente: Dato che in questo caso sono richiesti un FIN ed un ACK per ciascuna direzione normalmente i segmenti scambiati sono quattro; normalmente giacché in alcune -sitazioni il FIN del passo 1) è inviato insieme a dei dati. Comunque non è +situazioni il FIN del passo 1) è inviato insieme a dei dati. Comunque non è detto, anche se è possibile, che i segmenti inviati nei passi 2 e 3, siano accorpati in un singolo segmento. In \nfig\ si è rappresentato graficamente lo sequenza di scambio dei segmenti che stabilisce la connessione. @@ -225,7 +225,7 @@ in \figref{fig:net_cli_code}). Questo vuol dire ad esempio che se un processo viene terminato da un segnale tutte le connessioni aperte verranno chiuse. Infine è da sottolineare che, benché nella figura (e nell'esempio che vedremo -piu avanti in \secref{sec:TCPsimp_echo_example}) sia il client ad eseguire la +più avanti in \secref{sec:TCPsimp_echo_example}) sia il client ad eseguire la chiusura attiva, nella realtà questa può essere eseguita da uno qualunque dei due capi della comunicazione (come in fatto in precedenza da \figref{fig:net_serv_code}), e benché quello del client sia il caso più comune @@ -278,7 +278,7 @@ ad assumere per i due lati, server e client. \end{figure} La connessione viene iniziata dal client che annuncia un MSS di 1460 (un -valore tipico per IPv4 su ethernet) con linux, il server risponde con lo +valore tipico per IPv4 su ethernet) con Linux, il server risponde con lo stesso valore (ma potrebbe essere anche un valore diverso). Una volta che la connessione è stabilita il client scrive al server una @@ -340,7 +340,7 @@ tempo di vita, si stima che un pacchetto IP non possa restare nella rete per più di MSL secondi. Ogni implementazione del TCP deve scegliere un valore per la MSL (l'RFC1122 -raccomanda 2 minuti, linux usa 30 secondi), questo comporta una durata dello +raccomanda 2 minuti, Linux usa 30 secondi), questo comporta una durata dello stato \texttt{TIME\_WAIT} che a seconda delle implementazioni può variare fra 1 a 4 minuti. @@ -391,7 +391,7 @@ Se uno di questi pacchetti intrappolati non ricevendo risposta, provvederà alla ritrasmissione e se nel frattempo sarà stata stabilita una strada alternativa il pacchetto ritrasmesso giungerà a destinazione. Ma se dopo un po' di tempo (che non supera il limite dell'MSL) -l'anomalia viene a cessare il circolo di instadamento viene spezzato i +l'anomalia viene a cessare il circolo di instradamento viene spezzato i pacchetti intrappolati potranno essere inviati alla destinazione finale, con la conseguenza di avere dei pacchetti duplicati; questo è un caso che il TCP deve essere in grado di gestire. @@ -472,9 +472,9 @@ in tre intervalli: In realtà rispetto a quanto indicato nell'RFC1700 i vari sistemi hanno fatto scelte diverse per le porte effimere, in particolare in \nfig\ sono riportate -quelle di BSD, Solaris e linux. Nel caso di linux poi la scelta fra i due -intervali possibili viene fatta dinamicamente a seconda della memoria a -disposizione del kernel per gestire le rative tabelle. +quelle di BSD, Solaris e Linux. Nel caso di Linux poi la scelta fra i due +intervalli possibili viene fatta dinamicamente a seconda della memoria a +disposizione del kernel per gestire le relative tabelle. \begin{figure}[!htb] \centering @@ -512,10 +512,10 @@ campi \textit{Local Address} e \textit{Foreing Address}. Per capire meglio l'uso delle porte e come vengono utilizzate quando si ha a che fare con un'applicazione client/server (come quella che scriveremo in -\secref{sec:TCPel_cunc_serv}) esaminaremo cosa accade con le connessioni nel +\secref{sec:TCPel_cunc_serv}) esamineremo cosa accade con le connessioni nel caso di un server TCP che deve gestire connessioni multiple. -Se esguiamo un \texttt{netstat} su una macchina di prova (che supponiamo avere +Se eseguiamo un \texttt{netstat} su una macchina di prova (che supponiamo avere indirizzo 195.110.112.152) potremo avere un risultato del tipo: \begin{verbatim} Active Internet connections (servers and established) @@ -530,7 +530,7 @@ caching locale. Questo ci mostra ad esempio che il server ssh ha compiuto un'apertura passiva mettendosi in ascolto sulla porta 22 riservata a questo servizio e che si è posto in ascolto per connessioni provenienti da uno qualunque degli indirizzi -associati alle interfaccie locali; la notazione 0.0.0.0 usata da netstat è +associati alle interfacce locali; la notazione 0.0.0.0 usata da netstat è equivalente all'asterisco utilizzato per il numero di porta ed indica il valore generico, e corrisponde al valore \texttt{INADDR\_ANY} definito in \texttt{arpa/inet.h}. @@ -552,7 +552,7 @@ loopback. Una volta che ci si vorrà collegare a questa macchina da un'altra posta all'indirizzo 192.84.146.100 si potrà lanciare un client \texttt{ssh} per -creare una connessione verso la precedente, e il kernel associerà al suddetto +creare una connessione verso la precedente, e il kernel assocerà al suddetto una porta effimera che per esempio potrà essere la 21100, la connessione allora sarà espressa dalla socket pair $(192.84.146.100:21100, 195.110.112.152.22)$. @@ -576,7 +576,7 @@ il processo figlio gestisce la connessione mentre il padre resta in ascolto sul socket originale. Se a questo punto lanciamo un'altra volta il client ssh per una seconda -conessione quello che otterremo usando netstat sarà qualcosa del genere: +connessione quello che otterremo usando netstat sarà qualcosa del genere: \begin{verbatim} Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State @@ -678,7 +678,7 @@ socket, mentre per un server TCP questo restringer alle connessioni che arrivano verso tale indirizzo. Normalmente un client non specifica mai un indirizzo ad un suo socket, ed il -kernel sceglie l'indirizzo di orgine quando viene effettuata la connessione +kernel sceglie l'indirizzo di origine quando viene effettuata la connessione sulla base dell'interfaccia usata per trasmettere i pacchetti, (che dipende dalle regole di instradamento usate per raggiungere il server). Se un server non specifica il suo indirizzo locale il kernel userà come @@ -687,7 +687,7 @@ client. Per specificare un indirizzo generico con IPv4 si usa il valore \texttt{INADDR\_ANY}, il cui valore, come visto anche negli esempi precedenti -è pari a zero, nell'esempio \figref{fig:net_serv_sample} si è usata +è pari a zero, nell'esempio \figref{fig:net_serv_code} si è usata un'assegnazione immediata del tipo: \begin{verbatim} serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */ @@ -695,7 +695,7 @@ un'assegnazione immediata del tipo: Si noti che si è usato \texttt{htonl} per assegnare il valore \texttt{INADDR\_ANY}; benché essendo questo pari a zero il riordinamento sia -inutile; ma dato che tutte le constanti \texttt{INADDR\_} sono definite +inutile; ma dato che tutte le costanti \texttt{INADDR\_} sono definite secondo l'ordinamento della macchina è buona norma usare sempre la funzione \texttt{htonl}. @@ -748,7 +748,7 @@ connessione con un server TCP, il prototipo della funzione \item \texttt{EAFNOSUPPORT} l'indirizzo non ha una famiglia di indirizzi corretta nel relativo campo. \item \texttt{EACCESS, EPERM} si è tentato di eseguire una connessione ad un - indirizzo broacast senza che il socket fosse stato abilitato per il + indirizzo broadcast senza che il socket fosse stato abilitato per il broadcast. \end{errlist} \end{prototype} @@ -777,11 +777,11 @@ da errori o problemi nella chiamata della funzione sono le seguenti: dopo circa 180 secondi. % % Le informazioni su tutte le opzioni settabili via /proc stanno in -% linux/Documentation/networking/ip-sysctl.txt +% Linux/Documentation/networking/ip-sysctl.txt % \item Il client riceve come risposta al SYN un RST significa che non c'è nessun programma in ascolto per la connessione sulla porta specificata (il - che vuol dire probablmente che o si è sbagliato il numero della porta o che + che vuol dire probabilmente che o si è sbagliato il numero della porta o che non è stato avviato il server), questo è un errore fatale e la funzione ritorna non appena il RST viene ricevuto riportando un errore \texttt{ECONNREFUSED}. @@ -789,12 +789,12 @@ da errori o problemi nella chiamata della funzione sono le seguenti: Il flag RST sta per \textit{reset} ed è un segmento inviato direttamente dal TCP quando qualcosa non va. Tre condizioni che generano un RST sono: quando arriva un SYN per una porta che non ha nessun server in ascolto, - quando il TCP abortisce una connessione in corso, quandi TCP riceve un + quando il TCP abortisce una connessione in corso, quando TCP riceve un segmento per una connessione che non esiste. \item Il SYN del client provoca l'emissione di un messaggio ICMP di destinazione non raggiungibile. In questo caso dato che il messaggio può - essere dovuto ad una condizione transitoria si ripete l'emmissione dei SYN + essere dovuto ad una condizione transitoria si ripete l'emissione dei SYN come nel caso precedente, fino al timeout, e solo allora si restituisce il codice di errore dovuto al messaggio ICMP, che da luogo ad un \texttt{ENETUNREACH}. @@ -810,7 +810,7 @@ socket non Si noti infine che con la funzione \texttt{connect} si è specificato solo indirizzo e porta del server, quindi solo una metà della socket pair; essendo -questa funzione usata nei client l'altra metà contentente indirizzo e porta +questa funzione usata nei client l'altra metà contenente indirizzo e porta locale viene lasciata all'assegnazione automatica del kernel, e non è necessario effettuare una \texttt{bind}. @@ -856,10 +856,10 @@ infatti vengono mantenute due code: \begin{enumerate} \item Una coda delle connessioni incomplete (\textit{incomplete connection queue} che contiene un ingresso per ciascun socket per il quale è arrivato - un SYN ma il three-way handshake non si è ancora concluso. Questi socket + un SYN ma il three way handshake non si è ancora concluso. Questi socket sono tutti nello stato \texttt{SYN\_RECV}. \item Una coda delle connessioni complete (\textit{complete connection queue} - che contiene un ingresso per ciascun socket per il quale il three-way + che contiene un ingresso per ciascun socket per il quale il three way handshake è stato completato ma ancora \texttt{accept} non è ritornata. Questi socket sono tutti nello stato \texttt{ESTABLISHED}. \end{enumerate} @@ -868,7 +868,7 @@ Lo schema di funzionamento client il server crea una nuova entrata nella coda delle connessioni incomplete, e poi risponde con il SYN$+$ACK. La entrata resterà nella coda delle connessioni incomplete fino al ricevimento dell'ACK dal client o fino ad -un timeout. Nel caso di completamento del three-way handshake l'entrata viene +un timeout. Nel caso di completamento del three way handshake l'entrata viene sostata nella coda delle connessioni complete. Quando il processo chiama la funzione \texttt{accept} (vedi \secref{sec:TCPel_func_accept}) la prima entrata nella coda delle connessioni complete è passata al programma, o, se la @@ -879,9 +879,9 @@ Storicamente il valore del parametro \texttt{backlog} era corrispondente al massimo valore della somma del numero di entrate possibili per ciascuna di dette code. Stevens riporta che BSD ha sempre applicato un fattore di 1.5 al valore, e provvede una tabella con i risultati ottenuti con vari kernel, -compreso linux 2.0, che mostrano le differenze fra diverse implementazioni. +compreso Linux 2.0, che mostrano le differenze fra diverse implementazioni. -In linux il significato di questo valore è cambiato a partire dal kernel +In Linux il significato di questo valore è cambiato a partire dal kernel 2.2 per prevenire l'attacco chiamato \texttt{syn flood}. Questo si basa sull'emissione da parte dell'attaccante di un grande numero di pacchetti SYN indirizzati verso una porta forgiati con indirizzo IP fasullo\footnote{con la @@ -896,9 +896,9 @@ la \texttt{sysctl} o scrivendola direttamente in \texttt{/proc/sys/net/ipv4/tcp\_max\_syn\_backlog}. Quando si attiva la protezione dei syncookies però (con l'opzione da compilare nel kernel e da attivare usando \texttt{/proc/sys/net/ipv4/tcp\_syncookies}) questo valore -viene ignorato e non esiste più un valore massimo. In ogni caso in linux il +viene ignorato e non esiste più un valore massimo. In ogni caso in Linux il valore di \texttt{backlog} viene troncato ad un massimo di \texttt{SOMAXCONN} -se è superiore a detta constante (che di default vale 128). +se è superiore a detta costante (che di default vale 128). La scelta storica per il valore di questo parametro è di 5, e alcuni vecchi kernel non supportavano neanche valori superiori, ma la situazione corrente è @@ -915,12 +915,12 @@ compito principale della coda sia quello di gestire il caso in cui il server occupato fra chiamate successive alla \texttt{accept} (per cui la coda più occupata sarebbe quella delle connessioni completate), ma piuttosto quello di gestire la presenza di un gran numero di SYN in attesa di concludere il -three-way handshake. +three way handshake. Infine va messo in evidenza che nel caso di socket TCP quando un SYN arriva con tutte le code piene, il pacchetto deve essere ignorato. Questo perché la condizione in cui le code sono piene è ovviamente transitoria, per cui se il -client ristrasmette il SYN è probabile che passato un po' di tempo possa +client ritrasmette il SYN è probabile che passato un po' di tempo possa trovare nella coda lo spazio per una nuova connessione. Se invece si rispondesse con un RST per indicare l'impossibilità di effettuare la connessione la chiamata a \texttt{connect} nel client ritornerebbe con una @@ -979,13 +979,13 @@ viene messo in attesa. Il prototipo della funzione La funzione può essere usata solo con socket che supportino la connessione (cioè di tipo \texttt{SOCK\_STREAM}, \texttt{SOCK\_SEQPACKET} o \texttt{SOCK\_RDM}). Per alcuni protocolli che richiedono una conferma -esplicita della connessione, (attualmenente in linux solo DECnet ha questo +esplicita della connessione, (attualmente in Linux solo DECnet ha questo comportamento), la funzione opera solo l'estrazione dalla coda delle connessioni, la conferma della connessione viene fatta implicitamente dalla prima chiamata ad una \texttt{read} o una \texttt{write} mentre il rifiuto della connessione viene fatto con la funzione \texttt{close}. -E da chiarire che linux presenta un comportamento diverso nella gestione degli +È da chiarire che Linux presenta un comportamento diverso nella gestione degli errori rispetto ad altre implementazioni dei socket BSD, infatti la funzione \texttt{accept} passa gli errori di rete pendenti sul nuovo socket come codici di errore per \texttt{accept}. Inoltre la funzione non fa ereditare ai nuovi @@ -1038,7 +1038,7 @@ come chiuso e ritornare immediatamente al processo. Una volta chiamata il socket descriptor non è più utilizzabile dal processo e non può essere usato come argomento per una \texttt{write} o una \texttt{read} (anche se l'altro capo della connessione non avesse chiuso la sua parte). Il kernel invierà -comunque tutti i dati che ha in coda prima di inziare la sequenza di chiusura. +comunque tutti i dati che ha in coda prima di iniziare la sequenza di chiusura. Vedremo più avanti in \secref{sec:TCPadv_so_linger} come è possibile cambiare questo comportamento, e cosa deve essere fatto perché il processo possa @@ -1161,7 +1161,7 @@ Si noti come il figlio operi solo sul socket connesso, chiudendo immediatamente il socket \texttt{list\_fd}; mentre il padre continua ad operare solo sul socket in ascolto chiudendo \texttt{sock\_fd} dopo ciascuna \texttt{accept}. Per quanto abbiamo detto in \secref{sec:TCPel_func_close} -queste due chiusure non causano l'innesco della sequenza di chiusura perchè il +queste due chiusure non causano l'innesco della sequenza di chiusura perché il numero di riferimenti non si è annullato. Infatti subito dopo la creazione del socket \texttt{list\_fd} ha una @@ -1214,7 +1214,7 @@ l'indirizzo locale di un socket; ad esempio pu usualmente non chiama \texttt{bind}) per ottenere numero IP e porta locale associati al socket restituito da una \texttt{connect}, o da un server che ha chiamato \texttt{bind} su un socket usando 0 come porta locale per ottenere il -numero di porta effiemera assegnato dal kernel. +numero di porta effimera assegnato dal kernel. Inoltre quando un server esegue una \texttt{bind} su un indirizzo generico, se chiamata dopo il completamento di una connessione sul socket restituito da diff --git a/filedir.tex b/filedir.tex index c5f4675..8f64ac0 100644 --- a/filedir.tex +++ b/filedir.tex @@ -35,10 +35,10 @@ directory; l'albero viene appunto creato inserendo directory in altre directory. Il nome completo di file generico è composto da una serie di questi -\textsl{componenti} separati da una \texttt{/} (in linux più \texttt{/} +\textsl{componenti} separati da una \texttt{/} (in Linux più \texttt{/} consecutive sono considerate equivalenti ad una sola). Il nome completo di un file viene usualmente chiamato \textit{pathname}, e anche se il manuale della -glibc depreca questo nome (poichè genererebbe confusione, dato che con +glibc depreca questo nome (poiché genererebbe confusione, dato che con \textit{path} si indica anche un insieme di directory su cui effettuare una ricerca, come quello in cui si cercano i comandi) l'uso è ormai così comune che è senz'altro più chiaro dell'alternativa proposta. @@ -53,7 +53,7 @@ permessi devono consentire l'accesso. Se il pathname comincia per \texttt{/} la ricerca parte dalla directory radice del processo; questa, a meno di un \textit{chroot} (su cui torneremo in -seguito, vedi \secref{sec:proc_chroot}) è la stessa per tutti i processi ed +seguito, vedi \secref{sec:xxx_chroot}) è la stessa per tutti i processi ed equivale alla directory radice dell'albero (come descritto in \secref{sec:fileintr_overview}): in questo caso si parla di un pathname \textsl{assoluto}. Altrimenti la ricerca parte dalla directory corrente (su @@ -82,9 +82,9 @@ nel kernel) in \secref{sec:fileintr_vfs}. \subsection{Il funzionamento di un filesystem unix} \label{sec:filedir_filesystem} -Come già accennato in \secref{sec:fileintr_overview} linux (ed ogni unix in +Come già accennato in \secref{sec:fileintr_overview} Linux (ed ogni unix in generale) organizza i dati che tiene su disco attraverso l'uso di un -filesystem. Una delle caratteristiche di linux rispetto agli altri unix è +filesystem. Una delle caratteristiche di Linux rispetto agli altri unix è quella di poter supportare grazie al VFS una enorme quantità di filesystem diversi, ognuno dei quali ha una sua particolare struttura e funzionalità proprie; per questo non entreremo nei dettagli di un filesystem specifico, ma @@ -113,7 +113,7 @@ del tipo di quella esposta in \nfig. \caption{Organizzazione di un filesystem} \label{fig:filedir_filesys_detail} \end{figure} -da questa figura si evidenzano alcune caratteristiche su cui è bene porre +da questa figura si evidenziano alcune caratteristiche su cui è bene porre attenzione in quanto sono fondamentali per capire il funzionamento delle funzioni che manipolano i file e le directory su cui torneremo fra poco; in particolare è opportuno ricordare sempre che: @@ -188,7 +188,7 @@ particolare preferenza rispetto agli altri. Per aggiungere un nome ad un inode si utilizza la funzione \texttt{link}; si suole chiamare questo tipo di associazione un collegamento diretto (o -\textit{hard link}). Il prototipo della funzione e le sue caratteritiche +\textit{hard link}). Il prototipo della funzione e le sue caratteristiche principali, come risultano dalla man page, sono le seguenti: \begin{prototype}{unistd.h} {int link(const char * oldpath, const char * newpath)} @@ -238,7 +238,7 @@ richiamato in diverse directory. Per quanto dicevamo in \secref{sec:filedir_filesystem} la creazione del collegamento diretto è possibile solo se entrambi i pathname sono nello stesso -filesytem; inoltre il filesystem deve supportare i collegamenti diretti (non è +filesystem; inoltre il filesystem deve supportare i collegamenti diretti (non è il caso ad esempio del filesystem \texttt{vfat} di windows). La funzione opera sui file ordinari, come sugli altri oggetti del filesystem, @@ -247,7 +247,7 @@ un'altra directory, questo lo si fa perch dei circoli nel filesystem (vedi \secref{sec:filedir_symlink}) che molti programmi non sono in grado di gestire e la cui rimozione diventa estremamente complicata (in genere occorre far girare il programma \texttt{fsck} per -riparare il filesystem); data la sua pericolosità in linux questa +riparare il filesystem); data la sua pericolosità in Linux questa caratteristica è stata disabilitata, e la funzione restituisce l'errore \texttt{EPERM}. @@ -313,7 +313,7 @@ crash dei programmi; la tecnica \subsection{Le funzioni \texttt{remove} e \texttt{rename}} \label{sec:filedir_cre_canc} -Al contrario di quanto avviene con altri unix in linux non è possibile usare +Al contrario di quanto avviene con altri unix in Linux non è possibile usare \texttt{unlink} sulle directory, per cancellare una directory si può usare la funzione \texttt{rmdir} (vedi \secref{sec:filedir_dir_creat_rem}), oppure la funzione \texttt{remove}. Questa è la funzione prevista dallo standard ANSI C @@ -376,7 +376,7 @@ nuovo nome dopo che il vecchio Siccome la funzione \texttt{link} crea riferimenti agli inodes, essa può funzionare soltanto per file che risiedono sullo stesso filesystem, dato che in questo caso è garantita l'unicità dell'inode, e solo per un filesystem di -tipo unix. Inoltre in linux non è consentito eseguire un link diretto ad una +tipo unix. Inoltre in Linux non è consentito eseguire un link diretto ad una directory. Per ovviare a queste limitazioni i sistemi unix supportano un'altra forma di @@ -426,10 +426,10 @@ questa funzione \begin{prototype}{unistd.h} {int readlink(const char * path, char * buff, size\_t size)} - Legge il contnuto del link simbolico indicato da \texttt{path} nel buffer + Legge il contenuto del link simbolico indicato da \texttt{path} nel buffer \texttt{buff} di dimensione \texttt{size}. Non chiude la stringa con un carattere nullo e la tronca a \texttt{size} nel caso il buffer sia troppo - piccolo pe contenerla. + piccolo per contenerla. La funzione restituisce il numero di caratteri letti dentro \texttt{buff} o @@ -467,8 +467,8 @@ questa funzione \subsection{Le funzioni \texttt{chmod} e \texttt{fchmod}} \label{sec:filedir_chmod} -\subsection{Il flag \texttt{stiky}} -\label{sec:filedir_stiky} +\subsection{Il flag \texttt{sticky}} +\label{sec:filedir_sticky} \subsection{Le funzioni \texttt{chown}, \texttt{fchown} e \texttt{lchown}} \label{sec:filedir_chown} @@ -499,9 +499,9 @@ programma deve includere il file \texttt{sys/types.h}. \item \texttt{EACCESS} Non c'è il permesso di scrittura per la directory in cui si vuole inserire la nuova directory. - \item \texttt{EEXIST} Un file (o una directory) con quel nome essite di già. + \item \texttt{EEXIST} Un file (o una directory) con quel nome esiste di già. \item \texttt{EMLINK} La directory in cui si vuole creare la nuova directory - contiene troppi file. Sotto linux questo normalmente non avviene perchè il + contiene troppi file. Sotto Linux questo normalmente non avviene perché il filesystem standard consente la creazione di un numero di file maggiore di quelli che possono essere contenuti nell'hard-disk, ma potendo avere a che fare anche con filesystem di altri sistemi questo errore può presentarsi. @@ -516,7 +516,7 @@ programma deve includere il file \texttt{sys/types.h}. \subsection{Accesso alle directory} \label{sec:filedir_dir_read} -Benchè le directory siano oggetti del filesystem come tutti gli altri non ha +Benché le directory siano oggetti del filesystem come tutti gli altri non ha ovviamente senso aprirle come fossero dei file di dati. Può però essere utile poterne leggere il contenuto ad esempio per fare la lista dei file che esse contengono o ricerche sui medesimi. @@ -555,7 +555,7 @@ corrente. specificare un puntatore nullo come \textit{buffer}, nel qual caso la stringa sarà allocata automaticamente per una dimensione pari a \texttt{size} qualora questa sia diversa da zero, o della lunghezza esatta - del pathname altrimenti. In questo caso si deve ricordare di disallocara la + del pathname altrimenti. In questo caso si deve ricordare di disallocare la stringa una volta cessato il suo utilizzo. La funzione restituisce il puntatore \texttt{buffer} se riesce, @@ -566,7 +566,7 @@ corrente. è nullo. \item \texttt{ERANGE} L'argomento \texttt{size} è più piccolo della lunghezza del pathname. - \item \texttt{EACCES} Manca il permesso di lettura o di ricerca su uno dei + \item \texttt{EACCESS} Manca il permesso di lettura o di ricerca su uno dei componenti del pathname (cioè su una delle directory superiori alla corrente). \end{errlist} @@ -575,8 +575,8 @@ corrente. Di questa funzione esiste una versione \texttt{char * getwd(char * buffer)} fatta per compatibilità all'indietro con BSD, che non consente di specificare la dimensione del buffer; esso deve essere allocato in precedenza ed avere una -dimensione superiore a \texttt{PATH\_MAX} (di solito 256 byters, vedi -\secref{sec:xxx_limits}; il problema è che in linux non esiste una dimensione +dimensione superiore a \texttt{PATH\_MAX} (di solito 256 bytes, vedi +\secref{sec:xxx_limits}; il problema è che in Linux non esiste una dimensione superiore per un pathname, per cui non è detto che il buffer sia sufficiente a contenere il nome del file, e questa è la ragione principale per cui questa funzione è deprecata. @@ -594,7 +594,7 @@ per cambiare directory di lavoro. \begin{prototype}{unistd.h}{int chdir (const char * pathname)} Come dice il nome (che significa \textit{change directory}) questa funzione - serve a cambiare la directory di lavoro a quella speficata dal pathname + serve a cambiare la directory di lavoro a quella specificata dal pathname contenuto nella stringa \texttt{pathname}. \end{prototype} diff --git a/fileintro.tex b/fileintro.tex index c89f76b..a2735a7 100644 --- a/fileintro.tex +++ b/fileintro.tex @@ -11,11 +11,11 @@ Questo significa che si pu dalla seriale, alla parallela, alla console, e agli stessi dischi attraverso i cosiddetti file di dispositivo (i \textit{device files}). Questi sono dei file speciali agendo sui quali i programmi possono leggere, scrivere e compiere -operazioni direttamente sulle perferiche, usando le stesse funzioni che si +operazioni direttamente sulle periferiche, usando le stesse funzioni che si usano per i normali file di dati. In questo capitolo forniremo un'introduzione alle principali caratteristiche -di questa interfaccia, su come essa viene implementata in linux e su come sono +di questa interfaccia, su come essa viene implementata in Linux e su come sono organizzati i file nel sistema. @@ -66,20 +66,20 @@ oggetti visti attraverso l'interfaccia che manipola i files come le FIFO, i link, i socket e gli stessi i file di dispositivo (questi ultimi, per convenzione, sono inseriti nella directory \texttt{/dev}). -\subsection{Il \textit{virtual filesystem} di linux} +\subsection{Il \textit{virtual filesystem} di Linux} \label{sec:fileintr_vfs} -Esamineremo adesso come viene implementato l'accesso ai files in linux. Questa +Esamineremo adesso come viene implementato l'accesso ai files in Linux. Questa sezione riporta informazioni sui dettagli di come il kernel gestisce i files, ed è basata sul documento di Richard Goochs distribuito coi sorgenti del -kernel (\texttt{linux/Documentation/vfs.txt}). +kernel (nella directory \texttt{linux/Documentation/vfs.txt}). L'argomento è abbastanza ``esoterico'' e questa sezione può essere saltata ad una prima lettura; è bene però tenere presente che vengono introdotti qui alcuni termini che potranno comparire in seguito, come \textit{inode}, \textit{dentry}, \textit{dcache}. -In linux il concetto di \textit{everything is a file} è stato implementato +In Linux il concetto di \textit{everything is a file} è stato implementato attraverso il \textit{virtual filesystem} (da qui in avanti VFS) che è l'interfaccia astratta che il kernel rende disponibile ai programmi in user space attraverso la quale vengono manipolati i files; esso provvede anche @@ -201,7 +201,7 @@ proprietario, al gruppo, a tutti (una descrizione pi permessi associati ai file è riportata in \secref{sec:filedir_suid_sgid}). I restanti tre bit sono usati per indicare alcune caratteristiche più complesse (\textit{suid}, \textit{sgid}, e \textit{sticky}) su cui pure torneremo in -seguito (vedi \secref{sec:filedir_suid_sgid} e \secref{sec:filedir_stiky}). +seguito (vedi \secref{sec:filedir_suid_sgid} e \secref{sec:filedir_sticky}). Tutte queste informazioni sono tenute per ciascun file nell'inode. Quando un processo cerca l'accesso al file esso controlla i propri uid e gid @@ -256,16 +256,16 @@ accesso. Una delle differenze principali con altri sistemi operativi (come il VMS o Windows) è che per Unix tutti i file di dati sono identici e contengono un flusso continuo di bytes; non esiste cioè differenza per come vengono visti dal sistema file di diverso contenuto o formato (come nel caso di quella fra -file di testo e binari che c'è in windows) né c'è una strutturazione a record +file di testo e binari che c'è in Windows) né c'è una strutturazione a record per il cosiddetto ``accesso diretto'' come nel caso del VMS. % (con i kernel % della serie 2.4 è disponibile una forma di accesso diretto ai dischi il % \textit{raw access} che però non ha nulla a che fare con questo). -Una seconda differenza è nel formato dei file ascii; in Unix la fine riga è +Una seconda differenza è nel formato dei file ASCII; in Unix la fine riga è codificata in maniera diversa da Windows o MacIntosh, in particolare il fine riga è il carattere \texttt{LF} (o \verb|\n|) al posto del \texttt{CR} -(\verb|\r|) del mac e del \texttt{CR LF} di windows. Questo può causare alcuni +(\verb|\r|) del mac e del \texttt{CR LF} di Windows. Questo può causare alcuni problemi qualora si facciano assunzioni sul terminatore della riga. @@ -310,7 +310,7 @@ operazioni di controllo sul particolare tipo di oggetto del VFS scelto occorre usare l'interfaccia standard di unix coi file descriptors. Allo stesso modo devono essere usati i file descriptor se si vuole ricorrere a modalità speciali di I/O come il polling o il non-bloccante (vedi -\secref{sec:file_bohhhhh}). +\secref{sec:file_xxx}). Gli stream forniscono un'interfaccia di alto livello costruita sopra quella dei file descriptor, che tratta tutti i file nello stesso modo, con @@ -362,7 +362,7 @@ Questo ogni processo avrà la sua posizione corrente nel file, che non sarà influenzata da quello che altri processi possono fare. Anzi, aprire un file significa appunto creare ed inizializzare una tale struttura, per cui se si -apre due volte lo stesso file all'interno dello stesso processo, si otterrano +apre due volte lo stesso file all'interno dello stesso processo, si otterranno due file descriptor o due stream che avranno ancora una posizione corrente nel file assolutamente indipendente. diff --git a/filestd.tex b/filestd.tex index b854154..174ae98 100644 --- a/filestd.tex +++ b/filestd.tex @@ -1,4 +1,4 @@ -\chapter{I files: l'interfaccia standard C} +\chapter{I files: l'interfaccia standard ANSI C} \label{cha:files_std_interface} % @@ -37,7 +37,7 @@ nell'header \texttt{stdio.h} e sono: il processo invia ordinariamente i dati in uscita. Normalmente è associato dalla shell all'output del terminale e scrive sullo schermo. \item \texttt{FILE * stderr} Lo \textit{standard input} cioè lo stream su cui - il processo è supposto inviare i messaaggi di errore. Normalmente anch'esso + il processo è supposto inviare i messaggi di errore. Normalmente anch'esso è associato dalla shell all'output del terminale e scrive sullo schermo. \end{itemize} diff --git a/fileunix.tex b/fileunix.tex index aa85117..2aeda78 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -48,7 +48,7 @@ L'interfaccia standard unix per l'input/output sui file \subsection{La funzione \texttt{fcntl}} \label{sec:fileunix_fcntl} -\subsection{La funzione \texttt{fcntl}} +\subsection{La funzione \texttt{ioctl}} \label{sec:fileunix_ioctl} diff --git a/intro.tex b/intro.tex index a65d72d..4e8dd69 100644 --- a/intro.tex +++ b/intro.tex @@ -1,10 +1,10 @@ \chapter{Introduzione} \label{cha:intro_unix} -In questo primo capitolo sarà fatta un'introduzione ai contetti generali su +In questo primo capitolo sarà fatta un'introduzione ai concetti generali su cui è basato un sistema di tipo unix, per fornire una base di comprensione -mirata a sottolinearne le peculiarità che saranno poi importanti per quello -che rigarda la programmazione; in particolare faremo una panoramica sulla +mirata a sottolineare le peculiarità che saranno poi importanti per quello +che riguarda la programmazione; in particolare faremo una panoramica sulla struttura di un sistema \textit{unix-like} come Linux. Chi avesse già una conoscenza di questa materia può tranquillamente saltare @@ -13,15 +13,15 @@ il capitolo. \section{La struttura di un sistema Unix} \label{sec:intro_unix_struct} -Il concetto base di unix é quello di un nucleo del sistema (il cosiddetto -\textit{kernel}) a cui si demanda la gestione delle risorse essenziali (la -CPU, la memoria, le periferiche); mentre tutto il resto, quindi anche la parte -che prevede l'interazione con l'utente, deve venire realizzato tramite -programmi eseguiti dal kernel e che accedano alle risorse hardware tramite -delle richieste a quest'ultimo. +Il concetto base di un sistema unix-like é quello di un nucleo del sistema (il +cosiddetto \textit{kernel}) a cui si demanda la gestione delle risorse +essenziali (la CPU, la memoria, le periferiche) mentre tutto il resto, quindi +anche la parte che prevede l'interazione con l'utente, deve venire realizzato +tramite programmi eseguiti dal kernel e che accedano alle risorse hardware +tramite delle richieste a quest'ultimo. Fin dall'inizio unix si presenta come un sistema operativo -\textit{multitasking}, cioé in grado di eseguire contemporaneamente più +\textit{multitasking}, cioè in grado di eseguire contemporaneamente più programmi, e multiutente, in cui é possibile che più utenti siano connessi ad una macchina eseguendo più programmi ``in contemporanea'' (in realtà, almeno per macchine a processore singolo, i programmi vengono eseguiti singolarmente @@ -32,59 +32,58 @@ a rotazione). %computer (e quindi per un uso personale), sui quali l'hardware (allora %limitato) non consentiva la realizzazione di un sistema evoluto come uno unix. -Gli unix più recenti, come linux, sono stati realizzati usando alcune +Gli unix più recenti, come Linux, sono stati realizzati usando alcune caratteristiche dei processori moderni come la gestione hardware della memoria e la modalità protetta. In sostanza con i processori moderni si può disabilitare temporaneamente l'uso di certe istruzioni e l'accesso a certe zone di memoria fisica. Quello che succede é che il kernel é il solo programma ad essere eseguito in modalità privilegiata, con il completo accesso all'hardware, mentre i programmi normali vengono eseguiti in modalità protetta -(e non possono accedere direttamente alle zone di memoria riservate, al kernel +(e non possono accedere direttamente alle zone di memoria riservate o alle porte di input/output). Una parte del kernel, lo \textit{scheduler}, si occupa di stabilire, ad intervalli fissi e sulla base di un opportuno calcolo delle priorità, quale ``processo'' (vedi \capref{cha:process}) deve essere posto in esecuzione (il -cosidetto \textit{prehemptive scheduling}), e questo verrà comunque eseguito -in modelità protetta; quando necessario il processo potrà accedere alle +cosiddetto \textit{prehemptive scheduling}). Questo verrà comunque eseguito +in modalità protetta; quando necessario il processo potrà accedere alle risorse hardware soltanto attraverso delle opportune chiamate al sistema (\textit{system call}) con un'interfaccia ben definita e standardizzata che restituiranno il controllo al kernel. La memoria viene sempre gestita del kernel attraverso il meccanismo della memoria virtuale, che consente di assegnare a ciascun processo uno spazio di -indirizzi ``virtuale'' che il kernel stesso, con l'ausilio della unità di -gestione della memoria, si incaricherà di rimappare automaticamente sulla -memoria disponibile, salvando su disco (nella cosiddetta \textit{swap}) quando -necessario le pagine di memoria in eccedenza. +indirizzi ``virtuale'' (vedi \secref{sec:proc_memory}) che il kernel stesso, +con l'ausilio della unità di gestione della memoria, si incaricherà di +rimappare automaticamente sulla memoria disponibile, salvando quando +necessario su disco (nella cosiddetta \textit{swap}) le pagine di memoria in +eccedenza. Le periferiche infine vengono viste in genere attraverso un'interfaccia -astratta che permette di trattarle come fossero file. secondo il concetto per -cui \textit{everything is a file}, vedi \capref{cha:files_intro}, (questo -non è vero per le interfacce di rete, ma resta valido il concetto generale che -tutto il lavoro di accesso e gestione a basso livello è effettuato dal -kernel), mentre ai programmi vengono fornite solo delle routine di -interfacciamento; essendo l'argomento principale di cui tratteremo, di esse -parleremo in abbondanza nei capitoli successivi. +astratta che permette di trattarle come fossero file, secondo il concetto per +cui \textit{everything is a file}, vedi \capref{cha:files_intro}, (questo non +è vero per le interfacce di rete, che hanno un'interfaccia diversa, ma resta +valido il concetto generale che tutto il lavoro di accesso e gestione a basso +livello è effettuato dal kernel). \section{User space e kernel space} \label{sec:intro_userkernel} -Questa architettura fa sì che nei sistemi unix esista una distinzione -essenziale fra il cosiddetto \textit{user space}, che contraddistingue -l'ambiente in cui vengono eseguiti i programmi, e il \textit{kernel space} che -é l'ambiente in cui viene eseguito il kernel. Ogni programma gira come se -avesse la piena disponibilità della macchina e della memoria ed è, salvo i -meccanismi di comunicazione previsti dall'architettura (che esamineremo nel -\capref{cha:IPC}) completamente ignaro del fatto che altri programmi possono -essere messi in esecuzione dal kernel. - -In questo non è possibile ad un singolo programma disturbare l'azione di un -altro programma o del sistema e questo è il principale motivo della stabilità -di un sistema unix nei confronti di altri sistemi in cui i processi non hanno -di questi limiti, o che vengono per vari motivi eseguiti al livello del -kernel. +L'architettura appena descritta fa sì che nei sistemi unix esista una +distinzione essenziale fra il cosiddetto \textit{user space}, che +contraddistingue l'ambiente in cui vengono eseguiti i programmi, e il +\textit{kernel space} che é l'ambiente in cui viene eseguito il kernel. Ogni +programma vede se stesso come se avesse la piena disponibilità della CPU +e della memoria ed è, salvo i meccanismi di comunicazione previsti +dall'architettura (che esamineremo nel \capref{cha:IPC}) completamente ignaro +del fatto che altri programmi possono essere messi in esecuzione dal kernel. + +Per questa separazione non è possibile ad un singolo programma disturbare +l'azione di un altro programma o del sistema e questo è il principale motivo +della stabilità di un sistema unix nei confronti di altri sistemi in cui i +processi non hanno di questi limiti, o che vengono per vari motivi eseguiti al +livello del kernel. Pertanto deve essere chiaro a chi programma in unix che l'accesso diretto all'hardware non può avvenire se non all'interno del kernel, al di fuori dal @@ -108,9 +107,9 @@ standard internazionale POSIX1003.a(?)) che sono comuni a tutti gli unix. \label{sec:intro_kernandlib} Per capire meglio la distinzione fra kernel space e user space si può prendere -in esame la procedura di avvio di un sistema unix; all'avvio il bios (o in -generale il software di avvio posto nelle eprom) eseguirà il \textit{boot} -incarichandosi di caricare il kernel in memoria e di farne partire +in esame la procedura di avvio di un sistema unix; all'avvio il BIOS (o in +generale il software di avvio posto nelle EPROM) eseguirà il \textit{boot} +incaricandosi di caricare il kernel in memoria e di farne partire l'esecuzione; quest'ultimo, dopo aver inizializzato le periferiche farà partire il primo processo, \textit{init} che è quello che si incaricherà di far partire tutti i processi successivi, come quello che si occupa di @@ -125,7 +124,7 @@ programma di scrittura o di disegno, in user space. Questo significa ad esempio che il sistema di per sé non dispone di primitive per tutta una serie di operazioni (come la copia di un file) che altri sistemi -(come windows) hanno invece al loro interno. Per questo può capitare che +(come Windows) hanno invece al loro interno. Per questo può capitare che alcune operazioni, come quella in esempio, siano implementate come normali programmi. @@ -140,12 +139,12 @@ programmi di utilit si aspetta da un sistema operativo. Questo è importante anche dal punto di vista della programmazione, infatti -programmare in linux significa anzitutto essere in grado di usare la Libreria +programmare in Linux significa anzitutto essere in grado di usare la Libreria Standard del C, in quanto né il kernel né il linguaggio C implementano direttamente operazioni comuni come la gestione della memoria, l'input/output o la manipolazione delle stringhe presenti in qualunque programma. -Per questo in linux una parte essenziale del sistema (senza la quale nulla +Per questo in GNU/Linux una parte essenziale del sistema (senza la quale nulla funziona) è la realizzazione fatta dalla FSF della suddetta libreria (la \textit{glibc}), in cui sono state implementate tutte le funzioni essenziali definite negli standard POSIX e ANSI C, che viene utilizzata da qualunque @@ -162,7 +161,7 @@ monoutente. Il concetto base è quello di utente (\textit{user}) del sistema, utente che ha dei ben definiti limiti e capacità rispetto a quello che può fare. Sono così -previsti una serie di meccanismi per identificare i singoli utenti ed uan +previsti una serie di meccanismi per identificare i singoli utenti ed una serie di permessi e protezioni per impedire che utenti diversi possano danneggiarsi a vicenda o danneggiare il sistema. diff --git a/macro.tex b/macro.tex index 9feadaa..bff8918 100644 --- a/macro.tex +++ b/macro.tex @@ -9,14 +9,17 @@ % Figure commands % \newcommand{\curfig}{fig.~\thefigure} + \newcommand{\nfig}{% \setcounter{usercount}{\value{figure}}% \addtocounter{usercount}{1}% fig.~\thechapter.\theusercount} + \newcommand{\pfig}{% \setcounter{usercount}{\value{figure}}% \addtocounter{usercount}{-1}% fig.~\thechapter.\theusercount} + \newcommand{\figref}[1]{fig.~\ref{#1}} % % Tables commands diff --git a/main.tex b/main.tex index 3f3861d..0a2977c 100644 --- a/main.tex +++ b/main.tex @@ -2,7 +2,7 @@ %% GaPiL : Guida alla Programmazione in Linux %% %% S. Piccardi Feb. 2001 -%% +%% %% main.tex: file principale, gli altri vanno inclusi da questo. %% \documentclass[a4paper,11pt,twoside,italian]{book} diff --git a/network.tex b/network.tex index a1c04b7..fc5113d 100644 --- a/network.tex +++ b/network.tex @@ -1,7 +1,7 @@ \chapter{Introduzione alla programmazione di rete} \label{cha:network} -In questo capitolo sarà fatta un'introduzione ai contetti generali che servono +In questo capitolo sarà fatta un'introduzione ai concetti generali che servono come prerequisiti per capire la programmazione di rete, per evitare un capitolo puramente teorico partiremo con due semplici esempi per poi passare ad un esame a grandi linee dei protocolli di rete e di come questi sono @@ -62,7 +62,7 @@ estensivamente pi In \nfig\ è riportata la sezione principale del codice del nostro client elementare per il servizio \textit{daytime}, un servizio standard che -restituisce l'ora locale della macchina a cui si effettua la richesta. +restituisce l'ora locale della macchina a cui si effettua la richiesta. \begin{figure}[!htb] @@ -124,7 +124,7 @@ int main(int argc, char *argv[]) Il sorgente completo del programma (\texttt{SimpleDaytimeTCPClient.c}, che comprende il trattamento delle opzioni e una funzione per stampare un messaggio di aiuto) è allegato alla guida nella sezione dei codici sorgente e -può essere compilato su una qualunque macchina linux. +può essere compilato su una qualunque macchina Linux. Il programma anzitutto include gli header necessari (\texttt{\small 1--5}); dopo la dichiarazione delle variabili (\texttt{\small 9--12}) si è omessa @@ -151,7 +151,7 @@ comando. Usando la funzione \texttt{connect} sul socket creato in precedenza (\texttt{\small 28--32}) si provvede poi a stabilire la connessione con il -server specificato dall'indirizzo immesso nella struttura possata come secondo +server specificato dall'indirizzo immesso nella struttura passata come secondo argomento, il terzo argomento è la dimensione di detta struttura. Dato che esistono diversi tipi di socket, si è dovuto effettuare un cast della struttura inizializzata in precedenza, che è specifica per i socket IPv4. Un @@ -290,7 +290,7 @@ nuovo socket viene chiuso (\texttt{\small 54}). Il tutto è inserito in un loop infinito (\texttt{\small 42--55}) in modo da poter ripetere l'invio della data ad una successiva connessione. -È impostante notare che questo server è estremamente elementare, infatti a +È importante notare che questo server è estremamente elementare, infatti a parte il fatto di essere dipendente da IPv4, esso è in grado di servire solo un client alla volta, è cioè un \textsl{server iterativo}, inoltre esso è scritto per essere lanciato da linea di comando, se lo si volesse utilizzare @@ -354,8 +354,8 @@ della Difesa Americano. \begin{figure}[!htbp] \centering - \caption{Struttura a livelli dei protocolli OSi e TCP/IP, con la - relative corrispondeze e la divisione fra kernel e user space.} + \caption{Struttura a livelli dei protocolli OSI e TCP/IP, con la + relative corrispondenze e la divisione fra kernel e user space.} \label{fig:net_osi_tcpip_comp} \end{figure} @@ -384,7 +384,7 @@ operativo rispetto alla divisione fra user space e kernel space spiegata in device driver \& scheda di interfaccia \\ \hline \end{tabular} -\caption{I quattro livelli del protocollo TPC/IP.} +\caption{I quattro livelli del protocollo TCP/IP.} \label{tab:net_layers} \end{table} @@ -396,7 +396,7 @@ compongono, il TCP \textit{Trasmission Control Protocol} e l'IP \begin{description} \item \textbf{Applicazione} É relativo ai programmi di interfaccia utente, in - genere questi vengono realizzati secondo il modello Client-Server (vedi + genere questi vengono realizzati secondo il modello client-server (vedi \secref{sec:net_cliserv}. \item \textbf{Trasporto} Fornisce la comunicazione tra le due stazioni terminali su cui girano gli applicativi, regola il flusso delle @@ -435,7 +435,7 @@ opportuna (i \textit{socket}, che esamineremo in dettaglio in seguito), i quali li spezzerà in pacchetti di dimensione opportuna e li incapsulerà all'interno del suo protocollo di trasporto aggiungendo ad ogni pacchetto le informazioni necessarie alla gestione di quest'ultimo. Questo processo viene -svolto dirattamente nel kernel ad esempio dallo stack TCP nel caso il +svolto direttamente nel kernel ad esempio dallo stack TCP nel caso il protocollo di trasporto sia questo. Una volta composto il pacchetto nel formato adatto al protocollo di trasporto @@ -510,7 +510,7 @@ della rete a basso livello, un uso quindi molto specialistico, e che non rientra in quanto trattato qui. In questa sezione daremo una breve descrizione dei vari protocolli di TCP/IP, -concentrandoci per le ragioni esposte sul livello di trasposto. All'interno di +concentrandoci per le ragioni esposte sul livello di trasporto. All'interno di questo privilegeremo poi il protocollo TCP, per il ruolo centrale che svolge nella maggior parte delle applicazioni. @@ -518,7 +518,7 @@ nella maggior parte delle applicazioni. Benché si parli di TCP/IP questa famiglia di protocolli è composta anche da altri membri. In \nfig\ si è riportato uno schema che mostra un panorama sui -vari prottocolli della famiglia, e delle loro relazioni reciproche e con +vari protocolli della famiglia, e delle loro relazioni reciproche e con alcune dalle principali applicazioni che li usano. \begin{figure}[!htbp] @@ -533,7 +533,7 @@ I vari protocolli mostrati in figura sono i seguenti: \begin{list}{}{} \item \textsl{IPv4} \textit{Internet Protocol version 4}. È quello che comunemente si chiama IP. Ha origine negli anni '80 e da allora è la base su - cui è cotriuta internet. Usa indirizzi a 32 bit e provvede la trasmissione + cui è costruita internet. Usa indirizzi a 32 bit e provvede la trasmissione dei pacchetti TCP, UDP, ICMP e IGMP. \item \textsl{IPv6} \textit{Internet Protocol version 6}. È stato progettato a metà degli anni '90 per rimpiazzare IPv4. Ha indirizzi a 128 bit e effettua @@ -624,7 +624,7 @@ grandi linee nei seguenti punti: \item la semplificazione del formato della testata, eliminando o rendendo opzionali alcuni dei campi di IPv4, per eliminare la necessità di riprocessamento della stessa da parte dei router e contenere l'aumento di - dimensione dovuto all'ampiamento degli indirizzi + dimensione dovuto all'ampliamento degli indirizzi \item un supporto per le opzioni migliorato, per garantire una trasmissione più efficiente del traffico normale, limiti meno stringenti sulle dimensioni delle opzioni, e la flessibilità necessaria per introdurne di nuove in @@ -642,7 +642,7 @@ protocollo IP sono forniti nell'appendice \capref{cha:ip_protocol}. \subsection{UDP: User Datagram Protocol)} \label{sec:net_udp} -UDP è un protocollo di trasporto molto semplice, la sua descizione completa è +UDP è un protocollo di trasporto molto semplice, la sua descrizione completa è contenuta dell'RFC~768, ma in sostanza esso è una semplice interfaccia a IP dal livello di trasporto. Quando un'applicazione usa UDP essa scrive un pacchetto di dati (il cosiddetto \textit{datagram} che da il nome al @@ -673,7 +673,7 @@ Infine UDP (\textit{connectionless}) in quanto non è necessario stabilire nessun tipo di relazione tra origine e destinazione dei pacchetti. Si hanno così situazioni in cui un client può scrivere su uno stesso socket pacchetti destinati a -server diversi, o un server ricevere su un socket paccetti provenienti da +server diversi, o un server ricevere su un socket pacchetti provenienti da client diversi. Il modo più semplice di immaginarsi il funzionamento di UDP è quello della radio, in cui si può ``trasmettere a'' e ``ricevere da'' più stazioni usando la stessa frequenza. @@ -692,7 +692,7 @@ diverso da UDP; alla base del suo design infatti non stanno semplicit velocità, ma la ricerca della massima affidabilità possibile nella trasmissione dei dati. -La prima differenza con UDP è che TCP provvede sempre una conessione diretta +La prima differenza con UDP è che TCP provvede sempre una connessione diretta fra un client e un server, attraverso la quale essi possono comunicare; per questo il paragone più appropriato per questo protocollo è quello del collegamento telefonico, in quanto prima viene stabilita una connessione fra @@ -729,7 +729,7 @@ Il protocollo provvede anche un controllo di flusso (\textit{flow control}), cioè specifica sempre all'altro capo della trasmissione quanti dati può ricevere tramite una \textit{advertised window} (letteralmente finestra annunciata), che indica lo spazio disponibile nel buffer di ricezione, -cosicchè nella trasmissione non vengano inviati più dati di quelli che possono +cosicché nella trasmissione non vengano inviati più dati di quelli che possono essere ricevuti. Questa finestra cambia dinamicamente diminuendo con la ricezione dei dati dal @@ -806,7 +806,7 @@ La MTU pi MTU}, che dice qual'è la lunghezza massima oltre la quale un pacchetto inviato da una stazione ad un'altra verrebbe senz'altro frammentato. Si tenga conto che non è affatto detto che la \textit{path MTU} sia la stessa in -entrambe le direzioni, perchè l'instradamento può essere diverso nei due +entrambe le direzioni, perché l'instradamento può essere diverso nei due sensi, con diverse tipologie di rete coinvolte. Una delle differenze fra IPv4 e IPv6 é che per IPv6 la frammentazione può @@ -824,15 +824,15 @@ messaggio di errore ICMPv4 di tipo \textit{destination unreachable, Dato che i router IPv6 non possono effettuare la frammentazione la ricezione di un pacchetto di dimensione eccessiva per la ritrasmissione genererà sempre -un messaggio di errore ICMPv6 di tipo \textit{paket too big}. +un messaggio di errore ICMPv6 di tipo \textit{packet too big}. Dato che il meccanismo di frammentazione e riassemblaggio comporta inefficienza normalmente viene utilizzato il procedimento della \textit{path - MTU discover} (vedi RFC1191 per IPv4 e RFC1981 per IPv6) che permette dui + MTU discover} (vedi RFC~1191 per IPv4 e RFC~1981 per IPv6) che permette di trovare il \textit{path MTU} fra due stazioni; per la realizzazione del procedimento si usa il flag DF di IPv4 e il comportamento normale di IPv6 -inviando delle opportune serie di pacchetti (per i dettagli vedere l'RFC1191 -per IPv4 e l'RFC1981 per IPv6) fintanto che non si hanno più errori. +inviando delle opportune serie di pacchetti (per i dettagli vedere l'RFC~1191 +per IPv4 e l'RFC~1981 per IPv6) fintanto che non si hanno più errori. Il TCP usa sempre questo meccanismo, che per le implementazioni di IPv4 è opzionale, mentre diventa obbligatorio per IPv6. Per IPv6 infatti, non diff --git a/pref.tex b/pref.tex index 8024653..2b7910b 100644 --- a/pref.tex +++ b/pref.tex @@ -28,7 +28,7 @@ per il software libero. Questo progetto mira alla stesura di un libro il più completo e chiaro possibile sulla programmazione in GNU/Linux (che da qui in avanti spesso -chiameremo semplicemante linux per brevità). Ovviamente essendo i concetti in +chiameremo semplicemante Linux per brevità). Ovviamente essendo i concetti in gran parte gli stessi, esso dovrebbe restare valido anche per la programmazione in ambito Unix generico, pur restando l'intenzione di approfondire in maniera specifica le caratteristiche peculiari di GNU/Linux. diff --git a/process.tex b/process.tex index 84cd0fe..52c1f40 100644 --- a/process.tex +++ b/process.tex @@ -29,7 +29,7 @@ Anche quando all'interno di un programma possono essere presenti pi \textsl{filoni} di esecuzione (i cosiddetti \textit{thread}), o questo possa essere composto da moduli multipli completamente separati, quando questo sarà posto in esecuzione esso apparirà al sistema come un solo processo (il -discorso dei \textit{thread} comunque in linux necessita di una trattazione a +discorso dei \textit{thread} comunque in Linux necessita di una trattazione a parte per la peculiarità dell'implementazione). \section{La funzione \texttt{main}} @@ -40,7 +40,7 @@ avvio, usando il programma \texttt{ld-linux.so}, carica le librerie condivise che servono al programma, effettua il link dinamico del codice e poi alla fine lo esegue. Infatti, a meno di non aver specificato il flag \texttt{-static} durante la compilazione, tutti i -programmi in linux sono incompleti e necessitano di essere linkati alle +programmi in Linux sono incompleti e necessitano di essere linkati alle librerie condivise quando vengono avviati. La procedura è controllata da alcune variabili di ambiente e dal contenuto di \texttt{/etc/ld.so.conf}, i dettagli sono riportati nella man page di \texttt{ld.so}. @@ -50,7 +50,7 @@ sta al programmatore chiamare cos si suppone iniziale l'esecuzione; in ogni caso senza questa funzione lo stesso linker darebbe luogo ad errori. -Lo stadard ISO C specifica che la funzione \texttt{main} può o non avere +Lo standard ISO C specifica che la funzione \texttt{main} può o non avere argomenti o prendere due argomenti che rappresentano gli argomenti passati da linea di comando, in sostanza un prototipo che va sempre bene è il seguente: \begin{verbatim} @@ -96,7 +96,7 @@ la fine della funzione \texttt{main} senza ritornare esplicitamente si ha un valore di uscita indefinito, è pertanto consigliabile di concludere sempre in maniera esplicita detta funzione. -Una altra convenzione riserva i valori da 128 in sù per usi speciali, ad +Una altra convenzione riserva i valori da 128 in su per usi speciali, ad esempio 128 viene usato per indicare l'incapacità di eseguire un altro programma in un sottoprocesso. Benché anche questa convenzione non sia universalmente seguita è una buona idea tenerne conto. @@ -107,7 +107,7 @@ una shell non si cura di tutto questo e comunque il valore dello stato di uscita è sempre troncato ad 8 bit, per cui si potrebbe incorrere nel caso in cui l'errore 256, diventando zero, verrebbe interpretato come un successo. In \texttt{stdlib.h} sono definite due macro \texttt{EXIT\_SUCCESS} e -\texttt{EXIT\_FAILURE}, che in linux sono poste rispettivamente ai valori 0 e +\texttt{EXIT\_FAILURE}, che in Linux sono poste rispettivamente ai valori 0 e 1 (di tipo \texttt{int}), seguendo lo standard POSIX. Infine occorre distinguere fra lo stato di uscita di un programma @@ -224,7 +224,7 @@ attraveso una delle funzioni \texttt{exec} che vedremo in Allo stesso modo l'unico modo in cui un programma può concludere volontariamente la sua esecuzione è attraverso una chiamata alla system call -\texttt{\_exec} sia esplicitamnte o che in maniera indiretta attraverso l'uso +\texttt{\_exec} sia esplicitamente o che in maniera indiretta attraverso l'uso di \texttt{exit} o il ritorno della funzione \texttt{main}. Lo schema delle modalità con cui si avvia e conclude normalmente un programma @@ -248,7 +248,7 @@ attraverso l'uso di un segnale (modalit Una delle risorse base che ciascun processo ha a disposizione è la memoria, ed uno degli aspetti più complessi di un sistema unix (ed in particolar modo di -linux) è appunto la gestione della memoria. Qui ci occuperemo però di come la +Linux) è appunto la gestione della memoria. Qui ci occuperemo però di come la memoria viene vista dal punto di vista di un programma in esecuzione in un processo. @@ -258,14 +258,14 @@ processo. Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli di basso livello dipendono in maniera diretta dall'architettura -dell'hardware), ma quello più tipico, usato da unix (e da linux) è quello di +dell'hardware), ma quello più tipico, usato da unix (e da Linux) è quello di assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare in cui gli indirizzi vanno da zero ad un qualche valore massimo (nel caso di -linux fino al kernel 2.2 detto massimo era per macchine a 32bit di 2Gb, con il +Linux fino al kernel 2.2 detto massimo era per macchine a 32bit di 2Gb, con il kernel 2.4 il limite è stato esteso). Come accennato nell'introduzione questo spazio di indirizzi è virtuale e non -corrisponde all'effettiva posizione dei dati nella ram del computer; in genere +corrisponde all'effettiva posizione dei dati nella RAM del computer; in genere detto spazio non è neanche continuo (cioè non tutti gli indirizzi sono utilizzabili e/o utilizzati). @@ -273,13 +273,13 @@ La memoria virtuale viene divisa in pagine (che ad esempio sono di 4kb su macchine a 32 bit e 8kb sulle alpha, valori strettamente connessi all'hardware di gestione della memoria) di dimensione fissa, e ciascuna pagina della memoria virtuale è associata ad un supporto che può essere una pagina di -memoria reale o ad un dipositivo di stoccaggio secondario (in genere lo spazio +memoria reale o ad un dispositivo di stoccaggio secondario (in genere lo spazio disco riservato alla swap, o i file che contengono il codice). Lo stesso pezzo di memoria reale (o di spazio disco) può fare da supporto a diverse pagine di memoria virtuale appartenenti a processi diversi (come accade in genere per le pagine che contengono il codice delle librerie -condivise). Ad esempio il codice della fuzione \texttt{printf} starà su una +condivise). Ad esempio il codice della funzione \texttt{printf} starà su una sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria virtuale di tutti i processi hanno detta funzione nel loro codice. @@ -296,7 +296,7 @@ Quando un processo cerca di accedere ad una pagina che non reale avviene quello che viene chiamato un \textit{page fault}, l'hardware di gestione della memoria (la MMU del processore) genera una interruzione e passa il controllo al kernel il quale sospende il processo e si incarica di mettere -in ram la pagina richiesta (effettuando tutte le operazioni necessarie per +in RAM la pagina richiesta (effettuando tutte le operazioni necessarie per reperire lo spazio necessario), per poi restituire il controllo al processo. @@ -304,7 +304,7 @@ Dal punto di vista di un processo questo meccanismo trasparente e tutto avviene come se tutte le pagine fossero sempre disponibili in memoria. L'unica differenza avvertibile è quella dei tempi di esecuzione, che passano dai pochi nanosecondi necessari per l'accesso a tempi molto più -lunghi, dovuti all'intervento del kernel. Normalemente questo è il prezzo da +lunghi, dovuti all'intervento del kernel. Normalmente questo è il prezzo da pagare per avere un multitasking reale, ed in genere il sistema è molto efficiente in questo lavoro; quando però ci siano esigenze specifiche di prestazioni è possibile usare delle funzioni che permettono di bloccare il @@ -321,32 +321,32 @@ tentativo di accedere ad un indirizzo non allocato commette quando si è manipolato male un puntatore e genera quello che viene chiamato un \textit{segmentation fault}, si tenta cioè di leggere e scrivere da un indirizzo per il quale non esiste una associazione della pagina virtuale -ed il kernel riponde al relativo \textit{page fault} mandando un segnale +ed il kernel risponde al relativo \textit{page fault} mandando un segnale \texttt{SIGSEGV} al processo, che normalmente ne causa la terminazione immediata. È pertanto importante capire come viene strutturata la memoria virtuale di un processo; essa viene divisa in \textsl{segmenti}, cioè un insieme contiguo di -indirizzi virtuali ai quali il processo può accedere. Storicamente un +indirizzi virtuali ai quali il processo può accedere. Solitamente un programma C viene suddiviso nei seguenti segmenti: \begin{enumerate} \item Il segmento di testo (\textit{text segment}). Contiene il codice - macchina del programma e le costanti statiche. Normalente viene condiviso + macchina del programma e le costanti statiche. Normalmente viene condiviso così che più processi (anche diversi nel caso di librerie) possano - utilizzarlo e marcato in sola lettura per evitare sovrascritture accidentali - (o maliziose) che ne modifichino le istruzioni. + utilizzarlo e viene marcato in sola lettura per evitare sovrascritture + accidentali (o maliziose) che ne modifichino le istruzioni. Viene allocato da \texttt{exec} all'avvio del programma e resta invariato per tutto il tempo dell'esecuzione. -\item Il segmento dei dati (\textit{data segment}). Contiene le varibili +\item Il segmento dei dati (\textit{data segment}). Contiene le variabili globali (cioè quelle definite al di fuori di tutte le funzioni). Di norma è diviso in due parti. - La prima è il segmento dei dati inizializzati, che contiene le variabili - globali il cui valore è stato assegnato esplicitamente. Ad esempio se si - definisce: + La prima parte è il segmento dei dati inizializzati, che contiene le + variabili globali il cui valore è stato assegnato esplicitamente. Ad esempio + se si definisce: \begin{verbatim} double pi = 3.14; \end{verbatim} @@ -354,14 +354,14 @@ programma C viene suddiviso nei seguenti segmenti: segmento viene preallocato dalla \texttt{exec} e inizializzata ai valori specificati. - La seconda è il segmento dei dati non inizializzati, che contiene le + La seconda parte è il segmento dei dati non inizializzati, che contiene le variabili globali il cui valore è stato non è assegnato esplicitamente. Ad esempio se si definisce: \begin{verbatim} int vect[100]; \end{verbatim} questo valore sarà immagazzinato in questo segmento. Anch'esso viene - allocato all'avvio, e tutte le varibili vengono inizializzate a + allocato all'avvio, e tutte le variabili vengono inizializzate a zero (ed i puntatori a \texttt{NULL}). Storicamente questo segmento viene chiamato BBS (da \textit{block started by @@ -400,17 +400,78 @@ salvato sul file, in quanto viene inizializzato a zero al caricamento del programma. -\subsection{La librerie condivise} -\label{sec:proc_mem_shlib} +\subsection{Allocazione della memoria per i programmi C} +\label{sec:proc_mem_alloc} + +Il C supporta due tipi di allocazione della memoria, l'allocazione statica è +quella in cui vanno le variabili globali e le variabili statiche (e viene +effettuata nel segmento dei dati), lo spazio per queste variabili viene +allocati all'avvio del programma (come parte delle operazioni svolte da +\texttt{exec}) e non viene liberato fino alla sua conclusione. + +L'allocazione automatica è quella che avviene per le cosiddette variabili +automatiche, cioè gli argomenti delle funzioni o le variabili locali. Lo +spazio per queste variabili viene allocato nello stack quando viene eseguito +comando di invocazione della funzione e liberato quando si esce dalla +medesima. + +Esiste però un terzo tipo di allocazione, che non è prevista dal linguaggio C, +che è l'allocazione dinamica della memoria, necessaria quando il quantitativo +di memoria che serve è determinabile solo in corso di esecuzione del +programma. +Il C non consente di usare variabili allocate dinamicamente, non è possibile +cioè definire in fase di programmazione una variabile le cui dimensioni +possano essere modificate durante l'esecuzione del programma; però le librerie +del C forniscono una serie opportuna di funzioni per permettere l'allocazione +dinamica di spazio in memoria (in genere nello heap, usando la system call +\texttt{sbrk}), solo che a questo punto sarà possibile usarlo solo in maniera +indiretta attraverso dei puntatori. + +Le funzioni previste dallo standard ANSI C per la gestione della memoria sono +quattro, i prototipi sono i seguenti: +\begin{prototype}{stdlib.h}{void *calloc(size\_t size)} + Alloca \texttt{size} bytes nello heap. La memoria viene inizializzata a 0. + + La funzione restituisce il puntatore alla zona di memoria allocata in caso + di successo e \texttt{NULL} in caso di fallimento, nel qual caso + \texttt{errno} viene settata a \texttt{ENOMEM}. +\end{prototype} +\begin{prototype}{stdlib.h}{void *malloc(size\_t size)} + Alloca \texttt{size} bytes nello heap. La memoria non viene inizializzata. + La funzione restituisce il puntatore alla zona di memoria allocata in caso + di successo e \texttt{NULL} in caso di fallimento, nel qual caso + \texttt{errno} viene settata a \texttt{ENOMEM}. +\end{prototype} +\begin{prototype}{stdlib.h}{void free(void *ptr)} + Disalloca lo spazio di memoria puntato da \texttt{ptr}. + + La funzione non ritorna nulla. +\end{prototype} +\begin{prototype}{stdlib.h}{void *realloc(void *ptr, size\_t size)} + Cambia la dimensione del blocco allocato all'indirizzo \texttt{ptr} + portandola a \texttt{size}. + + La funzione restituisce il puntatore alla zona di memoria allocata in caso + di successo e \texttt{NULL} in caso di fallimento, nel qual caso + \texttt{errno} viene settata a \texttt{ENOMEM}. +\end{prototype} + +Il puntatore che le funzioni di allocazione ritornano è garantito essere +sempre correttamente allineato per tutti i tipi di dati; ad esempio sulle +macchine a 32 bit in genere è allineato a multipli di 4 bytes e sulle macchine +a 64 bit a multipli di 8 bytes. Il puntatori ritornati sono di tipo generico +così non è necessario effettuare un cast per assegnarli a puntatori di altro +tipo. -\subsection{Allocazione e disallocazione della memoria} -\label{sec:proc_mem_alloc} + + + \section{La gestione di parametri e opzioni} @@ -430,7 +491,7 @@ ciascuna delle quali viene considerata un parametro; di default per individuare le parole viene usato come separatore lo spazio (comportamento modificabile attraverso il settaggio della variabile di ambiente IFS). -Nella scansione viene costruito l'array di puntatori \texttt{argv} inserendo +Nella scansione viene costruito il vettore di puntatori \texttt{argv} inserendo in successione il puntatore alla stringa costituente l'$n$-simo parametro; la variabile \texttt{argc} viene inizializzata al numero di parametri trovati, in questo modo il primo parametro è sempre il nome del programma (vedi \nfig). @@ -442,7 +503,7 @@ In generale un programma unix riceve da linea di comando sia i parametri che le opzioni, queste ultime sono standardizzate per essere riconosciute come tali: un elemento di \texttt{argv} che inizia con \texttt{-} e che non sia un singolo \texttt{-} o \texttt{--} viene considerato un'opzione. In in genere -le opzioni sono costituite da un lettera preceduta dal meno e possono avere o +le opzioni sono costituite da una lettera preceduta dal meno e possono avere o no un parametro associato; un comando tipico può essere cioè qualcosa del tipo: \begin{verbatim} @@ -479,7 +540,7 @@ considerata conclusa. Quando la funzione trova un'opzione essa ritorna il valore numerico del carattere, in questo modo si possono prendere le azioni relative usando un -case; la funzione inizializza inoltre alcune varibili globali: +case; la funzione inizializza inoltre alcune variabili globali: \begin{itemize} \item \texttt{char * optarg} contiene il puntatore alla stringa argomento dell'opzione. @@ -490,8 +551,7 @@ case; la funzione inizializza inoltre alcune varibili globali: \item \texttt{int optopt} contiene il carattere dell'opzione non riconosciuta. \end{itemize} -In \nfig è mostrato un programma di esempio, - +In \nfig\ è mostrato un programma di esempio, \begin{figure}[htbp] \footnotesize @@ -547,6 +607,7 @@ la gestione di queste ultime versione estesa di \texttt{getopt}. + \subsection{Le variabili di ambiente} \label{sec:proc_env_var} diff --git a/prochand.tex b/prochand.tex index 40a880d..8d27565 100644 --- a/prochand.tex +++ b/prochand.tex @@ -65,15 +65,15 @@ gli header files \texttt{unistd.h} e \texttt{sys/types.h}). \label{sec:prochand_control} Esamineremo in questa sezione le varie funzioni per il controllo dei processi: -la lore creazione, la terminazione, l'esecuzione di altri programmi. Prima di +la loro creazione, la terminazione, l'esecuzione di altri programmi. Prima di trattare in dettaglio le singole funzioni, faremo un'introduzione generale ai -contetti che stanno alla base della gestione dei processi in unix. +concetti che stanno alla base della gestione dei processi in unix. \subsection{Una panoramica} \label{sec:prochand_control_overview} I processi vengono creati dalla funzione \texttt{fork}; in genere questa è una -system call, ma linux però usa un'altra nomenclatura, e la funzione fork è +system call, ma Linux però usa un'altra nomenclatura, e la funzione fork è basata a sua volta sulla system call \texttt{clone}, che viene usata anche per generare i \textit{thread}. Il processo figlio creato dalla \textit{fork} è una copia identica del processo processo padre, solo che ha un suo pid @@ -93,7 +93,7 @@ ricevuta dal processo padre, a quel punto tutte le risorse allocate nel sistema ad esso associate vengono rilasciate. Avere due processi che eseguono esattamente lo stesso codice non è molto -utile, mormalmente si genera un secondo processo per affidagli l'esecuzione di +utile, normalmente si genera un secondo processo per affidargli l'esecuzione di un compito specifico (ad esempio gestire una connessione dopo che questa è stata stabilita), o fargli eseguire (come fa la shell) un altro programma. Per questo si usa la seconda funzione fondamentale per programmazione coi processi @@ -137,7 +137,7 @@ viene eseguito dal padre o dal figlio. \label{sec:prochand_perms} Va messo qui tutta la storia su effective, real, saved uid, e pure le cose di -linux come il filesystem uid. +Linux come il filesystem uid. \subsection{Le funzioni \texttt{setuid} e \texttt{setgid}} \label{sec:prochand_setuid} diff --git a/signal.tex b/signal.tex index c5b2282..4b5ff40 100644 --- a/signal.tex +++ b/signal.tex @@ -200,7 +200,7 @@ anche al successivo del valore numerico assegnato all'ultimo segnale definito. \subsubsection{Segnali di errore di programma} Questi segnali sono generati quando il sistema, o in certi casi direttamente -l'hardware (come per i page fault non valildi) rileva un qualche errore +l'hardware (come per i page fault non validi) rileva un qualche errore insanabile nel programma in esecuzione. In generale la generazione di questi segnali significa che il programma ha dei gravi problemi (ad esempio ha dereferenziato un puntatore non valido o ha eseguito una operazione aritmetica @@ -233,14 +233,14 @@ Questi segnali sono: % aritmetiche e richiede che esse siano notificate. \item \texttt{SIGILL} Il nome deriva da \textit{illegal instruction}, significa che il programma sta cercando di eseguire una istruzione - privilegiata od inesistente, in generale del codice illegale. Poiché il + privilegiata o inesistente, in generale del codice illegale. Poiché il compilatore del C genera del codice valido si ottiene questo segnale se il - file eseguibile è corrotto o si stanno cercando di eseguire dei - dati. Quest'ultimo caso può accadere quando si passa un puntatore sbagliato - al posto di un puntatore a funzione, o si eccede la scrittura di un array di + file eseguibile è corrotto o si stanno cercando di eseguire dei dati. + Quest'ultimo caso può accadere quando si passa un puntatore sbagliato al + posto di un puntatore a funzione, o si eccede la scrittura di un vettore di una variabile locale, andando a corrompere lo stack. Lo stesso segnale viene - generato in caso di overflow dello stack o di problemi nell'esecuzione di - di un signal handler. + generato in caso di overflow dello stack o di problemi nell'esecuzione di di + un signal handler. \item \texttt{SIGSEGV} Il nome deriva da \textit{segment violation}, e significa che il programma sta cercando di leggere o scrivere in una zona di @@ -249,7 +249,7 @@ Questi segnali sono: accorge dell'errore ed il kernel genera il segnale. È tipico ottenere questo segnale dereferenziando un puntatore nullo o non - inizializzatoo leggendo al di la della fine di un vettore. + inizializzato leggendo al di la della fine di un vettore. \item \texttt{SIGBUS} \item \texttt{SIGABRT} diff --git a/socket.tex b/socket.tex index 9fac73d..32f1c0f 100644 --- a/socket.tex +++ b/socket.tex @@ -117,7 +117,7 @@ altro nome con cui si indicano i domini. A ciascun tipo di dominio corrisponde un analogo nome simbolico che inizia per \texttt{AF\_} da \textit{address family}, e che identifica il formato degli -indirizzi usati in quel dominio; le man pages di linux si riferiscono a questi +indirizzi usati in quel dominio; le man pages di Linux si riferiscono a questi anche come \textit{name space}, (nome che però il manuale della glibc riserva ai domini) e che identifica il formato degli indirizzi usati in quel dominio. @@ -130,7 +130,7 @@ supportino diverse strutture di indirizzi, per cui nella pratica questi due nomi sono equivalenti e corrispondono agli stessi valori. I domini (e i relativi nomi simbolici), così come i nomi delle famiglie di -indirizzi sono definiti dall'header \textit{socket.h}. In linux le famiglie di +indirizzi sono definiti dall'header \textit{socket.h}. In Linux le famiglie di protocolli disponibili sono riportate in \ntab. \begin{table}[htb] @@ -150,13 +150,13 @@ protocolli disponibili sono riportate in \ntab. PF\_APPLETALK & Appletalk & ddp(7) \\ PF\_PACKET & Low level packet interface & packet(7) \\ \end{tabular} - \caption{Famiglie di protocolli definiti in linux} + \caption{Famiglie di protocolli definiti in Linux} \label{tab:net_pf_names} \end{table} Non tutte le famiglie di protocolli sono accessibili dall'utente generico, ad esempio in generale tutti i socket di tipo \texttt{SOCK\_RAW} possono essere -creati solo da processi che hanno i provilegi di root (cioè effective uid +creati solo da processi che hanno i privilegi di root (cioè effective uid uguale a zero) o la capability \texttt{CAP\_NET\_RAW}. @@ -166,7 +166,7 @@ uguale a zero) o la capability \texttt{CAP\_NET\_RAW}. La scelta di un dominio non comporta però la scelta dello stile di comunicazione, questo infatti viene a dipendere dal protocollo che si andrà ad utilizzare fra quelli disponibili nella famiglia scelta. Le API permettono di -scegliere lo stile di comunicazione indicando il tipo di socket; linux e le +scegliere lo stile di comunicazione indicando il tipo di socket; Linux e le glibc mettono a disposizione i seguenti tipi di socket (che il manuale della glibc chiama \textit{styles}) definiti come \texttt{int} in \texttt{socket.h}: @@ -284,7 +284,7 @@ invocano dette funzioni passando l'indirizzo di un protocollo specifico occorrerà eseguire un casting del relativo puntatore. I tipi di dati che compongono la struttura sono stabiliti dallo standard -Posix.1g, riassunti in \ntab\ con i rispettivi file di include in cui sono +POSIX.1g, riassunti in \ntab\ con i rispettivi file di include in cui sono definiti; la struttura è invece definita nell'include file \texttt{sys/socket.h} @@ -314,14 +314,14 @@ definiti; la struttura \hline \end{tabular} \caption{Tipi di dati usati nelle strutture degli indirizzi, secondo quanto - stabilito dallo standard Posix.1g} + stabilito dallo standard POSIX.1g} \label{tab:sock_data_types} \end{table} In alcuni sistemi la struttura è leggermente diversa e prevede un primo membro aggiuntivo \texttt{uint8\_t sin\_len} (come riportato da R. Stevens nei suoi libri). Questo campo non verrebbe usato direttamente dal programmatore e non è -richiesto dallo standard Posix.1g, in linux pertanto non sussiste. Il campo +richiesto dallo standard POSIX.1g, in Linux pertanto non sussiste. Il campo \texttt{sa\_family\_t} era storicamente un \texttt{unsigned short}. Dal punto di vista del programmatore l'unico uso di questa struttura è quello @@ -340,7 +340,7 @@ I socket di tipo \texttt{PF\_INET} vengono usati per la comunicazione attraverso internet; la struttura per gli indirizzi per un socket internet (IPv4) è definita come \texttt{sockaddr\_in} nell'header file \texttt{netinet/in.h} e secondo le man page ha la forma mostrata in \nfig, -conforme allo standard Posix.1g. +conforme allo standard POSIX.1g. \begin{figure}[!htbp] @@ -377,7 +377,7 @@ usare la funzione \texttt{bind} su queste porte. Il membro \texttt{sin\_addr} contiene l'indirizzo internet dell'altro capo della comunicazione, e viene acceduto sia come struttura (un resto di una -implementazione precedente in cui questa era una union usata per accedere alle +implementazione precedente in cui questa era una \texttt{union} usata per accedere alle diverse classi di indirizzi) che come intero. Infine è da sottolineare che sia gli indirizzi che i numeri di porta devono @@ -417,7 +417,7 @@ struct in6_addr { Il campo \texttt{sin6\_family} deve essere sempre settato ad \texttt{AF\_INET6}, il campo \texttt{sin6\_port} è analogo a quello di IPv4 e -segue le stesse regole; il campo \texttt{sin6\_flowinfo} è a dua volta diviso +segue le stesse regole; il campo \texttt{sin6\_flowinfo} è a sua volta diviso in tre parti di cui i 24 bit inferiori indicano l'etichetta di flusso, i successivi 4 bit la priorità e gli ultimi 4 sono riservati; questi valori fanno riferimento ad alcuni campi specifici dell'header dei pacchetti IPv6 @@ -498,7 +498,7 @@ utile anche in seguito. \subsection{La \textit{endianess}} \label{sec:sock_endianess} -La rappresentazione di un numbero binario in un computer può essere fatta in +La rappresentazione di un numero binario in un computer può essere fatta in due modi, chiamati rispettivamente \textit{big endian} e \textit{little endian} a seconda di come i singoli bit vengono aggregati per formare le variabili intere (in diretta corrispondenza a come sono poi in realtà cablati @@ -515,14 +515,16 @@ numero. Il caso opposto, in cui si parte dal bit meno significativo per lo stesso motivo \textit{big endian}. La \textit{endianess} di un computer dipende essenzialmente dalla architettura -hardware usata; intel e digital usano il little endian, motorola, ibm, sun +hardware usata; Intel e Digital usano il little endian, Motorola, IBM, Sun (sostanzialmente tutti gli altri) usano il big endian. Il formato della rete è -anch'esso big endian. Esistono poi anche dei processori che possono scegliere -il tipo di formato all'avvio e alcuni, come il PowerPC o l'intel i860, possono -pure passare da un tipo all'altro con una specifica istruzione; in ogni caso -in linux l'ordinamanento è definito dall'archiettura e anche se questi -cambiamenti sono possibili anche dopo che il sistema è avviato, non vengono -mai eseguiti. +anch'esso big endian, quello del bus PCI è little endian, quello del bus VME è +big endian. + +Esistono poi anche dei processori che possono scegliere il tipo di formato +all'avvio e alcuni, come il PowerPC o l'Intel i860, possono pure passare da un +tipo di ordinamento all'altro con una specifica istruzione; in ogni caso in +Linux l'ordinamento è definito dall'architettura e anche se questi cambiamenti +sono possibili anche dopo che il sistema è avviato, non vengono mai eseguiti. \subsection{Le funzioni per il riordinamento} \label{sec:sock_func_ord} @@ -531,7 +533,7 @@ Il problema connesso all'endianess di architettura all'altra i dati vengono interpretati in maniera diversa, e ad esempio nel caso dell'intero a 16 bit ci si ritroverà con i due bytes in cui è suddiviso scambiati di posto, e ne sarà quindi invertito l'ordine di lettura -per cui, per riavere il valore originale dovrenno essere rovesciati. +per cui, per riavere il valore originale dovranno essere rovesciati. Per questo motivo si usano le seguenti funzioni di conversione che servono a tener conto automaticamente della possibile differenza fra l'ordinamento usato @@ -543,7 +545,7 @@ funzioni sono: quello della rete. \end{prototype} \begin{prototype}{netinet/in.h} -{unsigned sort int htons(unsigned short int hostshort)} +{unsigned short int htons(unsigned short int hostshort)} Converte l'intero a 16 bit \texttt{hostshort} dal formato della macchina a quello della rete. \end{prototype} @@ -575,7 +577,7 @@ codice su tutte le architetture. Un secondo insieme di funzioni di manipolazione serve per passare dal formato binario usato nelle strutture degli indirizzi alla rappresentazione dei numeri -IP che si usa normalente. +IP che si usa normalmente. Le prime tre funzioni di manipolazione riguardano la conversione degli indirizzi IPv4 da una stringa in cui il numero di IP è espresso secondo la