This is an old revision of the document!
Nucleul gestionează fiecare device hardware sau virtual prin intermediul unui device driver. Un device driver este o porțiune de cod din nucleu care implementează o serie de operații corespunzătoare acțiunilor de I/E (intrare/ieşire) asociate cu un device hardware. Procesele din userspace (spațiul utilizator) interacționează cu device driver-ul prin intermediul unor fișiere speciale denumite device nodes. API-ul (interfața de programare) oferit de device drivere include, în general, următoarele operații:
open
,close
,read
,write
,ioctl
.Operaţiile de mai sus sunt aplicate asupra device node-ului sau descriptorului de fişier asociat acelui device node.
Unele device-uri sunt reale (mouse, tastatură, disc), altele sunt virtuale în sensul că nu au un device hardware asociat (e.g /dev/zero
, /dev/null
). După modul în care se accesează datele, device-urile sunt împărțite în două categorii:
device de tip caracter
, datele sunt procesate octet cu octet. În această categorie se înscriu: tastatura, linia serială, mouse-ul.device de tip bloc
, datele pot fi procesate la nivel de bloc, e.g. hard disk.
Fișierele device node se găsesc în /dev
și au asociat un identificator format din major ID și minor ID.
Majorul și minorul sunt dați de coloanele 5 și 6 din output-ul ls -l
, separate prin virgulă.
Puteți vizualiza majorii folosiți în sistem din fișierul /proc/devices
.
Crearea unui device node se face folosind funcția mknod
int mknod(const char *pathname, mode_t mode, dev_t dev);
În general, informații despre fișiere și în particular despre device node-uri se pot afla cu funcțiile din familia stat.
int stat(const char *path, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *path, struct stat *buf);
Toate aceste funcții completează informațiile despre un fișier în structura struct stat
, care conține următoarele câmpuri:
struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ dev_t st_rdev; /* device ID (if special file) */ off_t st_size; /* total size, in bytes */ blksize_t st_blksize; /* blocksize for file system I/O */ blkcnt_t st_blocks; /* number of 512B blocks allocated */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last status change */ };
Un sistem de fișiere este o colecție organizată de fișiere și directoare. Un sistem de fișiere este creat folosind comanda mkfs. Din punct de vedere funcțional sistemele de fișiere se pot împărți în:
Tipurile de sisteme de fișiere suportate de nucleu pot fi observate în fișierul /proc/filesystems
.
daniel@debian$ cat /proc/filesystems nodev sysfs nodev proc nodev ramfs ext4 fuseblk
Pentru a putea fi folosit un sistem de fișiere trebuie atașat (montat) în ierarhia de directoare din sistem. Acest lucru se realizează cu comanda mount(8):
mount -t type device dir
sau apelul mount(2):
int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
Operația inversă, demontarea sistemului de fișiere din ierarhia de directoare se face cu comanda umount(8):
umount {dir|device}...
sau apelul: umount(2)
int umount(const char *target);
Fiecare proces are două atribute legate de directoare:
Un director este stocat în sistemul de fișiere într-un mod similar cu un fișier obișnuit. Există două lucruri diferite:
Un link simbolic (sau soft link), este un tip special de fișier al cărui conținut reprezintă numele altui fișier. Link-urile simbolice sunt create cu comanda ln -s
sau cu apelul symlink(2)
int symlink(const char *oldpath, const char *newpath);
Ștergerea unui link simbolic se face cu comanda unlink
sau cu apelul unlink(2)
int unlink(const char *pathname);
Un director poate fi creat folosind comanda mkdir
sau apelul mkdir(2))
int mkdir(const char *pathname, mode_t mode);
Apelul rmdir(2) șterge directorul specificat în argumentul pathname
:
int rmdir(const char *pathname);
De asemenea, pentru a șterge un fișier sau un director gol se poate folosi funcția remove(3)
int remove(const char *pathname);
După cum am precizat mai sus, un director conține nume de directoare sau fișiere.
Apelul opendir(3) deschide un director și întoarce un handle ce poate fi folosit mai târziu pentru a referi directorul.
DIR *opendir(const char *name); DIR *fdopendir(int fd);
Apelul readdir(3) citește intrări succesive dintr-un stream de directoare (DIR).
struct dirent *readdir(DIR *dirp);
Apelul readdir
întoarce un pointer la următoarea structură struct dirent
din streamul referit de dir
:
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all file system types */ char d_name[256]; /* filename */ };
Directorul curent al unui proces definește punctul de start pentru formarea căilor relative referite de procesul respectiv. Un proces nou creat moștenește directorul curent de la procesul părinte.
Directorul curent al unui proces poate fi determinat folosind apelul getcwd(3):
char *getcwd(char *cwdbuf, size_t size);
cwdbuf
, trebuie alocat înainte de apel astfel încât să poată stoca cel puțin size
octeți.cwdbuf
va conține calea absolută a directorului curent.Apelul chdir(2) schimbă directorul curent al procesului apelant către numele absolut sau relativ primit ca argument.
int chdir(const char *path);
Fiecare proces are un director rădăcină reprezentând punctul de unde căile absolute sunt interpretate. În mod implicit, acesta este directorul rădăcina real al sistemului de fișiere. Un proces nou moștenește directorul rădăcină de la părintele său. Există situații (e.g pentru a ascunde o parte din sistemul de fișiere) în care este util pentru un proces să-și schimbe directorul rădăcină. Acest lucru se realizează folosind apelul chroot(2)
int chroot(const char *path);
Apelul realpath(3) dereferențiază link-ul simbolic primit ca argument și rezolvă toate referințele către /.
și /..
pentru a produce un șir de caractere conținând calea absolută.
char *realpath(const char *path, char *resolved_path);
Apelurile dirname(3) și basename(3) împart un șir de caractere reprezentând o cale în partea de director
și partea de fișier.
char *dirname(char *path); char *basename(char *path);
De exemplu:
path dirname basename "/usr/lib" "/usr" "lib" "/usr/" "/" "usr" "usr" "." "usr" "/" "/" "/" "." "." "." ".." "." ".."
Vă invităm să evaluați activitatea echipei de SO și să precizați punctele tari și punctele slabe și sugestiile voastre de îmbunătățire a materiei. Feedback-ul vostru este foarte important pentru noi să creștem calitatea materiei în anii următori și să îmbunătățim materiile pe care le veți face în continuare.
mini.c
din directorul 1-mini/
. Pentru fiecare exercițiu decomentați linia TODO corespunzătoare.
Folosiți comanda ls -l /dev
și precizați două device node-uri de tip caracter și două device node-uri de tip bloc. Ce major și minor au?
Implementați comanda list
<device_node>, ce va primi ca argument un device node și va afișa pentru acesta tipul (c/b), identificatorii major
, respectiv minor
. Folosiți funcția stat(2) pentru a obține o structură de tipul struct stat
din care veți extrage tipul device-ului (st_mode
) (hint: S_ISCHR, S_ISBLK) apoi din câmpul st_rdev
extrageți major și minor. Nu uitați să decomentați linia marcată cu #define TODO2
Creați punctul de montare /mnt/my
. Ca root, rulați comanda:
mkdir /mnt/my
Parcurgeți paginile de manual ale funcțiilor mount și umount.
Folosiți comenzile mount
și umount
din executabilul mini pentru a monta discul /dev/sda1
în punctul de montare /mnt/my
. Citiți secțiunea marcată cu TODO din fișierul mini.c
. Pentru argumentul 4 și argumentul 5 al funcției mount
folosiți, respectiv, valorile 0
și NULL
.
Testare: Rulați, ca root, comanda:
./mini
și apoi rulați comanda de montare în cadrul acestui shell:
mount /dev/sda1 /mnt/my ext3
Într-o altă consolă, într-un shell obișnuit, verificați rezultatele folosind comanda
cat /proc/mounts
Pentru demontare rulați comanda:
umount /mnt/my
Adăugați suport pentru comenzile symlink și unlink în programul mini
. Urmăriți TODO4 .
Pentru testare folosiți, în shell-ul aferent comenzii ./mini
, comanda:
symlink /etc/passwd local-passwd
Ca să verificați, într-o altă consolă, în același director cu cel în care ați rulat comanda ./mini
, folosiți
ls -l
Pentru a șterge symlink-ul folosiți comanda
unlink local-passwd
Pentru validare rulați din nou comanda
ls -l
Adăugați suport pentru comenzile mkdir și rmdir în programul mini
. Urmăriți TODO5 .
Ca al doilea argument pentru funcția mkdir
folosiți (mode_t) 0755
.
Adăugați suport pentru comanda ls dirname/
în programul mini
. Aceasta va trebui să afișeze recursiv toate directoarele și fișierele începând cu directorul dat ca parametru (puteți parcurge recursiv în adâncime arborele de fișiere). Urmăriți TODO6 și demo-ul 5 de la curs
Adăugați suport pentru comenzile pwd și chdir în programul mini
. Urmăriți TODO7 .