Consiglio Nazionale dell
Transcript
Consiglio Nazionale dell
Programmazione di Sistema Massimo Bernaschi Istituto per le Applicazioni del Calcolo “Mauro Picone” Consiglio Nazionale delle Ricerche Viale Manzoni, 30 - 00185 Rome - Italy http://www.iac.cnr.it/ e-mail: [email protected] M. Bernaschi: Sistemi Operativi II Libreria C, Unix System Call, Win32 API È importante capire le differenze concettuali e di utilizzo tra • la libreria C – funzioni nella libreria ANSI-C standard: http://www.infosys.utas.edu.au/info/documentation/C/CStdLib.html • le funzioni definite nello standard POSIX (Portable Operating System Interface) 1003.1 – le funzioni POSIX che NON sono nella libreria C sono elencate in: http://cplus.kompf.de/posixlist.html • le Application Programming Interface di Windows (Win32 API). – Windows supporta la libreria ANSI-C. – Windows sockets 2 M. Bernaschi: Sistemi Operativi II – Remote Procedure Call Una lista di FAQ su Win32 è disponibile su: http://www.winprog.org/faq/ 3 M. Bernaschi: Sistemi Operativi II I principi di Win32 Alcune delle principali caratteristiche di Win32: • Quasi tutte le risorse di sistema sono kernel object identificati e referenziati da un handle. Questi handle giocano un ruolo simile a quello dei file descriptor o process id in Unix. – Notare come gli handle sono oggetti “opachi”. Non sono interi allocati in ordine sequenziale. Ad esempio, il carattere speciale dei descrittori 0, 1, 2 in Unix non ha analogo in Win32. • La Win32 API non è object oriented ma i kernel object possono essere manipolati solo con l’API ufficiali. • Sono definiti come oggetti: file, processi, thread, pipe, memory mapping, eventi. Gli oggetti hanno attributi di sicurezza. • L’API di Win32 è molto ricca e flessibile (molte funzioni che 4 M. Bernaschi: Sistemi Operativi II eseguono la stessa operazione con “varianti sul tema”). • Win32 offre numerosi meccanismi di sincronizzazione e comunicazione. • L’unità fondamentale di esecuzione è il thread. Un processo può contenere uno o più thread. – I processi in Win32 non hanno nessuna relazione tipo “padre-figlio” o di appartenenza ad un gruppo di processi. • In genere i nomi delle funzioni dell’API Win32 sono lunghi e “descrittivi” • I tipi predefiniti richiesti da Win32 sono scritti a lettere maiuscole e (cercano di essere) descrittivi: – BOOL: elemento a 32 bit contenente un singolo valore logico; – HANDLE; 5 M. Bernaschi: Sistemi Operativi II – DWORD: “unsigned int” a 32 bit (uno dei tipi più diffusi); – LPTSTR: puntatore a stringa di caratteri (8 o 16 bit); – LPSECURITY ATTRIBUTES • I tipi predefiniti evitano l’uso dell’operatore *; • Anche se disegnata from scratch, la Win32 API mantiene compatibilità con la Win16 API di Windows 3.1. – Questa feature spiega la presenza di anacronismi come i tipi LPTSTR e LPDWORD che fanno riferimento a long pointer. • Gli include file interessanti sono: windows.h, winnt.h, winbase.h • In Windows l’end-of-line per i file di testo è rappresentata da CR-LF mentre in Unix da LF. • Capire quando usare le funzioni della libreria C (con il vantaggio 6 M. Bernaschi: Sistemi Operativi II della portabilità) oppure le primitive della Win32 (o di Unix) è uno degli scopi di questo corso. 7 M. Bernaschi: Sistemi Operativi II Come copiare un file Quattro implementazioni: • libreria C standard (win32smp/chaptr01/cpC.c); • stile Unix (POSIX) (win32smp/chaptr01/cpU.c); • Win32 “base” (win32smp/chaptr01/cpW.c); • Funzione di “convenienza” della Win32: CopyFile (win32smp/chaptr01/cpCF.c); 8 M. Bernaschi: Sistemi Operativi II Accesso ai file Esistono diversi tipi di file system sia sotto Windows che sotto UNIX. • Windows: – due tipi di file: testo e binario. – VFAT e FAT32, eredità del File Allocation Table del DOS. – NTFS disponibile su Windows NT, 2000/3, XP, Vista, Windows 7. ∗ Non limita rigidamente la lunghezza dei nomi di file; ∗ supporta i “large” file; ∗ fornisce attributi di sicurezza, compressione, recovery..., cifratura; – Win32 supporta la gerarchia del file system anche se mantiene il concetto di drive (C:, D:,...,H:); 9 M. Bernaschi: Sistemi Operativi II – come separatore di path può essere usato /. – Esistono limitazioni all’insieme di caratteri che possono costituire il nome di un file o di una directory (non possono essere utilizzati, ad esempio i primi 31 caratteri ASCII). – I nomi sono case-insensitive – I nomi di file e directory sono limitati a 255 caratteri (è possibile superare il limite ricorrendo all’estensione Unicode) – Win32 non supporta il concetto di file link che permette di indicare lo stesso file con due nomi distinti. ∗ in realtà esiste un supporto per il sottosistema POSIX ma è ignorato da Win32. – Esistono invece gli Alternate Data Stream, cioè flussi indipendenti di dati che fanno riferimento allo stesso file. Un incubo dal punto di vista della sicurezza! 10 M. Bernaschi: Sistemi Operativi II • Unix: – Ext2 ed Ext3 (Linux) – JFS (AIX) – XFS (IRIX) – I nomi sono case-sensitive – La lunghezza massima del nome dipende dall’implementazione – Utilizza il concetto di link (hard o simbolico). 11 M. Bernaschi: Sistemi Operativi II Operazioni elementari su file Apertura, lettura, scrittura, chiusura; • CreateFile: http://msdn.microsoft.com/en-us/library/default.aspx HANDLE CreateFile( LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ); 12 M. Bernaschi: Sistemi Operativi II • ReadFile: BOOL ReadFile( HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped ); Da notare che la funzione non fallisce se l’handle è posizionato alla fine del file, piuttosto viene tornato un valore 0 in lpNumberOfBytesRead • WriteFile: sostanzialmente simmetrica alla ReadFile. 13 M. Bernaschi: Sistemi Operativi II • CloseFile: BOOL CloseHandle(HANDLE hObject); Le funzioni UNIX equivalenti sono open, read, write, close. Le funzioni nella libreria C equivalenti sono fopen, fread, fwrite, fclose. Notare come queste ultime non prendono un singolo argomento per specificare il numero di byte da trasferire ma, piuttosto, la dimensione dell’“oggetto” ed il numero di “oggetti” da trasferire 14 M. Bernaschi: Sistemi Operativi II Standard Devices e I/O a console Sia UNIX che Win32 hanno tre dispositivi “standard” per i flussi di input, output ed error. • Unix usa i primi 3 file descriptor (0, 1, 2) • Win32 richiede degli handle e offre una funzione per ottenere gli handle dai device standard: HANDLE GetStdHandle(DWORD nStdHandle); Per ridirezionare uno standard device è necessario usare: BOOL SetStdHandle(DWORD nStdHandle, HANDLE hHandle); in cui hHandle è l’handle del file che deve sostituire lo standard device. nStdHandle deve avere uno dei tre seguenti valori: 15 M. Bernaschi: Sistemi Operativi II STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE. È possibile accedere in ogni caso la console utilizzando i file speciali CONIN$ e CONOUT$. 16 M. Bernaschi: Sistemi Operativi II I/O a console Per l’I/O a console esistono delle funzioni specifiche: • ReadConsole: BOOL ReadConsole( HANDLE hConsoleInput, LPVOID lpBuffer, DWORD nNumberOfCharsToRead, LPDWORD lpNumberOfCharsRead, LPVOID lpReserved); lpReserved deve essere NULL • WriteConsole: simile a ReadConsole 17 M. Bernaschi: Sistemi Operativi II • SetConsoleMode: BOOL SetConsoleMode(HANDLE hConsoleHandle, DWORD dwMode); l’handle deve avere accesso GENERIC READ anche se corrisponde ad un device solo per l’output. dwMode può assumere valori quali ENABLE LINE INPUT, ENABLE ECHO INPUT, ENABLE QUICK EDIT MODE,... L’equivalente funzione in Unix è la: #include <termios.h> int tcsetattr (int fd, int optional_actions, struct termios *termios_p); 18 M. Bernaschi: Sistemi Operativi II • Esistono inoltre in Win32 le funzioni: BOOL FreeConsole() e BOOL AllocConsole(). Notare come le applicazioni che usano una GUI non hanno una console di default ed è quindi necessario usare l’AllocConsole prima di poter usare funzioni come la WriteConsole oppure la printf. Esempi di utilizzo: win32smp/Win32Smp/chaptr02/cat.c 19 M. Bernaschi: Sistemi Operativi II Funzioni di “convenienza” Permettono di svolgere in maniera semplificata operazioni come: • BOOL DeleteFile(LPCTSTR lpFileName); • BOOL CopyFile( LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, BOOL bFailIfExists); • ... • BOOL MoveFileEx( LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, DWORD dwFlags); Gli argomenti bFailIfExists e fdwFlags modificano il comportamento nel caso in cui il file target esiste. 20 M. Bernaschi: Sistemi Operativi II Gestione delle directory La creazione di una directory può essere effettuata con BOOL CreateDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes); mentre la cancellazione richiede BOOL RemoveDirectory(LPCTSTR lpPathName); le funzioni BOOL SetCurrentDirectory(LPCTSTR lpPathName) e DWORD GetCurrentDirectory(DWORD nBufferLength, LPTSTR lpBuffer); permettono di definire e conoscere la working directory. Esempi di utilizzo: win32smp/Win32Smp/chaptr02/pwda.c Sotto Unix/Linux, Le funzioni di scan di una directory sono opendir, readdir, closedir. 21 M. Bernaschi: Sistemi Operativi II Non esistono funzioni per la gestione delle directory nella libreria C. 22 M. Bernaschi: Sistemi Operativi II File e Directory: funzioni avanzate (1) • Win32 è capace di gestire indirizzi di file a 64 bit anche se il sistema stesso è 32 bit. • La stragrande maggioranza dei sistemi Unix supporta large file (indirizzi dei file a 64 bit) ed i sistemi stessi sono a 64 bit. • Linux, pur avendo avuto nel passato come principale piattaforma Intel 32, cioè un sistema a 32 bit: – Supporta file di dimensione > 2 GB grazie alla Large File Interface disponibile dal kernel 2.4 in poi. 23 M. Bernaschi: Sistemi Operativi II File e Directory: funzioni avanzate (2) Praticamente tutti i sistemi operativi e la libreria C supportano il concetto di associare un pointer ad ogni file aperto per indicare la posizione attuale all’interno del file. • Le operazioni di lettura e scrittura iniziano dalla posizione indicata dal file pointer ed incrementano il file pointer del numero di byte trasferiti. • È possibile modificare la posizione del file pointer usando: – Libreria C: int fsetpos( FILE *stream, fpos t *pos) e int fseek( FILE *stream, long offset, int whence) – Linux/Unix: off t lseek(int fildes, off t offset, int whence) whence specifica il riferimento rispetto a cui effettuare lo 24 M. Bernaschi: Sistemi Operativi II spostamento e può assumere uno di tre possibili valori: SEEK_SET, SEEK_CUR, SEEK_END. lseek ritorna direttamente la posizione corrente mentre con la libreria C è necessario utilizzare la funzione long ftell(FILE *stream). – Win32: DWORD SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); ∗ Questa chiamata è particolarmente tricky perché, ad esempio, lDistanceToMove va considerato come signed o unsigned a seconda del valore di dwMoveMethod. Se lpDistanceToMoveHigh è NULL, la funzione può operare solo su file di lunghezza inferiore a 232 − 1. 25 M. Bernaschi: Sistemi Operativi II dwMoveMethod specifica il punto di partenza in maniera analoga al parametro whence. ∗ È possibile inoltre specificare la file position utilizzando la struttura di overlap che costituisce l’ultimo argomento delle primitive ReadFile e WriteFile. Definendo gli opportuni valori nei campi Offset e OffsetHigh l’operazione di I/O inizia alla posizione specificata ma il file pointer non viene modificato. Grande attenzione è richiesta per l’accesso a file la cui dimensione supera i 2GB. Sotto Unix è possibile utilizzare lseek64 mentre nella libreria C fseek64 oppure fseeko. 26 M. Bernaschi: Sistemi Operativi II Dimensione di un file La dimensione di un file può essere ottenuta in Win32 con la chiamata: DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); Se la dimensione supera i 2 GB, il valore di ritorno contiene la parte meno significativa del numero a 64 bit che indica la dimensione mentre lpFileSizeHigh punta alla variabile che contiene la parte più significativa dello stesso numero. In alternativa si può utilizzare: BOOL GetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize); un LARGE_INTEGER è una struttura usata per rappresentare un intero (quindi un numero con segno) a 64 bit. 27 M. Bernaschi: Sistemi Operativi II Sotto Unix la dimensione di un file (e tutta una serie di altre informazioni) può essere ottenuta con la chiamata stat oppure fstat. Notare come la libreria C non offra primitive per questo scopo. 28 M. Bernaschi: Sistemi Operativi II Caratteristiche di file e directory Le caratteristiche di un file possono essere accedute in Win32 con la primitiva: HANDLE FindFirstFile(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData); che torna un search handle da utilizzare in successive chiamate alla BOOL FindNextFile(HANDLE hFindFile, LPWIN32_FIND_DATA lpFindFileData); • lpFileName punta ad una directory o un pathname che può contenere wildcard come i caratteri * e ?. • lpFindFileData punta alla struttura che contiene le caratteristiche del file 29 M. Bernaschi: Sistemi Operativi II typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; TCHAR cFileName[MAX_PATH]; TCHAR cAlternateFileName[14]; /* DOS notation 8.3 */ } WIN32_FIND_DATA, *PWIN32_FIND_DATA; Attenzione: non è possibile usare la CloseHandle per chiudere l’handle. Usare la BOOL FindClose(HANDLE hFindFile). 30 M. Bernaschi: Sistemi Operativi II • Molte di queste informazioni possono essere ottenute direttamente tramite un handle su un file aperto. Ad esempio: BOOL GetFileTime( HANDLE hFile, LPFILETIME lpCreationTime, LPFILETIME lpLastAccessTime, LPFILETIME lpLastWriteTime); Il tempo in Win32 è misurato in unità di 100 nanosecondi a partire dal 1/1/1601. 31 M. Bernaschi: Sistemi Operativi II Sotto Unix la stat o fstat tornano le seguenti informazioni: struct stat { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; unsigned long st_blksize; unsigned long st_blocks; time_t st_atime; time_t st_mtime; time_t st_ctime; }; /* /* /* /* /* /* /* /* /* /* /* /* /* device */ inode */ protection */ number of hard links */ user ID of owner */ group ID of owner */ device type (if inode device) */ total size, in bytes */ blocksize for filesystem I/O */ number of blocks allocated */ time of last access */ time of last modification */ time of last change */ 32 M. Bernaschi: Sistemi Operativi II Win32, Unix e la libreria C offrono funzioni per la creazione di nomi per i file temporanei: GetTempFileName, mktemp e FILE *tmpfile rispettivamente. 33 M. Bernaschi: Sistemi Operativi II File locking in Win32 • Win32 permette di definire lock su file interi o su parti. • In Win32 i lock sono di tipo mandatory e possono essere shared (read-only) o exclusive (read-write). • La funzione fondamentale è: BOOL LockFileEx(HANDLE hFile, DWORD dwFlags, DWORD dwReserved, DWORD nNumberOfBytesToLockLow, DWORD nNumberOfBytesToLockHigh, LPOVERLAPPED lpOverlapped); lpOverlapped è una struttura overlapped che viene utilizzata come in precedenza per specificare la posizione (a 64 bit) della regione di file che deve essere “controllata”. 34 M. Bernaschi: Sistemi Operativi II typedef struct _OVERLAPPED {ULONG_PTR Internal; ULONG_PTR InternalHigh; union { struct { DWORD Offset; DWORD OffsetHigh; }; PVOID Pointer; }; HANDLE hEvent; } OVERLAPPED, *LPOVERLAPPED; Il campo dwFlags specifica diverse caratteristiche del lock (esclusivo invece che condiviso e/o non-bloccante invece di bloccante). • I lock non sono ereditati da un nuovo processo creato • L’operazione di unlock (UnlockFileEx()) deve agire esattamente sullo stesso range di quella di lock. 35 M. Bernaschi: Sistemi Operativi II File Locking in Unix/Linux • “Advisory” e “Mandatory” locks • Usare sempre la funzione POSIX.1 fcntl o la sua interfaccia lockf() int fcntl(int fd, int cmd, struct flock * lock); struct flock { short int l_type; short int l_whence; __off_t l_start; __off_t l_len; __pid_t l_pid; }; /* /* /* /* /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK */ Where ‘l_start’ is relative to */ Offset where the lock begins. */ Size of the locked area; zero means EOF */ Process holding the lock. */ • tre valori possibili per cmd: F_GETLK, F_SETLK, F_SETLKW; • tre valori per l whence: SEEK SET, SEEK CUR, SEEK END; 36 M. Bernaschi: Sistemi Operativi II La fcntl è usata per cinque diversi scopi: • duplicare un descrittore esistente (cmd=F DUPFD) • ottiene/definisce il flag di close-on-exec per un file descriptor (cmd=F GETFD or F SETFD) • ottiene/definisce i flag per il file status (cmd=F GETFL or F SETFL). I flag possibili sono O_NONBLOCK, O_APPEND, O_ASYNC. • ottiene/definisce l’ownership per l’I/O asincrono (cmd=F GETOWN or F SETOWN) • ottiene/definisce i record lock (cmd=F GETLK, F SETLK or F SETLKW) 37 M. Bernaschi: Sistemi Operativi II • F SETLKW è una versione bloccante di F SETLK. L’attesa è interrotta se viene intercettato un segnale. • I lock sono associati con un processo ed un file. Quando un processo termina tutti i suoi lock sono rilasciati. Ogni volta che un descrittore viene chiuso, tutti i lock sul file referenziato da quel descrittore per quel processo sono rilasciati anche se sono stati presi in sezioni diverse del processo! • I locks non sono mai ereditati attraverso una fork. • I locks possono essere ereditati da un nuovo programma attraverso una exec. 38 M. Bernaschi: Sistemi Operativi II Mandatory lock in Unix/Linux • I lock mandatory sono stati aggiunti relativamente tardi in Unix/Linux. • POSIX non specifica nessuno schema per i lock mandatory. • La soluzione adottata è stata quella di utilizzare la stessa interfaccia (fcntl/lockf) ma su file appositamente “marcati” . • I file sono marcati definendo il bit setgroup-id ma rimuovendo la definizione del bit group-execute (chmod g+s file). • Attenzione! Sotto Linux il file system deve esser montato con l’opzion mand. 39 M. Bernaschi: Sistemi Operativi II Il Registry in Windows Il registry è un database centralizzato di tipo gerarchico che contiene tutte le informazioni sulle applicazioni ed il sistema. • L’accesso avviene tramite le registry keys che possono essere descritte come delle directory. • Una chiave può contenere altre chiavi o coppie nome/valore. – Ogni chiave deve avere un valore di default. • Il comando REGEDIT (o REGEDT32) permette di visualizzare e modificare i contenuti del registry che includono informazioni su: – Sistema operativo – Applicazioni installate – Hardware (tipo di processore, numero di processori, memoria) – Utenti e Servizi 40 M. Bernaschi: Sistemi Operativi II – ... • I sistemi Unix/Linux mantengono tradizionalmente la maggior parte di queste informazioni nella directory /etc (e sottodirectory) in semplici file di testo. Gli entry point del registry sono delle chiavi predefinite: HKEY_LOCAL_MACHINE HKEY_USERS HKEY_CURRENT_CONFIG HKEY_CURRENT_USER HKEY_CLASSES_ROOT 41 M. Bernaschi: Sistemi Operativi II API per il registry LONG RegOpenKeyEx( HKEY hKey, LPCTSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult); apre una sottochiave. Partendo da una delle chiavi riservate predefinite è possibile “attraversare” il registry ed ottenere un handle per qualsiasi chiave subordinata. Attenzione, le chiavi hanno un handle speciale (HKEY). 42 M. Bernaschi: Sistemi Operativi II LONG RegEnumKeyEx( HKEY hKey, DWORD dwIndex, LPTSTR lpName, LPDWORD lpcName, LPDWORD lpReserved, LPTSTR lpClass, LPDWORD lpcClass, PFILETIME lpftLastWriteTime); Enumera le sottochiavi di una data chiave aperta (simile alla FindFirstFile, FindNextFile per le directory). 43 M. Bernaschi: Sistemi Operativi II LONG RegCreateKeyEx( HKEY hKey, LPCTSTR lpSubKey, DWORD Reserved, LPTSTR lpClass, DWORD dwOptions, REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition); Crea una nuova chiave lpSubKey di tipo lpClass. Il parametro lpdwDisposition indica se la chiave già esisteva o è stata creata. 44 M. Bernaschi: Sistemi Operativi II LONG RegEnumValue( HKEY hKey, DWORD dwIndex, LPTSTR lpValueName, LPDWORD lpcValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData ); Enumera i valori della chiave hKey partendo dall’indice dwIndex 45 M. Bernaschi: Sistemi Operativi II LONG RegSetValueEx( HKEY hKey, LPCTSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, DWORD cbData); Associa alla chiave hKey un nome lpValueName che viene posto uguale a lpData ed ha tipo dwType. 46